You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by mi...@apache.org on 2024/09/27 06:33:09 UTC
(incubator-devlake) branch feat-miller-columns created (now 569953f60)
This is an automated email from the ASF dual-hosted git repository.
mintsweet pushed a change to branch feat-miller-columns
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
at 569953f60 feat: simplify the miller columns
This branch includes the following new commits:
new 569953f60 feat: simplify the miller columns
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(incubator-devlake) 01/01: feat: simplify the miller columns
Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mintsweet pushed a commit to branch feat-miller-columns
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 569953f6059b76d9292c3f824b1851a2e2bd847c
Author: mintsweet <0x...@gmail.com>
AuthorDate: Fri Sep 27 18:32:52 2024 +1200
feat: simplify the miller columns
---
config-ui/package.json | 4 +-
.../components/data-scope-remote/search-local.tsx | 129 +++++++-------------
.../components/data-scope-remote/search-remote.tsx | 135 ++++++++++-----------
.../plugins/components/data-scope-select/index.tsx | 95 ++++++++++-----
.../webhook/components/selector-dialog.tsx | 19 +--
config-ui/yarn.lock | 20 +--
6 files changed, 189 insertions(+), 213 deletions(-)
diff --git a/config-ui/package.json b/config-ui/package.json
index 6bf071988..7e1305d72 100644
--- a/config-ui/package.json
+++ b/config-ui/package.json
@@ -24,8 +24,8 @@
"dependencies": {
"@ant-design/icons": "^5.4.0",
"@fontsource/roboto": "^5.0.14",
- "@mints/hooks": "^1.0.0-beta.2",
- "@mints/miller-columns": "^2.0.0-beta.5",
+ "@mints/hooks": "^1.0.0-beta.9",
+ "@mints/miller-columns": "^2.0.0-beta.10",
"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
"@mui/styled-engine-sc": "^6.0.0-alpha.18",
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 67b8f4a7f..961ca68e9 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,11 +16,12 @@
*
*/
-import { useState, useReducer, useCallback } from 'react';
+import { useState, useReducer } from 'react';
import { CheckCircleFilled, SearchOutlined } from '@ant-design/icons';
import { Space, Tag, Button, Input, Modal } from 'antd';
-import { MillerColumns } from '@mints/miller-columns';
import { useDebounce } from '@mints/hooks';
+import type { IDType } from '@mints/miller-columns';
+import { MillerColumns } from '@mints/miller-columns';
import API from '@/api';
import { Block, Loading, Message } from '@/components';
@@ -76,43 +77,26 @@ export const SearchLocal = ({ mode, plugin, connectionId, config, disabledScope,
const searchDebounce = useDebounce(search, { wait: 500 });
- const request = useCallback(
- async (groupId?: string | number, params?: any) => {
- const res = await API.scope.remote(plugin, connectionId, {
- groupId: groupId ?? null,
- pageToken: params?.nextPageToken,
- });
-
- return {
- data: res.children.map((it) => ({
- parentId: it.parentId,
- id: it.id,
- title: it.name ?? it.fullName,
- canExpand: it.type === 'group',
- original: it,
- })),
- hasMore: !!res.nextPageToken,
- params: {
- nextPageToken: res.nextPageToken,
- },
- };
- },
- [plugin, connectionId, scope, searchDebounce],
- );
+ const request = async (groupId?: string | number, params?: any) => {
+ const res = await API.scope.remote(plugin, connectionId, {
+ groupId: groupId ?? null,
+ pageToken: params?.nextPageToken,
+ });
- const requestAll = useCallback(
- async (groupId?: string | number) => {
- 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: false,
- };
- },
- [scope, searchDebounce],
- );
+ return {
+ data: res.children.map((it) => ({
+ parentId: it.parentId,
+ id: it.id,
+ title: it.name ?? it.fullName,
+ canExpand: it.type === 'group',
+ original: it,
+ })),
+ hasMore: !!res.nextPageToken,
+ params: {
+ nextPageToken: res.nextPageToken,
+ },
+ };
+ };
const handleRequestAll = async () => {
setOpen(false);
@@ -145,6 +129,24 @@ export const SearchLocal = ({ mode, plugin, connectionId, config, disabledScope,
dispatch({ type: 'DONE' });
};
+ const millerColumnsProps = {
+ bordered: true,
+ theme: {
+ colorPrimary: '#7497f7',
+ borderColor: '#dbe4fd',
+ },
+ columnHeight: 300,
+ mode,
+ renderTitle: (id?: IDType) =>
+ !id &&
+ config.millerColumn?.firstColumnTitle && <S.ColumnTitle>{config.millerColumn.firstColumnTitle}</S.ColumnTitle>,
+ renderLoading: () => <Loading size={20} style={{ padding: '4px 12px' }} />,
+ selectable: true,
+ disabledIds: disabledScope.map((it) => it.id),
+ selectedIds: selectedScope.map((it) => it.id),
+ onSelectedIds: (_: IDType[], data?: any) => onChange(data ?? []),
+ };
+
return (
<>
<Block title={config.title} required>
@@ -189,56 +191,19 @@ export const SearchLocal = ({ mode, plugin, connectionId, config, disabledScope,
)}
</Block>
<Block>
- {status === 'idle' && (
+ {status === 'idle' ? (
<MillerColumns
- bordered
- theme={{
- colorPrimary: '#7497f7',
- borderColor: '#dbe4fd',
- }}
+ {...millerColumnsProps}
request={request}
- columnCount={search ? 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' }} />}
- renderError={() => <span style={{ color: 'red' }}>Something Error</span>}
- selectable
- disabledIds={(disabledScope ?? []).map((it) => it.id)}
- selectedIds={selectedScope.map((it) => it.id)}
- onSelectedIds={(_, data) => onChange(data ?? [])}
+ columnCount={config.millerColumn?.columnCount ?? 1}
/>
- )}
- {status === 'done' && (
+ ) : (
<>
<Input prefix={<SearchOutlined />} value={search} onChange={(e) => setSearch(e.target.value)} />
<MillerColumns
- bordered
- theme={{
- colorPrimary: '#7497f7',
- borderColor: '#dbe4fd',
- }}
- request={requestAll}
- columnCount={search ? 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' }} />}
- renderError={() => <span style={{ color: 'red' }}>Something Error</span>}
- selectable
- disabledIds={(disabledScope ?? []).map((it) => it.id)}
- selectedIds={selectedScope.map((it) => it.id)}
- onSelectedIds={(_, data) => onChange(data ?? [])}
+ {...millerColumnsProps}
+ loading={status === 'loading'}
+ items={searchDebounce ? scope.filter((it) => it.title.includes(searchDebounce) && !it.canExpand) : scope}
/>
</>
)}
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 0510ad29a..1841d3403 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,11 +16,13 @@
*
*/
-import { useState, useCallback } from 'react';
+import { useState } from 'react';
import { SearchOutlined } from '@ant-design/icons';
import { Space, Tag, Input } from 'antd';
-import { MillerColumns } from '@mints/miller-columns';
+import { useRequest } from '@mints/hooks';
import { useDebounce } from '@mints/hooks';
+import type { IDType } from '@mints/miller-columns';
+import { MillerColumns } from '@mints/miller-columns';
import API from '@/api';
import { Block, Loading } from '@/components';
@@ -43,60 +45,62 @@ export const SearchRemote = ({ mode, plugin, connectionId, config, disabledScope
const searchDebounce = useDebounce(search, { wait: 500 });
- const request = useCallback(
- async (groupId?: string | number, params?: any) => {
- let data = [];
- let hasMore = false;
- let newParams = {};
-
- 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',
- original: it,
- }));
+ const { loading, data } = useRequest(async () => {
+ if (!searchDebounce) {
+ return [];
+ }
+ const res = await API.scope.searchRemote(plugin, connectionId, {
+ search: searchDebounce,
+ page: 1,
+ pageSize: 50,
+ });
+ return res.children.map((it) => ({
+ parentId: it.parentId,
+ id: it.id,
+ title: it.fullName ?? it.name,
+ canExpand: it.type === 'group',
+ original: it,
+ }));
+ }, [plugin, connectionId, searchDebounce]);
- hasMore = !!res.nextPageToken;
- newParams = {
- pageToken: res.nextPageToken,
- };
- } else {
- const res = await API.scope.searchRemote(plugin, connectionId, {
- search: searchDebounce,
- page: params?.page ?? 1,
- pageSize: 20,
- });
+ const request = async (groupId?: string | number, params?: any) => {
+ 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.fullName ?? it.name,
- canExpand: it.type === 'group',
- original: it,
- }));
+ return {
+ data: res.children.map((it) => ({
+ parentId: it.parentId,
+ id: it.id,
+ title: it.name ?? it.fullName,
+ canExpand: it.type === 'group',
+ original: it,
+ })),
+ hasMore: !!res.nextPageToken,
+ params: {
+ pageToken: res.nextPageToken,
+ },
+ };
+ };
- hasMore = res.children.length === res.pageSize;
- newParams = {
- page: (params?.page ?? 0) + 1,
- count: (params?.count ?? 0) + res.children.length,
- };
- }
-
- return {
- data,
- hasMore,
- params: newParams,
- };
+ const millerColumnsProps = {
+ bordered: true,
+ theme: {
+ colorPrimary: '#7497f7',
+ borderColor: '#dbe4fd',
},
- [plugin, connectionId, searchDebounce],
- );
+ columnHeight: 300,
+ mode,
+ renderTitle: (id?: IDType) =>
+ !id &&
+ config.millerColumn?.firstColumnTitle && <S.ColumnTitle>{config.millerColumn.firstColumnTitle}</S.ColumnTitle>,
+ renderLoading: () => <Loading size={20} style={{ padding: '4px 12px' }} />,
+ selectable: true,
+ disabledIds: disabledScope.map((it) => it.id),
+ selectedIds: selectedScope.map((it) => it.id),
+ onSelectedIds: (_: IDType[], data?: any) => onChange(data ?? []),
+ };
return (
<>
@@ -125,28 +129,11 @@ export const SearchRemote = ({ mode, plugin, connectionId, config, disabledScope
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={(_, data) => onChange(data ?? [])}
- />
+ {searchDebounce ? (
+ <MillerColumns {...millerColumnsProps} loading={loading} items={data ?? []} columnCount={1} />
+ ) : (
+ <MillerColumns {...millerColumnsProps} request={request} columnCount={config.millerColumn?.columnCount} />
+ )}
</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 d6913cee0..6bee1af1e 100644
--- a/config-ui/src/plugins/components/data-scope-select/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-select/index.tsx
@@ -19,12 +19,15 @@
import { useState, useEffect, useCallback } from 'react';
import { RedoOutlined, PlusOutlined } from '@ant-design/icons';
import { Flex, Button, Input, Space, Tag } from 'antd';
+import { useRequest } from '@mints/hooks';
+import type { IDType } from '@mints/miller-columns';
import { MillerColumns } from '@mints/miller-columns';
import { useDebounce } from '@mints/hooks';
import API from '@/api';
import { Loading, Block, ExternalLink, Message } from '@/components';
import { getPluginScopeId } from '@/plugins';
+import type { IDataScope } from '@/types';
interface Props {
plugin: string;
@@ -65,6 +68,25 @@ export const DataScopeSelect = ({
);
}, []);
+ const { loading, data } = useRequest(async () => {
+ if (!searchDebounce) {
+ return [];
+ }
+ const res = await API.scope.list(plugin, connectionId, {
+ page: 1,
+ pageSize: 50,
+ searchTerm: searchDebounce,
+ });
+
+ return res.scopes.map((it) => ({
+ parentId: null,
+ id: getPluginScopeId(plugin, it.scope),
+ title: it.scope.fullName ?? it.scope.name,
+ canExpand: false,
+ original: it,
+ }));
+ }, [plugin, connectionId, searchDebounce, version]);
+
const request = useCallback(
async (_?: string | number, params?: any) => {
const res = await API.scope.list(plugin, connectionId, {
@@ -87,11 +109,46 @@ export const DataScopeSelect = ({
},
};
},
- [plugin, connectionId, searchDebounce, version],
+ [plugin, connectionId],
);
const handleSubmit = () => onSubmit?.(selectedIds);
+ const millerColumnsProps = {
+ bordered: true,
+ theme: {
+ colorPrimary: '#7497f7',
+ borderColor: '#dbe4fd',
+ },
+ columnHeight: 200,
+ renderLoading: () => <Loading size={20} style={{ padding: '4px 12px' }} />,
+ 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: true,
+ selectedIds,
+ onSelectedIds: (
+ ids: IDType[],
+ data?: Array<{
+ scope: IDataScope;
+ }>,
+ ) => {
+ setSelectedIds(ids);
+ setSelectedScope(
+ (data ?? []).map((it) => ({
+ id: getPluginScopeId(plugin, it.scope),
+ name: it.scope.fullName ?? it.scope.name,
+ })),
+ );
+ },
+ };
+
return (
<Block
title="Select Data Scope"
@@ -142,37 +199,11 @@ export const DataScopeSelect = ({
</Space>
<div>
<Input.Search value={search} onChange={(e) => setSearch(e.target.value)} />
- <MillerColumns
- bordered
- theme={{
- colorPrimary: '#7497f7',
- borderColor: '#dbe4fd',
- }}
- request={request}
- columnHeight={200}
- 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}
- onSelectedIds={(ids, data) => {
- setSelectedIds(ids);
- setSelectedScope(
- (data ?? []).map((it) => ({
- id: it.scope.id,
- name: it.scope.name,
- })),
- );
- }}
- />
+ {searchDebounce ? (
+ <MillerColumns {...millerColumnsProps} loading={loading} items={data ?? []} />
+ ) : (
+ <MillerColumns {...millerColumnsProps} request={request} rootId={version} />
+ )}
</div>
<Flex justify="flex-end" gap="small">
<Button onClick={onCancel}>Cancel</Button>
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 a0c972dee..516298572 100644
--- a/config-ui/src/plugins/register/webhook/components/selector-dialog.tsx
+++ b/config-ui/src/plugins/register/webhook/components/selector-dialog.tsx
@@ -16,7 +16,7 @@
*
*/
-import { useCallback, useState } from 'react';
+import { useState } from 'react';
import { Modal } from 'antd';
import { MillerColumns } from '@mints/miller-columns';
@@ -39,17 +39,6 @@ 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 (
@@ -74,7 +63,11 @@ export const SelectorDialog = ({ open, saving, onCancel, onSubmit }: Props) => {
colorPrimary: '#7497f7',
borderColor: '#dbe4fd',
}}
- request={request}
+ items={webhooks.map((it) => ({
+ parentId: null,
+ id: it.id,
+ title: it.name,
+ }))}
columnHeight={160}
renderLoading={() => <Loading size={20} style={{ padding: '4px 12px' }} />}
selectable
diff --git a/config-ui/yarn.lock b/config-ui/yarn.lock
index 9e36a73e3..c7db434e4 100644
--- a/config-ui/yarn.lock
+++ b/config-ui/yarn.lock
@@ -2073,9 +2073,9 @@ __metadata:
languageName: node
linkType: hard
-"@mints/hooks@npm:^1.0.0-beta.2":
- version: 1.0.0-beta.2
- resolution: "@mints/hooks@npm:1.0.0-beta.2"
+"@mints/hooks@npm:^1.0.0-beta.9":
+ version: 1.0.0-beta.9
+ resolution: "@mints/hooks@npm:1.0.0-beta.9"
dependencies:
lodash: ^4.17.21
react: ^18.3.1
@@ -2083,13 +2083,13 @@ __metadata:
peerDependencies:
react: ^18.3.1
react-dom: ^18.3.1
- checksum: b11707b70aca8c931d247e18065046d7f5bbef4eee7e17bbae1ff1c85a4f90e830d6af0d3397bd8bec63fa81b5f44055363184b162b4cd90edc0316d4d53251b
+ checksum: 03f146f2e1881dee18383502dc7631f630c7b99fd7da67d54d37a7b3abac6518e0a302e34b968c72d27cb21ae0c45c39e34d668930881d3e1fd2fbb7dac34b85
languageName: node
linkType: hard
-"@mints/miller-columns@npm:^2.0.0-beta.5":
- version: 2.0.0-beta.5
- resolution: "@mints/miller-columns@npm:2.0.0-beta.5"
+"@mints/miller-columns@npm:^2.0.0-beta.10":
+ version: 2.0.0-beta.10
+ resolution: "@mints/miller-columns@npm:2.0.0-beta.10"
dependencies:
"@fontsource/roboto": ^5.0.14
"@mui/material": ^5.16.7
@@ -2108,7 +2108,7 @@ __metadata:
react-dom: ^18.2.0
react-infinite-scroll-component: ^6.1.0
styled-components: ^6.1.12
- checksum: 2ff5e7e942a1f5e592d7fe53d5522a59d72075604e80cfcf816d70d67ad33d3982b699770cdab01065bff19a219117b51017ea878ce5f015f120fb6623431839
+ checksum: 94c3ba41210f2ccbddc413ef6c26e5615f11c5a3aac7954484d838d1b05713543def70b6714e79cfc396efea522f553b2d648b36af994bf66456a440836a1386
languageName: node
linkType: hard
@@ -3910,8 +3910,8 @@ __metadata:
dependencies:
"@ant-design/icons": ^5.4.0
"@fontsource/roboto": ^5.0.14
- "@mints/hooks": ^1.0.0-beta.2
- "@mints/miller-columns": ^2.0.0-beta.5
+ "@mints/hooks": ^1.0.0-beta.9
+ "@mints/miller-columns": ^2.0.0-beta.10
"@mui/icons-material": ^5.16.7
"@mui/material": ^5.16.7
"@mui/styled-engine-sc": ^6.0.0-alpha.18