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

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

commit 9f8cc63bf89dd7c24a12d2fe77a1b37f1f790961
Author: mintsweet <[email protected]>
AuthorDate: Wed Aug 23 11:20:49 2023 +1200

    refactor(config-ui): improve the plugin component data-scope-select-remote
---
 .../components/data-scope-select-remote/api.ts     |  18 +++
 .../components/data-scope-select-remote/index.tsx  | 168 ++++++++++++++++-----
 .../components/data-scope-select-remote/styled.ts  |   5 +
 .../{styled.ts => types.ts}                        |  18 ++-
 4 files changed, 168 insertions(+), 41 deletions(-)

diff --git a/config-ui/src/plugins/components/data-scope-select-remote/api.ts 
b/config-ui/src/plugins/components/data-scope-select-remote/api.ts
index 19abb110d..1d8c79f41 100644
--- a/config-ui/src/plugins/components/data-scope-select-remote/api.ts
+++ b/config-ui/src/plugins/components/data-scope-select-remote/api.ts
@@ -18,6 +18,24 @@
 
 import { request } from '@/utils';
 
+import * as T from './types';
+
+export const getRemoteScope = (plugin: string, connectionId: ID, params: 
T.GetRemoteScopeParams) =>
+  request(`/plugins/${plugin}/connections/${connectionId}/remote-scopes`, {
+    method: 'get',
+    data: params,
+  });
+
+export const searchRemoteScope = (
+  plugin: string,
+  connectionId: ID,
+  params: T.SearchRemoteScopeParams,
+): Promise<{ children: T.ResItem[] }> =>
+  
request(`/plugins/${plugin}/connections/${connectionId}/search-remote-scopes`, {
+    method: 'get',
+    data: params,
+  });
+
 export const getDataScope = (plugin: string, connectionId: ID, scopeId: 
string) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scopes/${scopeId}`);
 
diff --git 
a/config-ui/src/plugins/components/data-scope-select-remote/index.tsx 
b/config-ui/src/plugins/components/data-scope-select-remote/index.tsx
index 3b5565224..e454087c4 100644
--- a/config-ui/src/plugins/components/data-scope-select-remote/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-select-remote/index.tsx
@@ -16,16 +16,18 @@
  *
  */
 
-import { useMemo, useState } from 'react';
-import { Button, Intent } from '@blueprintjs/core';
+import { useEffect, useMemo, useState } from 'react';
+import { Button, Intent, InputGroup } from '@blueprintjs/core';
+import type { McsID, McsItem, McsColumn } from 'miller-columns-select';
+import MillerColumnsSelect from 'miller-columns-select';
+import { useDebounce } from 'ahooks';
+import { uniqBy } from 'lodash';
 
-import { Buttons } from '@/components';
+import { FormItem, MultiSelector, Loading, Buttons } from '@/components';
 import { getPluginConfig, getPluginScopeId } from '@/plugins';
 import { operator } from '@/utils';
 
-import { DataScopeMillerColumns } from '../data-scope-miller-columns';
-import { DataScopeSearch } from '../data-scope-search';
-
+import * as T from './types';
 import * as API from './api';
 import * as S from './styled';
 
@@ -39,16 +41,80 @@ interface Props {
 
 export const DataScopeSelectRemote = ({ plugin, connectionId, disabledScope, 
onCancel, onSubmit }: Props) => {
   const [operating, setOperating] = useState(false);
-  const [selectedItems, setSelectedItems] = useState<Array<{ data: any }>>([]);
 
-  const disabledItems = useMemo(
-    () => (disabledScope ?? []).map((it) => ({ id: getPluginScopeId(plugin, 
it) })),
-    [disabledScope],
+  // miller columns
+  const [items, setItems] = useState<McsItem<T.ResItem>[]>([]);
+  const [selectedItems, setSelectedItems] = useState<T.ResItem[]>([]);
+  const [loadedIds, setLoadedIds] = useState<ID[]>([]);
+  const [nextTokenMap, setNextTokenMap] = useState<Record<ID, string>>({});
+
+  // search
+  const [query, setQuery] = useState('');
+  const [items2, setItems2] = useState<McsItem<T.ResItem>[]>([]);
+  const [selectedItems2, setSelectedItems2] = useState<T.ResItem[]>([]);
+  const [page, setPage] = useState(1);
+  const [total, setTotal] = useState(0);
+  const search = useDebounce(query, { wait: 500 });
+
+  const config = useMemo(() => getPluginConfig(plugin).dataScope, [plugin]);
+
+  const selectedScope = useMemo(
+    () => uniqBy([...selectedItems, ...selectedItems2], 'id'),
+    [selectedItems, selectedItems2],
   );
 
-  const pluginConfig = useMemo(() => getPluginConfig(plugin), [plugin]);
+  const getItems = async (groupId: ID | null, currentPageToken?: string) => {
+    const res = await API.getRemoteScope(plugin, connectionId, {
+      groupId,
+      pageToken: currentPageToken,
+    });
+
+    setItems([
+      ...items,
+      ...(res.children ?? []).map((it: any) => ({
+        ...it,
+        title: it.name,
+      })),
+    ]);
+
+    if (!res.nextPageToken) {
+      setLoadedIds([...loadedIds, groupId ? groupId : 'root']);
+    } else {
+      setNextTokenMap({
+        ...nextTokenMap,
+        [`${groupId ? groupId : 'root'}`]: res.nextPageToken,
+      });
+    }
+  };
+
+  useEffect(() => {
+    getItems(null);
+  }, []);
 
-  const error = useMemo(() => (!selectedItems.length ? 'No Data Scope is 
Selected' : ''), [selectedItems]);
+  const searchItems = async () => {
+    if (!search) return;
+
+    const res = await API.searchRemoteScope(plugin, connectionId, {
+      search,
+      page,
+      pageSize: 50,
+    });
+
+    setItems2(
+      res.children.map((it) => ({
+        ...it,
+        title: it.fullName,
+      })),
+    );
+
+    if (page === 1) {
+      // setTotal(res.count);
+    }
+  };
+
+  useEffect(() => {
+    searchItems();
+  }, [search, page]);
 
   const handleSubmit = async () => {
     const [success, res] = await operator(
@@ -66,40 +132,64 @@ export const DataScopeSelectRemote = ({ plugin, 
connectionId, disabledScope, onC
 
   return (
     <S.Wrapper>
-      {pluginConfig.dataScope.render ? (
-        pluginConfig.dataScope.render({
+      {config.render ? (
+        config.render({
           plugin,
           connectionId,
-          disabledItems,
+          disabledItems: (disabledScope ?? []).map((scope) => ({ id: 
getPluginScopeId(plugin, scope) })),
           selectedItems,
           onChangeItems: setSelectedItems,
         })
       ) : (
         <>
-          <h4>{pluginConfig.dataScope.millerColumns?.title}</h4>
-          <p>{pluginConfig.dataScope.millerColumns?.subTitle}</p>
-          <DataScopeMillerColumns
-            title={pluginConfig.dataScope.millerColumns?.firstColumnTitle}
-            columnCount={pluginConfig.dataScope.millerColumns?.columnCount ?? 
3}
-            plugin={plugin}
-            connectionId={connectionId}
-            disabledItems={disabledItems}
-            selectedItems={selectedItems}
-            onChangeItems={setSelectedItems}
-          />
-          {pluginConfig.dataScope.search && (
-            <>
-              <h5 style={{ marginTop: 16 
}}>{pluginConfig.dataScope.search.title}</h5>
-              <p>{pluginConfig.dataScope.search.subTitle}</p>
-              <DataScopeSearch
-                plugin={plugin}
-                connectionId={connectionId}
-                disabledItems={disabledItems}
-                selectedItems={selectedItems}
-                onChangeItems={setSelectedItems}
+          <FormItem label={config.title} required>
+            <MultiSelector
+              disabled
+              items={selectedScope}
+              getKey={(it) => it.id}
+              getName={(it) => it.fullName}
+              selectedItems={selectedScope}
+            />
+          </FormItem>
+          <FormItem>
+            <InputGroup leftIcon="search" value={query} onChange={(e) => 
setQuery(e.target.value)} />
+            {!search ? (
+              <MillerColumnsSelect
+                items={items}
+                columnCount={config.millerColumnCount ?? 1}
+                columnHeight={300}
+                getCanExpand={(it) => it.type === 'group'}
+                getHasMore={(id) => !loadedIds.includes(id ?? 'root')}
+                onExpand={(id: McsID) => getItems(id, nextTokenMap[id])}
+                onScroll={(id: McsID | null) => getItems(id, nextTokenMap[id 
?? 'root'])}
+                renderTitle={(column: McsColumn) =>
+                  !column.parentId &&
+                  config.millerFirstTitle && 
<S.ColumnTitle>{config.millerFirstTitle}</S.ColumnTitle>
+                }
+                renderLoading={() => <Loading size={20} style={{ padding: '4px 
12px' }} />}
+                disabledIds={(disabledScope ?? []).map((it) => 
getPluginScopeId(plugin, it))}
+                selectedIds={selectedScope.map((it) => it.id)}
+                onSelectItemIds={(selectedIds: ID[]) =>
+                  setSelectedItems(items.filter((it) => 
selectedIds.includes(it.id)))
+                }
+              />
+            ) : (
+              <MillerColumnsSelect
+                items={items2}
+                columnCount={1}
+                columnHeight={300}
+                getCanExpand={() => false}
+                getHasMore={() => total === 0}
+                onScroll={() => setPage(page + 1)}
+                renderLoading={() => <Loading size={20} style={{ padding: '4px 
12px' }} />}
+                disabledIds={(disabledScope ?? []).map((it) => 
getPluginScopeId(plugin, it))}
+                selectedIds={selectedScope.map((it) => it.id)}
+                onSelectItemIds={(selectedIds: ID[]) =>
+                  setSelectedItems2(items2.filter((it) => 
selectedIds.includes(it.id)))
+                }
               />
-            </>
-          )}
+            )}
+          </FormItem>
         </>
       )}
       <Buttons position="bottom" align="right">
@@ -109,7 +199,7 @@ export const DataScopeSelectRemote = ({ plugin, 
connectionId, disabledScope, onC
           intent={Intent.PRIMARY}
           text="Save"
           loading={operating}
-          disabled={!!error}
+          disabled={!selectedItems.length}
           onClick={handleSubmit}
         />
       </Buttons>
diff --git 
a/config-ui/src/plugins/components/data-scope-select-remote/styled.ts 
b/config-ui/src/plugins/components/data-scope-select-remote/styled.ts
index 4bf74a53c..41e76ecb3 100644
--- a/config-ui/src/plugins/components/data-scope-select-remote/styled.ts
+++ b/config-ui/src/plugins/components/data-scope-select-remote/styled.ts
@@ -19,3 +19,8 @@
 import styled from 'styled-components';
 
 export const Wrapper = styled.div``;
+
+export const ColumnTitle = styled.div`
+  padding: 6px 12px;
+  font-weight: 600;
+`;
diff --git 
a/config-ui/src/plugins/components/data-scope-select-remote/styled.ts 
b/config-ui/src/plugins/components/data-scope-select-remote/types.ts
similarity index 73%
copy from config-ui/src/plugins/components/data-scope-select-remote/styled.ts
copy to config-ui/src/plugins/components/data-scope-select-remote/types.ts
index 4bf74a53c..02f5b8b40 100644
--- a/config-ui/src/plugins/components/data-scope-select-remote/styled.ts
+++ b/config-ui/src/plugins/components/data-scope-select-remote/types.ts
@@ -16,6 +16,20 @@
  *
  */
 
-import styled from 'styled-components';
+export type ResItem = {
+  type: 'group' | 'scope';
+  parentId: ID | null;
+  id: ID;
+  name: string;
+  fullName: string;
+  data: any;
+};
 
-export const Wrapper = styled.div``;
+export type GetRemoteScopeParams = {
+  groupId: ID | null;
+  pageToken?: string;
+};
+
+export type SearchRemoteScopeParams = {
+  search?: string;
+} & Pagination;

Reply via email to