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 2a063b2e8 refactor: simplify miller columns (#8025)
2a063b2e8 is described below

commit 2a063b2e85e47fee59e5a20450858154ab5f5b62
Author: 青湛 <[email protected]>
AuthorDate: Wed Sep 11 13:57:06 2024 +1200

    refactor: simplify miller columns (#8025)
---
 config-ui/package.json                             |   9 +-
 config-ui/src/api/scope/index.ts                   |   2 +-
 .../components/data-scope-remote/search-local.tsx  | 273 ++++++--------
 .../components/data-scope-remote/search-remote.tsx | 244 +++++--------
 .../plugins/components/data-scope-select/index.tsx | 210 ++++++-----
 .../webhook/components/selector-dialog.tsx         |  34 +-
 config-ui/yarn.lock                                | 395 +++++++++++++++++----
 7 files changed, 661 insertions(+), 506 deletions(-)

diff --git a/config-ui/package.json b/config-ui/package.json
index 99d10bf19..62fe1e327 100644
--- a/config-ui/package.json
+++ b/config-ui/package.json
@@ -24,6 +24,11 @@
   "dependencies": {
     "@ahooksjs/use-url-state": "^3.5.1",
     "@ant-design/icons": "^5.3.0",
+    "@fontsource/roboto": "^5.0.14",
+    "@mints/miller-columns": "^2.0.0-beta.1",
+    "@mui/icons-material": "^5.16.7",
+    "@mui/material": "^5.16.7",
+    "@mui/styled-engine-sc": "^6.0.0-alpha.18",
     "@reduxjs/toolkit": "^2.2.1",
     "ahooks": "^3.7.10",
     "antd": "^5.14.2",
@@ -34,7 +39,6 @@
     "dayjs": "^1.11.10",
     "file-saver": "^2.0.5",
     "lodash": "^4.17.21",
-    "miller-columns-select": "1.4.1",
     "react": "^18.2.0",
     "react-copy-to-clipboard": "^5.1.0",
     "react-dom": "^18.2.0",
@@ -69,5 +73,8 @@
     "typescript": "^5.1.6",
     "vite": "^5.1.4",
     "vite-plugin-svgr": "^4.2.0"
+  },
+  "resolutions": {
+    "@mui/styled-engine": "npm:@mui/styled-engine-sc@^6.0.0-alpha.18"
   }
 }
diff --git a/config-ui/src/api/scope/index.ts b/config-ui/src/api/scope/index.ts
index 7007314f6..b9d19a672 100644
--- a/config-ui/src/api/scope/index.ts
+++ b/config-ui/src/api/scope/index.ts
@@ -91,7 +91,7 @@ export const searchRemote = (
   plugin: string,
   connectionId: ID,
   data: SearchRemoteQuery,
-): Promise<{ children: RemoteScope[]; count: number }> =>
+): Promise<{ children: RemoteScope[]; page: number; pageSize: number }> =>
   
request(`/plugins/${plugin}/connections/${connectionId}/search-remote-scopes`, {
     method: 'get',
     data,
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 70660c71f..716abf0e0 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
@@ -16,20 +16,50 @@
  *
  */
 
-import { useState, useEffect, useMemo } from 'react';
+import { useState, useReducer, useCallback } from 'react';
 import { CheckCircleFilled, SearchOutlined } from '@ant-design/icons';
-import { Space, Tag, Button, Input, Modal, message } from 'antd';
-import type { McsID, McsItem, McsColumn } from 'miller-columns-select';
-import { MillerColumnsSelect } from 'miller-columns-select';
+import { Space, Tag, Button, Input, Modal } from 'antd';
+import { MillerColumns } from '@mints/miller-columns';
 import { useDebounce } from 'ahooks';
 
 import API from '@/api';
-import { Loading, Block, Message } from '@/components';
-import { IPluginConfig } from '@/types';
+import { Block, Loading, Message } from '@/components';
+import type { IPluginConfig } from '@/types';
 
-import * as T from './types';
 import * as S from './styled';
 
+type StateType = {
+  status: string;
+  scope: any[];
+  originData: any[];
+};
+
+const reducer = (
+  state: StateType,
+  action: { type: string; payload?: Pick<Partial<StateType>, 'scope' | 
'originData'> },
+) => {
+  switch (action.type) {
+    case 'LOADING':
+      return {
+        ...state,
+        status: 'loading',
+      };
+    case 'APPEND':
+      return {
+        ...state,
+        scope: [...state.scope, ...(action.payload?.scope ?? [])],
+        originData: [...state.originData, ...(action.payload?.originData ?? 
[])],
+      };
+    case 'DONE':
+      return {
+        ...state,
+        status: 'done',
+      };
+    default:
+      return state;
+  }
+};
+
 interface Props {
   mode: 'single' | 'multiple';
   plugin: string;
@@ -40,149 +70,85 @@ interface Props {
   onChange: (selectedScope: any[]) => void;
 }
 
-let canceling = false;
-
 export const SearchLocal = ({ mode, plugin, connectionId, config, 
disabledScope, selectedScope, onChange }: Props) => {
-  const [miller, setMiller] = useState<{
-    items: McsItem<T.ResItem>[];
-    loadedIds: ID[];
-    expandedIds: ID[];
-    errorId?: ID | null;
-    nextTokenMap: Record<ID, string>;
-  }>({
-    items: [],
-    loadedIds: [],
-    expandedIds: [],
-    nextTokenMap: {},
-  });
-
   const [open, setOpen] = useState(false);
-  const [status, setStatus] = useState('init');
-
-  const [query, setQuery] = useState('');
-  const search = useDebounce(query, { wait: 500 });
-
-  const scopes = useMemo(
-    () =>
-      search
-        ? miller.items
-            .filter((it) => 
it.name.toLocaleLowerCase().includes(search.toLocaleLowerCase()))
-            .filter((it) => it.type !== 'group')
-            .map((it) => ({
-              ...it,
-              parentId: null,
-            }))
-        : miller.items,
-    [search, miller.items],
-  );
+  const [search, setSearch] = useState('');
 
-  const getItems = async ({
-    groupId,
-    currentPageToken,
-    loadAll,
-  }: {
-    groupId: ID | null;
-    currentPageToken?: string;
-    loadAll?: boolean;
-  }) => {
-    if (canceling) {
-      canceling = false;
-      setStatus('init');
-      return;
-    }
+  const [{ status, scope, originData }, dispatch] = useReducer(reducer, {
+    status: 'idle',
+    scope: [],
+    originData: [],
+  });
 
-    let newItems: McsItem<T.ResItem>[] = [];
-    let nextPageToken = '';
-    let errorId: ID | null;
+  const searchDebounce = useDebounce(search, { wait: 500 });
+
+  const request = useCallback(
+    async (groupId?: string | number, params?: any) => {
+      if (scope.length) {
+        return {
+          data: searchDebounce
+            ? scope
+                .filter((it) => it.title.includes(searchDebounce) && 
!it.canExpand)
+                .map((it) => ({ ...it, parentId: null }))
+            : scope.filter((it) => it.parentId === (groupId ?? null)),
+          hasMore: status === 'loading' ? true : false,
+          originData,
+        };
+      }
 
-    try {
       const res = await API.scope.remote(plugin, connectionId, {
-        groupId,
-        pageToken: currentPageToken,
+        groupId: groupId ?? null,
+        pageToken: params?.nextPageToken,
       });
 
-      newItems = (res.children ?? []).map((it) => ({
-        ...it,
-        title: it.name,
+      const data = res.children.map((it) => ({
+        parentId: it.parentId,
+        id: it.id,
+        title: it.name ?? it.fullName,
+        canExpand: it.type === 'group',
       }));
 
-      nextPageToken = res.nextPageToken;
-    } catch (err: any) {
-      errorId = groupId;
-      message.error(err.response.data.message);
-    }
-
-    if (nextPageToken) {
-      setMiller((m) => ({
-        ...m,
-        items: [...m.items, ...newItems],
-        expandedIds: [...m.expandedIds, groupId ?? 'root'],
-        nextTokenMap: {
-          ...m.nextTokenMap,
-          [`${groupId ? groupId : 'root'}`]: nextPageToken,
+      return {
+        data,
+        hasMore: !!res.nextPageToken,
+        params: {
+          nextPageToken: res.nextPageToken,
         },
-      }));
-
-      if (loadAll) {
-        await getItems({ groupId, currentPageToken: nextPageToken, loadAll });
-      }
-    } else {
-      setMiller((m) => ({
-        ...m,
-        items: [...m.items, ...newItems],
-        expandedIds: [...m.expandedIds, groupId ?? 'root'],
-        loadedIds: [...m.loadedIds, groupId ?? 'root'],
-        errorId,
-      }));
+        originData: res.children,
+      };
+    },
+    [plugin, connectionId, scope, status, searchDebounce],
+  );
 
-      const groupItems = newItems.filter((it) => it.type === 'group');
+  const handleRequestAll = async () => {
+    setOpen(false);
+    dispatch({ type: 'LOADING' });
 
-      if (loadAll && groupItems.length) {
-        groupItems.forEach(async (it) => await getItems({ groupId: it.id, 
loadAll: true }));
-      }
-    }
-  };
+    const getData = async (groupId?: string | number, currentPageToken?: 
string) => {
+      const res = await API.scope.remote(plugin, connectionId, {
+        groupId: groupId ?? null,
+        pageToken: currentPageToken,
+      });
 
-  useEffect(() => {
-    getItems({ groupId: null });
-  }, []);
+      const data = res.children.map((it) => ({
+        parentId: it.parentId,
+        id: it.id,
+        title: it.name ?? it.fullName,
+        canExpand: it.type === 'group',
+      }));
 
-  useEffect(() => {
-    if (
-      miller.items.length &&
-      !miller.items.filter((it) => it.type === 'group' && 
!miller.loadedIds.includes(it.id)).length
-    ) {
-      setStatus('loaded');
-    }
-  }, [miller]);
+      dispatch({ type: 'APPEND', payload: { scope: data, originData: 
res.children } });
 
-  const handleLoadAllScopes = async () => {
-    setOpen(false);
-    setStatus('loading');
+      if (res.nextPageToken) {
+        await getData(groupId, res.nextPageToken);
+      }
 
-    if (!miller.loadedIds.includes('root')) {
-      await getItems({
-        groupId: null,
-        currentPageToken: miller.nextTokenMap['root'],
-        loadAll: true,
-      });
-    }
+      await Promise.all(data.filter((it) => it.canExpand).map((it) => 
getData(it.id)));
+    };
 
-    const noLoadedItems = miller.items.filter((it) => it.type === 'group' && 
!miller.loadedIds.includes(it.id));
-    if (noLoadedItems.length) {
-      noLoadedItems.forEach(async (it) => {
-        await getItems({
-          groupId: it.id,
-          currentPageToken: miller.nextTokenMap[it.id],
-          loadAll: true,
-        });
-      });
-    }
-  };
+    await getData();
 
-  const handleCancelLoadAllScopes = () => {
-    setStatus('cancel');
-    canceling = true;
+    dispatch({ type: 'DONE' });
   };
 
   return (
@@ -209,59 +175,54 @@ export const SearchLocal = ({ mode, plugin, connectionId, 
config, disabledScope,
         {(status === 'loading' || status === 'cancel') && (
           <S.JobLoad>
             <Loading style={{ marginRight: 8 }} size={20} />
-            Loading: <span className="count">{miller.items.length}</span> 
scopes found
-            <Button style={{ marginLeft: 8 }} loading={status === 'cancel'} 
onClick={handleCancelLoadAllScopes}>
-              Cancel
-            </Button>
+            Loading: <span className="count">{scope.length}</span> scopes found
           </S.JobLoad>
         )}
 
-        {status === 'loaded' && (
+        {status === 'done' && (
           <S.JobLoad>
             <CheckCircleFilled style={{ color: '#4DB764' }} />
-            <span className="count">{miller.items.length}</span> scopes found
+            <span className="count">{scope.length}</span> scopes found
           </S.JobLoad>
         )}
 
-        {status === 'init' && (
+        {status === 'idle' && (
           <S.JobLoad>
-            <Button type="primary" disabled={!miller.items.length} onClick={() 
=> setOpen(true)}>
+            <Button type="primary" onClick={() => setOpen(true)}>
               Load all scopes to search by keywords
             </Button>
           </S.JobLoad>
         )}
       </Block>
       <Block>
-        {status === 'loaded' && (
-          <Input prefix={<SearchOutlined />} value={query} onChange={(e) => 
setQuery(e.target.value)} />
+        {status === 'done' && (
+          <Input prefix={<SearchOutlined />} value={search} onChange={(e) => 
setSearch(e.target.value)} />
         )}
-        <MillerColumnsSelect
-          mode={mode}
-          items={scopes}
+        <MillerColumns
+          bordered
+          theme={{
+            colorPrimary: '#7497f7',
+            borderColor: '#dbe4fd',
+          }}
+          request={request}
           columnCount={search ? 1 : config.millerColumn?.columnCount ?? 1}
           columnHeight={300}
-          getCanExpand={(it) => it.type === 'group'}
-          getHasMore={(id) => !miller.loadedIds.includes(id ?? 'root')}
-          getHasError={(id) => id === miller.errorId}
-          onExpand={(id: McsID) => getItems({ groupId: id })}
-          onScroll={(id: McsID | null) =>
-            getItems({ groupId: id, currentPageToken: miller.nextTokenMap[id 
?? 'root'] })
-          }
-          renderTitle={(column: McsColumn) =>
-            !column.parentId &&
+          mode={mode}
+          renderTitle={(id) =>
+            !id &&
             config.millerColumn?.firstColumnTitle && (
               
<S.ColumnTitle>{config.millerColumn.firstColumnTitle}</S.ColumnTitle>
             )
           }
           renderLoading={() => <Loading size={20} style={{ padding: '4px 12px' 
}} />}
           renderError={() => <span style={{ color: 'red' }}>Something 
Error</span>}
+          selectable
           disabledIds={(disabledScope ?? []).map((it) => it.id)}
           selectedIds={selectedScope.map((it) => it.id)}
-          onSelectItemIds={(selectedIds: ID[]) => 
onChange(miller.items.filter((it) => selectedIds.includes(it.id)))}
-          expandedIds={miller.expandedIds}
+          onSelectedIds={(ids, data) => onChange((data ?? []).filter((it) => 
ids.includes(it.id)))}
         />
       </Block>
-      <Modal open={open} centered onOk={handleLoadAllScopes} onCancel={() => 
setOpen(false)}>
+      <Modal open={open} centered onOk={handleRequestAll} onCancel={() => 
setOpen(false)}>
         <Message content={`This operation may take a long time, as it iterates 
through all the ${config.title}.`} />
       </Modal>
     </>
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 4679b8564..0f6710fe8 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
@@ -16,19 +16,16 @@
  *
  */
 
-import { useState, useEffect, useMemo } from 'react';
+import { useState, useCallback } from 'react';
 import { SearchOutlined } from '@ant-design/icons';
-import { Space, Tag, Input, message } from 'antd';
-import type { McsID, McsItem, McsColumn } from 'miller-columns-select';
-import MillerColumnsSelect from 'miller-columns-select';
+import { Space, Tag, Input } from 'antd';
 import { useDebounce } from 'ahooks';
-import { uniqBy } from 'lodash';
+import { MillerColumns } from '@mints/miller-columns';
 
 import API from '@/api';
-import { Loading, Block } from '@/components';
-import { IPluginConfig } from '@/types';
+import { Block, Loading } from '@/components';
+import type { IPluginConfig } from '@/types';
 
-import * as T from './types';
 import * as S from './styled';
 
 interface Props {
@@ -42,116 +39,67 @@ interface Props {
 }
 
 export const SearchRemote = ({ mode, plugin, connectionId, config, 
disabledScope, selectedScope, onChange }: Props) => {
-  const [miller, setMiller] = useState<{
-    items: McsItem<T.ResItem>[];
-    loadedIds: ID[];
-    errorId?: ID | null;
-    nextTokenMap: Record<ID, string>;
-  }>({
-    items: [],
-    loadedIds: [],
-    nextTokenMap: {},
-  });
-
-  const [search, setSearch] = useState<{
-    loading: boolean;
-    items: McsItem<T.ResItem>[];
-    currentItems: McsItem<T.ResItem>[];
-    query: string;
-    page: number;
-    total: number;
-  }>({
-    loading: true,
-    items: [],
-    currentItems: [],
-    query: '',
-    page: 1,
-    total: 0,
-  });
-
-  const searchDebounce = useDebounce(search.query, { wait: 500 });
-
-  const allItems = useMemo(
-    () =>
-      uniqBy(
-        [...miller.items, ...search.items].filter((it) => it.type === 'scope'),
-        'id',
-      ),
-    [miller.items, search.items],
+  const [search, setSearch] = useState('');
+
+  const searchDebounce = useDebounce(search, { wait: 500 });
+
+  const request = useCallback(
+    async (groupId?: string | number, params?: any) => {
+      let data = [];
+      let hasMore = false;
+      let newParams = {};
+      let originData = [];
+
+      if (!searchDebounce) {
+        const res = await API.scope.remote(plugin, connectionId, {
+          groupId: groupId ?? null,
+          pageToken: params?.pageToken,
+        });
+
+        data = res.children.map((it) => ({
+          parentId: it.parentId,
+          id: it.id,
+          title: it.name ?? it.fullName,
+          canExpand: it.type === 'group',
+        }));
+
+        hasMore = !!res.nextPageToken;
+        newParams = {
+          pageToken: res.nextPageToken,
+        };
+        originData = res.children;
+      } else {
+        const res = await API.scope.searchRemote(plugin, connectionId, {
+          search: searchDebounce,
+          page: params?.page ?? 1,
+          pageSize: 20,
+        });
+
+        data = res.children.map((it) => ({
+          parentId: it.parentId,
+          id: it.id,
+          title: it.fullName ?? it.name,
+          canExpand: it.type === 'group',
+        }));
+
+        hasMore = res.children.length === res.pageSize;
+        newParams = {
+          page: (params?.page ?? 0) + 1,
+          count: (params?.count ?? 0) + res.children.length,
+        };
+        originData = res.children;
+      }
+
+      return {
+        data,
+        hasMore,
+        params: newParams,
+        originData,
+      };
+    },
+    [plugin, connectionId, searchDebounce],
   );
 
-  const getItems = async (groupId: ID | null, currentPageToken?: string) => {
-    let newItems: McsItem<T.ResItem>[] = [];
-    let nextPageToken = '';
-    let errorId: ID | null;
-
-    try {
-      const res = await API.scope.remote(plugin, connectionId, {
-        groupId,
-        pageToken: currentPageToken,
-      });
-
-      newItems = (res.children ?? []).map((it) => ({
-        ...it,
-        title: it.name,
-      }));
-
-      nextPageToken = res.nextPageToken;
-    } catch (err: any) {
-      errorId = groupId;
-      message.error(err.response.data.message);
-    }
-
-    if (nextPageToken && newItems.length) {
-      setMiller((m) => ({
-        ...m,
-        items: [...m.items, ...newItems],
-        nextTokenMap: {
-          ...m.nextTokenMap,
-          [`${groupId ? groupId : 'root'}`]: nextPageToken,
-        },
-      }));
-    } else {
-      setMiller((m) => ({
-        ...m,
-        items: [...m.items, ...newItems],
-        loadedIds: [...m.loadedIds, groupId ?? 'root'],
-        errorId,
-      }));
-    }
-  };
-
-  useEffect(() => {
-    getItems(null);
-  }, []);
-
-  const searchItems = async () => {
-    if (!searchDebounce) return;
-
-    const res = await API.scope.searchRemote(plugin, connectionId, {
-      search: searchDebounce,
-      page: search.page,
-      pageSize: 20,
-    });
-
-    const newItems = (res.children ?? []).map((it) => ({
-      ...it,
-      title: it.fullName ?? it.name,
-    }));
-
-    setSearch((s) => ({
-      ...s,
-      loading: false,
-      items: [...allItems, ...newItems],
-      currentItems: newItems,
-      total: res.count,
-    }));
-  };
-
-  useEffect(() => {
-    searchItems();
-  }, [searchDebounce, search.page]);
-
   return (
     <>
       <Block title={config.title} required>
@@ -176,47 +124,31 @@ export const SearchRemote = ({ mode, plugin, 
connectionId, config, disabledScope
         <Input
           prefix={<SearchOutlined />}
           placeholder={config.searchPlaceholder ?? 'Search'}
-          value={search.query}
-          onChange={(e) => setSearch({ ...search, query: e.target.value, 
loading: true, currentItems: [] })}
+          value={search}
+          onChange={(e) => setSearch(e.target.value)}
+        />
+        <MillerColumns
+          bordered
+          theme={{
+            colorPrimary: '#7497f7',
+            borderColor: '#dbe4fd',
+          }}
+          request={request}
+          columnCount={searchDebounce ? 1 : config.millerColumn?.columnCount 
?? 1}
+          columnHeight={300}
+          mode={mode}
+          renderTitle={(id?) =>
+            !id &&
+            config.millerColumn?.firstColumnTitle && (
+              
<S.ColumnTitle>{config.millerColumn.firstColumnTitle}</S.ColumnTitle>
+            )
+          }
+          renderLoading={() => <Loading size={20} style={{ padding: '4px 12px' 
}} />}
+          selectable
+          disabledIds={disabledScope.map((it) => it.id)}
+          selectedIds={selectedScope.map((it) => it.id)}
+          onSelectedIds={(ids, data) => onChange((data ?? []).filter((it) => 
ids.includes(it.id)))}
         />
-        {!searchDebounce ? (
-          <MillerColumnsSelect
-            mode={mode}
-            items={miller.items}
-            columnCount={config.millerColumn?.columnCount ?? 1}
-            columnHeight={300}
-            getCanExpand={(it) => it.type === 'group'}
-            getHasMore={(id) => !miller.loadedIds.includes(id ?? 'root')}
-            getHasError={(id) => id === miller.errorId}
-            onExpand={(id: McsID) => getItems(id, miller.nextTokenMap[id])}
-            onScroll={(id: McsID | null) => getItems(id, 
miller.nextTokenMap[id ?? 'root'])}
-            renderTitle={(column: McsColumn) =>
-              !column.parentId &&
-              config.millerColumn?.firstColumnTitle && (
-                
<S.ColumnTitle>{config.millerColumn.firstColumnTitle}</S.ColumnTitle>
-              )
-            }
-            renderLoading={() => <Loading size={20} style={{ padding: '4px 
12px' }} />}
-            renderError={() => <span style={{ color: 'red' }}>Something 
Error</span>}
-            disabledIds={(disabledScope ?? []).map((it) => it.id)}
-            selectedIds={selectedScope.map((it) => it.id)}
-            onSelectItemIds={(selectedIds: ID[]) => 
onChange(allItems.filter((it) => selectedIds.includes(it.id)))}
-          />
-        ) : (
-          <MillerColumnsSelect
-            mode={mode}
-            items={search.currentItems}
-            columnCount={1}
-            columnHeight={300}
-            getCanExpand={() => false}
-            getHasMore={() => search.loading}
-            onScroll={() => setSearch({ ...search, page: search.page + 1 })}
-            renderLoading={() => <Loading size={20} style={{ padding: '4px 
12px' }} />}
-            disabledIds={(disabledScope ?? []).map((it) => it.id)}
-            selectedIds={selectedScope.map((it) => it.id)}
-            onSelectItemIds={(selectedIds: ID[]) => 
onChange(allItems.filter((it) => selectedIds.includes(it.id)))}
-          />
-        )}
       </Block>
     </>
   );
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 213b7ed25..02f252ef4 100644
--- a/config-ui/src/plugins/components/data-scope-select/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-select/index.tsx
@@ -16,16 +16,14 @@
  *
  */
 
-import { useState, useEffect, useMemo } from 'react';
+import { useState, useEffect, useCallback } from 'react';
 import { RedoOutlined, PlusOutlined } from '@ant-design/icons';
-import { Flex, Select, Button } from 'antd';
+import { Flex, Button, Input, Space, Tag } from 'antd';
 import { useDebounce } from 'ahooks';
-import type { McsItem } from 'miller-columns-select';
-import MillerColumnsSelect from 'miller-columns-select';
+import { MillerColumns } from '@mints/miller-columns';
 
 import API from '@/api';
 import { Loading, Block, ExternalLink, Message } from '@/components';
-import { useRefreshData } from '@/hooks';
 import { getPluginScopeId } from '@/plugins';
 
 interface Props {
@@ -45,74 +43,51 @@ export const DataScopeSelect = ({
   onSubmit,
   onCancel,
 }: Props) => {
-  const [loading, setLoading] = useState(false);
-  const [query, setQuery] = useState('');
-  const [items, setItems] = useState<McsItem<{ data: any }>[]>([]);
   const [selectedIds, setSelectedIds] = useState<ID[]>([]);
-  // const [selectedItems, setSelecteItems] = useState<any>([]);
-  const [page, setPage] = useState(1);
-  const [pageSize] = useState(10);
-  const [total, setTotal] = useState(0);
+  const [originData, setOriginData] = useState<any[]>([]);
+  const [search, setSearch] = useState('');
+  const [version, setVersion] = useState(0);
+
+  const searchDebounce = useDebounce(search, { wait: 500 });
 
   useEffect(() => {
     setSelectedIds((initialScope ?? []).map((sc) => sc.id));
   }, []);
 
-  const getDataScope = async (page: number) => {
-    if (page === 1) {
-      setLoading(true);
-    }
+  const request = useCallback(
+    async (_?: string | number, params?: any) => {
+      const res = await API.scope.list(plugin, connectionId, {
+        page: params?.page ?? 1,
+        pageSize: 20,
+        searchTerm: searchDebounce,
+      });
 
-    const res = await API.scope.list(plugin, connectionId, { page, pageSize });
-    setItems((items) => [
-      ...items,
-      ...res.scopes.map((sc) => ({
+      const data = res.scopes.map((it) => ({
         parentId: null,
-        id: getPluginScopeId(plugin, sc.scope),
-        title: sc.scope.fullName ?? sc.scope.name,
-        data: sc.scope,
-      })),
-    ]);
-
-    setTotal(res.count);
-    setLoading(false);
-  };
-
-  useEffect(() => {
-    getDataScope(page);
-  }, [page]);
-
-  const search = useDebounce(query, { wait: 500 });
-
-  const { ready, data } = useRefreshData(
-    async () => await API.scope.list(plugin, connectionId, { searchTerm: 
search }),
-    [search],
-  );
-
-  const searchOptions = useMemo(
-    () =>
-      data?.scopes.map((sc) => ({
-        label: sc.scope.fullName ?? sc.scope.name,
-        value: getPluginScopeId(plugin, sc.scope),
-      })) ?? [],
-    [data],
+        id: getPluginScopeId(plugin, it.scope),
+        title: it.scope.fullName ?? it.scope.name,
+        canExpand: false,
+      }));
+
+      return {
+        data,
+        hasMore: res.count > (params?.page ?? 1) * 20,
+        params: {
+          page: (params?.page ?? 1) + 1,
+        },
+        originData: res.scopes,
+      };
+    },
+    [plugin, connectionId, searchDebounce, version],
   );
 
-  const handleScroll = () => setPage(page + 1);
-
   const handleSubmit = () => onSubmit?.(selectedIds);
 
-  const handleRefresh = () => {
-    setQuery('');
-    setItems([]);
-    getDataScope(1);
-  };
-
   return (
     <Block
       title="Select Data Scope"
       description={
-        items.length ? (
+        originData.length ? (
           <>
             Select the data scope in this Connection that you wish to 
associate with this Project. If you wish to add
             more Data Scope to this Connection, please{' '}
@@ -130,65 +105,80 @@ export const DataScopeSelect = ({
       }
       required
     >
-      {loading ? (
-        <Loading />
-      ) : items.length ? (
-        <Flex vertical gap="middle">
-          {showWarning ? (
-            <Message
-              style={{ marginBottom: 24 }}
-              content={
-                <>
-                  Unchecking Data Scope below will only remove it from the 
current Project and will not delete the
-                  historical data. If you would like to delete the data of 
Data Scope, please{' '}
-                  <ExternalLink 
link={`/connections/${plugin}/${connectionId}`}>go to the Connection 
page</ExternalLink>
-                  .
-                </>
-              }
-            />
+      <Flex vertical gap="middle">
+        {showWarning ? (
+          <Message
+            style={{ marginBottom: 24 }}
+            content={
+              <>
+                Unchecking Data Scope below will only remove it from the 
current Project and will not delete the
+                historical data. If you would like to delete the data of Data 
Scope, please{' '}
+                <ExternalLink 
link={`/connections/${plugin}/${connectionId}`}>go to the Connection 
page</ExternalLink>.
+              </>
+            }
+          />
+        ) : (
+          <Flex>
+            <Button type="primary" icon={<RedoOutlined />} onClick={() => 
setVersion(version + 1)}>
+              Refresh Data Scope
+            </Button>
+          </Flex>
+        )}
+        <Space wrap>
+          {selectedIds.length ? (
+            selectedIds.map((id) => {
+              const item = originData.find((it) => getPluginScopeId(plugin, 
it.scope) === `${id}`);
+              return (
+                <Tag
+                  key={id}
+                  color="blue"
+                  closable
+                  onClose={() => setSelectedIds(selectedIds.filter((it) => it 
!== id))}
+                >
+                  {item?.scope.fullName ?? item?.scope.name}
+                </Tag>
+              );
+            })
           ) : (
-            <Flex>
-              <Button type="primary" icon={<RedoOutlined />} 
onClick={handleRefresh}>
-                Refresh Data Scope
-              </Button>
-            </Flex>
+            <span>Please select scope...</span>
           )}
-          <Select
-            filterOption={false}
-            loading={!ready}
-            showSearch
-            mode="multiple"
-            options={searchOptions}
-            value={selectedIds}
-            onChange={(value) => setSelectedIds(value)}
-            onSearch={(value) => setQuery(value)}
-          />
-          <MillerColumnsSelect
-            showSelectAll
-            columnCount={1}
+        </Space>
+        <div>
+          <Input.Search value={search} onChange={(e) => 
setSearch(e.target.value)} />
+          <MillerColumns
+            bordered
+            theme={{
+              colorPrimary: '#7497f7',
+              borderColor: '#dbe4fd',
+            }}
+            request={request}
             columnHeight={200}
-            items={items}
-            getHasMore={() => items.length < total}
-            onScroll={handleScroll}
+            renderLoading={() => <Loading size={20} style={{ padding: '4px 
12px' }} />}
+            renderError={() => <span style={{ color: 'red' }}>Something 
Error</span>}
+            renderNoData={() => (
+              <Flex style={{ height: '100%' }} justify="center" align="center">
+                <ExternalLink link={`/connections/${plugin}/${connectionId}`}>
+                  <Button type="primary" icon={<PlusOutlined />}>
+                    Add Data Scope
+                  </Button>
+                </ExternalLink>
+              </Flex>
+            )}
+            selectable
             selectedIds={selectedIds}
-            onSelectItemIds={setSelectedIds}
+            onSelectedIds={(ids, data) => {
+              setSelectedIds(ids);
+              setOriginData(data ?? []);
+            }}
           />
-          <Flex justify="flex-end" gap="small">
-            <Button onClick={onCancel}>Cancel</Button>
-            <Button type="primary" disabled={!selectedIds.length} 
onClick={handleSubmit}>
-              Save
-            </Button>
-          </Flex>
-        </Flex>
-      ) : (
-        <Flex>
-          <ExternalLink link={`/connections/${plugin}/${connectionId}`}>
-            <Button type="primary" icon={<PlusOutlined />}>
-              Add Data Scope
-            </Button>
-          </ExternalLink>
+        </div>
+        <Flex justify="flex-end" gap="small">
+          <Button onClick={onCancel}>Cancel</Button>
+          <Button type="primary" disabled={!selectedIds.length} 
onClick={handleSubmit}>
+            Save
+          </Button>
         </Flex>
-      )}
+      </Flex>
     </Block>
   );
 };
diff --git 
a/config-ui/src/plugins/register/webhook/components/selector-dialog.tsx 
b/config-ui/src/plugins/register/webhook/components/selector-dialog.tsx
index 4c0c49511..a0c972dee 100644
--- a/config-ui/src/plugins/register/webhook/components/selector-dialog.tsx
+++ b/config-ui/src/plugins/register/webhook/components/selector-dialog.tsx
@@ -16,9 +16,9 @@
  *
  */
 
-import { useState } from 'react';
+import { useCallback, useState } from 'react';
 import { Modal } from 'antd';
-import MillerColumnsSelect from 'miller-columns-select';
+import { MillerColumns } from '@mints/miller-columns';
 
 import { useAppSelector } from '@/hooks';
 import { Block, Loading } from '@/components';
@@ -39,6 +39,17 @@ export const SelectorDialog = ({ open, saving, onCancel, 
onSubmit }: Props) => {
 
   const webhooks = useAppSelector(selectWebhooks);
 
+  const request = useCallback(async () => {
+    return {
+      data: webhooks.map((it) => ({
+        parentId: null,
+        id: it.id,
+        title: it.name,
+      })),
+      hasMore: false,
+    };
+  }, [webhooks]);
+
   const handleSubmit = () => onSubmit(webhooks.filter((it) => 
selectedIds.includes(it.id)));
 
   return (
@@ -57,19 +68,18 @@ export const SelectorDialog = ({ open, saving, onCancel, 
onSubmit }: Props) => {
     >
       <S.Wrapper>
         <Block title="Webhooks" description="Select an existing Webhook to 
import to the current project.">
-          <MillerColumnsSelect
-            columnCount={1}
+          <MillerColumns
+            bordered
+            theme={{
+              colorPrimary: '#7497f7',
+              borderColor: '#dbe4fd',
+            }}
+            request={request}
             columnHeight={160}
-            getHasMore={() => false}
             renderLoading={() => <Loading size={20} style={{ padding: '4px 
12px' }} />}
-            items={webhooks.map((it) => ({
-              parentId: null,
-              id: it.id,
-              title: it.name,
-              name: it.name,
-            }))}
+            selectable
             selectedIds={selectedIds}
-            onSelectItemIds={setSelectedIds}
+            onSelectedIds={setSelectedIds}
           />
         </Block>
       </S.Wrapper>
diff --git a/config-ui/yarn.lock b/config-ui/yarn.lock
index 2ea91ec1b..a4dc8623d 100644
--- a/config-ui/yarn.lock
+++ b/config-ui/yarn.lock
@@ -280,7 +280,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/helper-module-imports@npm:^7.0.0, 
@babel/helper-module-imports@npm:^7.22.15, 
@babel/helper-module-imports@npm:^7.22.5":
+"@babel/helper-module-imports@npm:^7.22.15":
   version: 7.22.15
   resolution: "@babel/helper-module-imports@npm:7.22.15"
   dependencies:
@@ -690,7 +690,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/plugin-syntax-jsx@npm:^7.22.5, @babel/plugin-syntax-jsx@npm:^7.23.3":
+"@babel/plugin-syntax-jsx@npm:^7.23.3":
   version: 7.23.3
   resolution: "@babel/plugin-syntax-jsx@npm:7.23.3"
   dependencies:
@@ -1655,6 +1655,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.25.0, 
@babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7":
+  version: 7.25.6
+  resolution: "@babel/runtime@npm:7.25.6"
+  dependencies:
+    regenerator-runtime: ^0.14.0
+  checksum: 
ee1a69d3ac7802803f5ee6a96e652b78b8addc28c6a38c725a4ad7d61a059d9e6cb9f6550ed2f63cce67a1bd82e0b1ef66a1079d895be6bfb536a5cfbd9ccc32
+  languageName: node
+  linkType: hard
+
 "@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0":
   version: 7.24.0
   resolution: "@babel/template@npm:7.24.0"
@@ -1666,7 +1675,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/traverse@npm:^7.24.0, @babel/traverse@npm:^7.4.5":
+"@babel/traverse@npm:^7.24.0":
   version: 7.24.0
   resolution: "@babel/traverse@npm:7.24.0"
   dependencies:
@@ -1718,7 +1727,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@emotion/is-prop-valid@npm:^1.1.0":
+"@emotion/is-prop-valid@npm:1.2.2":
   version: 1.2.2
   resolution: "@emotion/is-prop-valid@npm:1.2.2"
   dependencies:
@@ -1734,13 +1743,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@emotion/stylis@npm:^0.8.4":
-  version: 0.8.5
-  resolution: "@emotion/stylis@npm:0.8.5"
-  checksum: 
67ff5958449b2374b329fb96e83cb9025775ffe1e79153b499537c6c8b2eb64b77f32d7b5d004d646973662356ceb646afd9269001b97c54439fceea3203ce65
-  languageName: node
-  linkType: hard
-
 "@emotion/unitless@npm:0.8.0":
   version: 0.8.0
   resolution: "@emotion/unitless@npm:0.8.0"
@@ -1748,7 +1750,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@emotion/unitless@npm:^0.7.4, @emotion/unitless@npm:^0.7.5":
+"@emotion/unitless@npm:0.8.1":
+  version: 0.8.1
+  resolution: "@emotion/unitless@npm:0.8.1"
+  checksum: 
385e21d184d27853bb350999471f00e1429fa4e83182f46cd2c164985999d9b46d558dc8b9cc89975cb337831ce50c31ac2f33b15502e85c299892e67e7b4a88
+  languageName: node
+  linkType: hard
+
+"@emotion/unitless@npm:^0.7.5":
   version: 0.7.5
   resolution: "@emotion/unitless@npm:0.7.5"
   checksum: 
f976e5345b53fae9414a7b2e7a949aa6b52f8bdbcc84458b1ddc0729e77ba1d1dfdff9960e0da60183877873d3a631fa24d9695dd714ed94bcd3ba5196586a6b
@@ -1958,6 +1967,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@fontsource/roboto@npm:^5.0.14":
+  version: 5.0.14
+  resolution: "@fontsource/roboto@npm:5.0.14"
+  checksum: 
c7a47aedd55233c84270e8ccb36fc529d37815b49acaab276de572dc67c694f9e76e9dd566cbb32b948d542bed5dc151b58c62641325c043e1eb8140e327da55
+  languageName: node
+  linkType: hard
+
 "@humanwhocodes/config-array@npm:^0.11.14":
   version: 0.11.14
   resolution: "@humanwhocodes/config-array@npm:0.11.14"
@@ -2039,6 +2055,178 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@mints/miller-columns@npm:^2.0.0-beta.1":
+  version: 2.0.0-beta.1
+  resolution: "@mints/miller-columns@npm:2.0.0-beta.1"
+  dependencies:
+    "@fontsource/roboto": ^5.0.14
+    "@mui/material": ^5.16.7
+    "@mui/styled-engine-sc": ^6.0.0-alpha.18
+    lodash: ^4.17.21
+    react: ^18.2.0
+    react-dom: ^18.2.0
+    react-infinite-scroll-component: ^6.1.0
+    styled-components: ^6.1.12
+  peerDependencies:
+    "@fontsource/roboto": ^5.0.14
+    "@mui/material": ^5.16.7
+    "@mui/styled-engine-sc": ^6.0.0-alpha.18
+    lodash: ^4.17.21
+    react: ^18.2.0
+    react-dom: ^18.2.0
+    react-infinite-scroll-component: ^6.1.0
+    styled-components: ^6.1.12
+  checksum: 
ca49de90e123850029cf1db5ac41567bdd04c0d8b60db3783260265e5b283fddd576c38b573de804a7f35c44e228045b8fa5000d9b8e8a75c53c3ce05ca5deec
+  languageName: node
+  linkType: hard
+
+"@mui/core-downloads-tracker@npm:^5.16.7":
+  version: 5.16.7
+  resolution: "@mui/core-downloads-tracker@npm:5.16.7"
+  checksum: 
b65c48ba2bf6bba6435ba9f2d6c33db0c8a85b3ff7599136a9682b72205bec76470ab5ed5e6e625d5bd012ed9bcbc641ed677548be80d217c9fb5d0435567062
+  languageName: node
+  linkType: hard
+
+"@mui/icons-material@npm:^5.16.7":
+  version: 5.16.7
+  resolution: "@mui/icons-material@npm:5.16.7"
+  dependencies:
+    "@babel/runtime": ^7.23.9
+  peerDependencies:
+    "@mui/material": ^5.0.0
+    "@types/react": ^17.0.0 || ^18.0.0
+    react: ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 
a875f2837897d79a83173d80461e06ab090b64d08913d26433cf2cbeb8e7c7456468632a7aa495d722718f09111a8043255777d73b4dfbe9e0f863a170fc7190
+  languageName: node
+  linkType: hard
+
+"@mui/material@npm:^5.16.7":
+  version: 5.16.7
+  resolution: "@mui/material@npm:5.16.7"
+  dependencies:
+    "@babel/runtime": ^7.23.9
+    "@mui/core-downloads-tracker": ^5.16.7
+    "@mui/system": ^5.16.7
+    "@mui/types": ^7.2.15
+    "@mui/utils": ^5.16.6
+    "@popperjs/core": ^2.11.8
+    "@types/react-transition-group": ^4.4.10
+    clsx: ^2.1.0
+    csstype: ^3.1.3
+    prop-types: ^15.8.1
+    react-is: ^18.3.1
+    react-transition-group: ^4.4.5
+  peerDependencies:
+    "@emotion/react": ^11.5.0
+    "@emotion/styled": ^11.3.0
+    "@types/react": ^17.0.0 || ^18.0.0
+    react: ^17.0.0 || ^18.0.0
+    react-dom: ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@emotion/react":
+      optional: true
+    "@emotion/styled":
+      optional: true
+    "@types/react":
+      optional: true
+  checksum: 
5057b48c3ce554247de9a8f675bda9bbda079bc83a696c500525f3ebbd63315a44f1c2a7c83c2025dbd02d2722892e397a0af10c1219d45f6534e41d91a43cc0
+  languageName: node
+  linkType: hard
+
+"@mui/private-theming@npm:^5.16.6":
+  version: 5.16.6
+  resolution: "@mui/private-theming@npm:5.16.6"
+  dependencies:
+    "@babel/runtime": ^7.23.9
+    "@mui/utils": ^5.16.6
+    prop-types: ^15.8.1
+  peerDependencies:
+    "@types/react": ^17.0.0 || ^18.0.0
+    react: ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 
314ba598ab17cd425a36e4cab677ed26fe0939b23e53120da77cfbc3be6dada5428fa8e2a55cb697417599a4e3abfee6d4711de0a7318b9fb2c3a822b2d5b5a8
+  languageName: node
+  linkType: hard
+
+"@mui/styled-engine-sc@npm:^6.0.0-alpha.18, 
@mui/styled-engine@npm:@mui/styled-engine-sc@^6.0.0-alpha.18":
+  version: 6.0.2
+  resolution: "@mui/styled-engine-sc@npm:6.0.2"
+  dependencies:
+    "@babel/runtime": ^7.25.0
+    csstype: ^3.1.3
+    hoist-non-react-statics: ^3.3.2
+    prop-types: ^15.8.1
+  peerDependencies:
+    styled-components: ^6.0.0
+  checksum: 
027972651eb83d6ec68ba4f56fa1dbd84334036707af98ca403c5009a95db0ad6bb2583097b8e533a94663f7d2f35a707a527c802f1759cf9e17e24b913de092
+  languageName: node
+  linkType: hard
+
+"@mui/system@npm:^5.16.7":
+  version: 5.16.7
+  resolution: "@mui/system@npm:5.16.7"
+  dependencies:
+    "@babel/runtime": ^7.23.9
+    "@mui/private-theming": ^5.16.6
+    "@mui/styled-engine": ^5.16.6
+    "@mui/types": ^7.2.15
+    "@mui/utils": ^5.16.6
+    clsx: ^2.1.0
+    csstype: ^3.1.3
+    prop-types: ^15.8.1
+  peerDependencies:
+    "@emotion/react": ^11.5.0
+    "@emotion/styled": ^11.3.0
+    "@types/react": ^17.0.0 || ^18.0.0
+    react: ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@emotion/react":
+      optional: true
+    "@emotion/styled":
+      optional: true
+    "@types/react":
+      optional: true
+  checksum: 
86cc11d062645b6742328178ca3a9e2aa2c6d064a559e4fb8c6c6bb8251794959b9dad385f9508fdcab2ae2764503c80f7c3d4f6eb1e0e8aa649f28d4f59133b
+  languageName: node
+  linkType: hard
+
+"@mui/types@npm:^7.2.15":
+  version: 7.2.16
+  resolution: "@mui/types@npm:7.2.16"
+  peerDependencies:
+    "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 
7bb86487be8e55a4e138a6a5878ab272caee71546a7a2368223274afae65229f673334e59b8e3f7717ea7ea8d44af5f068b2eb4c212cddb98fefecfa873b868a
+  languageName: node
+  linkType: hard
+
+"@mui/utils@npm:^5.16.6":
+  version: 5.16.6
+  resolution: "@mui/utils@npm:5.16.6"
+  dependencies:
+    "@babel/runtime": ^7.23.9
+    "@mui/types": ^7.2.15
+    "@types/prop-types": ^15.7.12
+    clsx: ^2.1.1
+    prop-types: ^15.8.1
+    react-is: ^18.3.1
+  peerDependencies:
+    "@types/react": ^17.0.0 || ^18.0.0
+    react: ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 
6f8068f07f60a842fcb2e2540eecbd9c5f04df695bcc427184720e8ae138ae689fefd3c20147ab7c76e809ede6e10f5e08d1c34cd3a8b09bd22d2020a666a96f
+  languageName: node
+  linkType: hard
+
 "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1":
   version: 5.1.1-v1
   resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1"
@@ -2104,6 +2292,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@popperjs/core@npm:^2.11.8":
+  version: 2.11.8
+  resolution: "@popperjs/core@npm:2.11.8"
+  checksum: 
e5c69fdebf52a4012f6a1f14817ca8e9599cb1be73dd1387e1785e2ed5e5f0862ff817f420a87c7fc532add1f88a12e25aeb010ffcbdc98eace3d55ce2139cf0
+  languageName: node
+  linkType: hard
+
 "@rc-component/color-picker@npm:~1.5.2":
   version: 1.5.2
   resolution: "@rc-component/color-picker@npm:1.5.2"
@@ -2629,6 +2824,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/prop-types@npm:^15.7.12":
+  version: 15.7.12
+  resolution: "@types/prop-types@npm:15.7.12"
+  checksum: 
ac16cc3d0a84431ffa5cfdf89579ad1e2269549f32ce0c769321fdd078f84db4fbe1b461ed5a1a496caf09e637c0e367d600c541435716a55b1d9713f5035dfe
+  languageName: node
+  linkType: hard
+
 "@types/react-copy-to-clipboard@npm:^5.0.7":
   version: 5.0.7
   resolution: "@types/react-copy-to-clipboard@npm:5.0.7"
@@ -2677,6 +2879,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/react-transition-group@npm:^4.4.10":
+  version: 4.4.11
+  resolution: "@types/react-transition-group@npm:4.4.11"
+  dependencies:
+    "@types/react": "*"
+  checksum: 
a6e3b2e4363cb019e256ae4f19dadf9d7eb199da1a5e4109bbbf6a132821884044d332e9c74b520b1e5321a7f545502443fd1ce0b18649c8b510fa4220b0e5c2
+  languageName: node
+  linkType: hard
+
 "@types/react@npm:*, @types/react@npm:^18.2.56":
   version: 18.2.60
   resolution: "@types/react@npm:18.2.60"
@@ -2720,6 +2931,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/stylis@npm:4.2.5":
+  version: 4.2.5
+  resolution: "@types/stylis@npm:4.2.5"
+  checksum: 
24f91719db5569979e9e2f197e050ef82e1fd72474e8dc45bca38d48ee56481eae0f0d4a7ac172540d7774b45a2a78d901a4c6d07bba77a33dbccff464ea3edf
+  languageName: node
+  linkType: hard
+
 "@types/unist@npm:*, @types/unist@npm:^3.0.0":
   version: 3.0.2
   resolution: "@types/unist@npm:3.0.2"
@@ -3320,21 +3538,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"babel-plugin-styled-components@npm:>= 1.12.0":
-  version: 2.1.4
-  resolution: "babel-plugin-styled-components@npm:2.1.4"
-  dependencies:
-    "@babel/helper-annotate-as-pure": ^7.22.5
-    "@babel/helper-module-imports": ^7.22.5
-    "@babel/plugin-syntax-jsx": ^7.22.5
-    lodash: ^4.17.21
-    picomatch: ^2.3.1
-  peerDependencies:
-    styled-components: ">= 2"
-  checksum: 
d791aed68d975dae4f73055f86cd47afa99cb402b8113acdaf5678c8b6fba2cbc15543f2debe8ed09becb198aae8be2adfe268ad41f4bca917288e073a622bf8
-  languageName: node
-  linkType: hard
-
 "babel-plugin-transform-react-remove-prop-types@npm:^0.4.24":
   version: 0.4.24
   resolution: "babel-plugin-transform-react-remove-prop-types@npm:0.4.24"
@@ -3586,6 +3789,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"clsx@npm:^2.1.0, clsx@npm:^2.1.1":
+  version: 2.1.1
+  resolution: "clsx@npm:2.1.1"
+  checksum: 
acd3e1ab9d8a433ecb3cc2f6a05ab95fe50b4a3cfc5ba47abb6cbf3754585fcb87b84e90c822a1f256c4198e3b41c7f6c391577ffc8678ad587fc0976b24fd57
+  languageName: node
+  linkType: hard
+
 "color-convert@npm:^1.9.0":
   version: 1.9.3
   resolution: "color-convert@npm:1.9.3"
@@ -3668,6 +3878,11 @@ __metadata:
   dependencies:
     "@ahooksjs/use-url-state": ^3.5.1
     "@ant-design/icons": ^5.3.0
+    "@fontsource/roboto": ^5.0.14
+    "@mints/miller-columns": ^2.0.0-beta.1
+    "@mui/icons-material": ^5.16.7
+    "@mui/material": ^5.16.7
+    "@mui/styled-engine-sc": ^6.0.0-alpha.18
     "@reduxjs/toolkit": ^2.2.1
     "@types/file-saver": ^2.0.5
     "@types/node": ^18.19.20
@@ -3694,7 +3909,6 @@ __metadata:
     husky: ^8.0.0
     lint-staged: ^13.1.0
     lodash: ^4.17.21
-    miller-columns-select: 1.4.1
     prettier: ^2.7.1
     react: ^18.2.0
     react-copy-to-clipboard: ^5.1.0
@@ -3812,7 +4026,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"css-to-react-native@npm:3.2.0, css-to-react-native@npm:^3.0.0":
+"css-to-react-native@npm:3.2.0":
   version: 3.2.0
   resolution: "css-to-react-native@npm:3.2.0"
   dependencies:
@@ -3830,7 +4044,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"csstype@npm:^3.0.2, csstype@npm:^3.1.3":
+"csstype@npm:3.1.3, csstype@npm:^3.0.2, csstype@npm:^3.1.3":
   version: 3.1.3
   resolution: "csstype@npm:3.1.3"
   checksum: 
8db785cc92d259102725b3c694ec0c823f5619a84741b5c7991b8ad135dfaa66093038a1cc63e03361a6cd28d122be48f2106ae72334e067dd619a51f49eddf7
@@ -3967,6 +4181,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"dom-helpers@npm:^5.0.1":
+  version: 5.2.1
+  resolution: "dom-helpers@npm:5.2.1"
+  dependencies:
+    "@babel/runtime": ^7.8.7
+    csstype: ^3.0.2
+  checksum: 
863ba9e086f7093df3376b43e74ce4422571d404fc9828bf2c56140963d5edf0e56160f9b2f3bb61b282c07f8fc8134f023c98fd684bddcb12daf7b0f14d951c
+  languageName: node
+  linkType: hard
+
 "dot-case@npm:^3.0.4":
   version: 3.0.4
   resolution: "dot-case@npm:3.0.4"
@@ -5202,7 +5426,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.3.0":
+"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2":
   version: 3.3.2
   resolution: "hoist-non-react-statics@npm:3.3.2"
   dependencies:
@@ -6416,20 +6640,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"miller-columns-select@npm:1.4.1":
-  version: 1.4.1
-  resolution: "miller-columns-select@npm:1.4.1"
-  dependencies:
-    classnames: ^2.3.2
-    react-infinite-scroll-component: ^6.1.0
-    styled-components: ^5.3.6
-  peerDependencies:
-    react: ^18.2.0
-    react-dom: ^18.2.0
-  checksum: 
88452c6d09d27116c1ef05dda7cab26f5d565ef2d63eac007ef9cc3d331cd0510997bcf0b45191678b323b0089b9bbca4973fabb12732c2c3ebc1d940164e8a5
-  languageName: node
-  linkType: hard
-
 "mime-db@npm:1.52.0":
   version: 1.52.0
   resolution: "mime-db@npm:1.52.0"
@@ -6989,6 +7199,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"postcss@npm:8.4.38":
+  version: 8.4.38
+  resolution: "postcss@npm:8.4.38"
+  dependencies:
+    nanoid: ^3.3.7
+    picocolors: ^1.0.0
+    source-map-js: ^1.2.0
+  checksum: 
649f9e60a763ca4b5a7bbec446a069edf07f057f6d780a5a0070576b841538d1ecf7dd888f2fbfd1f76200e26c969e405aeeae66332e6927dbdc8bdcb90b9451
+  languageName: node
+  linkType: hard
+
 "postcss@npm:^8.4.35":
   version: 8.4.35
   resolution: "postcss@npm:8.4.35"
@@ -7042,7 +7263,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
+"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
   version: 15.8.1
   resolution: "prop-types@npm:15.8.1"
   dependencies:
@@ -7713,6 +7934,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-is@npm:^18.3.1":
+  version: 18.3.1
+  resolution: "react-is@npm:18.3.1"
+  checksum: 
e20fe84c86ff172fc8d898251b7cc2c43645d108bf96d0b8edf39b98f9a2cae97b40520ee7ed8ee0085ccc94736c4886294456033304151c3f94978cec03df21
+  languageName: node
+  linkType: hard
+
 "react-markdown@npm:^9.0.1":
   version: 9.0.1
   resolution: "react-markdown@npm:9.0.1"
@@ -7806,6 +8034,21 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-transition-group@npm:^4.4.5":
+  version: 4.4.5
+  resolution: "react-transition-group@npm:4.4.5"
+  dependencies:
+    "@babel/runtime": ^7.5.5
+    dom-helpers: ^5.0.1
+    loose-envify: ^1.4.0
+    prop-types: ^15.6.2
+  peerDependencies:
+    react: ">=16.6.0"
+    react-dom: ">=16.6.0"
+  checksum: 
75602840106aa9c6545149d6d7ae1502fb7b7abadcce70a6954c4b64a438ff1cd16fc77a0a1e5197cdd72da398f39eb929ea06f9005c45b132ed34e056ebdeb1
+  languageName: node
+  linkType: hard
+
 "react@npm:^18.2.0":
   version: 18.2.0
   resolution: "react@npm:18.2.0"
@@ -8230,7 +8473,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"shallowequal@npm:1.1.0, shallowequal@npm:^1.1.0":
+"shallowequal@npm:1.1.0":
   version: 1.1.0
   resolution: "shallowequal@npm:1.1.0"
   checksum: 
f4c1de0837f106d2dbbfd5d0720a5d059d1c66b42b580965c8f06bb1db684be8783538b684092648c981294bf817869f743a066538771dbecb293df78f765e00
@@ -8341,6 +8584,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"source-map-js@npm:^1.2.0":
+  version: 1.2.0
+  resolution: "source-map-js@npm:1.2.0"
+  checksum: 
791a43306d9223792e84293b00458bf102a8946e7188f3db0e4e22d8d530b5f80a4ce468eb5ec0bf585443ad55ebbd630bf379c98db0b1f317fd902500217f97
+  languageName: node
+  linkType: hard
+
 "space-separated-tokens@npm:^2.0.0":
   version: 2.0.2
   resolution: "space-separated-tokens@npm:2.0.2"
@@ -8529,25 +8779,23 @@ __metadata:
   languageName: node
   linkType: hard
 
-"styled-components@npm:^5.3.6":
-  version: 5.3.11
-  resolution: "styled-components@npm:5.3.11"
+"styled-components@npm:^6.1.12":
+  version: 6.1.13
+  resolution: "styled-components@npm:6.1.13"
   dependencies:
-    "@babel/helper-module-imports": ^7.0.0
-    "@babel/traverse": ^7.4.5
-    "@emotion/is-prop-valid": ^1.1.0
-    "@emotion/stylis": ^0.8.4
-    "@emotion/unitless": ^0.7.4
-    babel-plugin-styled-components: ">= 1.12.0"
-    css-to-react-native: ^3.0.0
-    hoist-non-react-statics: ^3.0.0
-    shallowequal: ^1.1.0
-    supports-color: ^5.5.0
+    "@emotion/is-prop-valid": 1.2.2
+    "@emotion/unitless": 0.8.1
+    "@types/stylis": 4.2.5
+    css-to-react-native: 3.2.0
+    csstype: 3.1.3
+    postcss: 8.4.38
+    shallowequal: 1.1.0
+    stylis: 4.3.2
+    tslib: 2.6.2
   peerDependencies:
     react: ">= 16.8.0"
     react-dom: ">= 16.8.0"
-    react-is: ">= 16.8.0"
-  checksum: 
10edd4dae3b0231ec02d86bdd09c88e894eedfa7e9d4f8e562b09fb69c67a27d586cbcf35c785002d59b3bf11e6c0940b0efce40d13ae9ed148b26b1dc8f3284
+  checksum: 
cb836c5d4cc8d183f4b70a4a1b1aa13551c57389e9c8fe3286619eef9fc81466fee09c39a1c8b5aa03deb0e466e4d5ee04921f7d9f3b7afe4744e539e6047550
   languageName: node
   linkType: hard
 
@@ -8578,7 +8826,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0":
+"stylis@npm:4.3.2":
+  version: 4.3.2
+  resolution: "stylis@npm:4.3.2"
+  checksum: 
0faa8a97ff38369f47354376cd9f0def9bf12846da54c28c5987f64aaf67dcb6f00dce88a8632013bfb823b2c4d1d62a44f4ac20363a3505a7ab4e21b70179fc
+  languageName: node
+  linkType: hard
+
+"supports-color@npm:^5.3.0":
   version: 5.5.0
   resolution: "supports-color@npm:5.5.0"
   dependencies:
@@ -8708,6 +8963,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"tslib@npm:2.6.2, tslib@npm:^2.0.3, tslib@npm:^2.4.1":
+  version: 2.6.2
+  resolution: "tslib@npm:2.6.2"
+  checksum: 
329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad
+  languageName: node
+  linkType: hard
+
 "tslib@npm:^1.8.1":
   version: 1.14.1
   resolution: "tslib@npm:1.14.1"
@@ -8715,13 +8977,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"tslib@npm:^2.0.3, tslib@npm:^2.4.1":
-  version: 2.6.2
-  resolution: "tslib@npm:2.6.2"
-  checksum: 
329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad
-  languageName: node
-  linkType: hard
-
 "tsutils@npm:^3.21.0":
   version: 3.21.0
   resolution: "tsutils@npm:3.21.0"

Reply via email to