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 2164b9d7b feat: add some tips when updating scope config (#7422)
2164b9d7b is described below
commit 2164b9d7b2b3084325b19ea491391ab1bb2fa42a
Author: 青湛 <[email protected]>
AuthorDate: Mon May 6 14:08:34 2024 +0800
feat: add some tips when updating scope config (#7422)
---
config-ui/src/api/scope-config/index.ts | 5 ++
.../src/api/scope-config/{index.ts => types.ts} | 25 ++------
.../src/plugins/components/scope-config/index.tsx | 75 +++++++++++++++++-----
.../routes/blueprint/connection-detail/index.tsx | 3 +-
config-ui/src/routes/connection/connection.tsx | 50 +++++++++++++--
5 files changed, 117 insertions(+), 41 deletions(-)
diff --git a/config-ui/src/api/scope-config/index.ts
b/config-ui/src/api/scope-config/index.ts
index caaa789d7..41547d9c0 100644
--- a/config-ui/src/api/scope-config/index.ts
+++ b/config-ui/src/api/scope-config/index.ts
@@ -18,6 +18,8 @@
import { request } from '@/utils';
+import { ICheck } from './types';
+
export const list = (plugin: string, connectionId: ID) =>
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`);
@@ -35,3 +37,6 @@ export const update = (plugin: string, connectionId: ID, id:
ID, data: any) =>
method: 'patch',
data,
});
+
+export const check = (plugin: string, id: ID): Promise<ICheck> =>
+ request(`/plugins/${plugin}/scope-config/${id}/projects`);
diff --git a/config-ui/src/api/scope-config/index.ts
b/config-ui/src/api/scope-config/types.ts
similarity index 53%
copy from config-ui/src/api/scope-config/index.ts
copy to config-ui/src/api/scope-config/types.ts
index caaa789d7..4c779c658 100644
--- a/config-ui/src/api/scope-config/index.ts
+++ b/config-ui/src/api/scope-config/types.ts
@@ -16,22 +16,9 @@
*
*/
-import { request } from '@/utils';
-
-export const list = (plugin: string, connectionId: ID) =>
- request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`);
-
-export const get = (plugin: string, connectionId: ID, id: ID) =>
-
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs/${id}`);
-
-export const create = (plugin: string, connectionId: ID, data: any) =>
- request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`, {
- method: 'post',
- data,
- });
-
-export const update = (plugin: string, connectionId: ID, id: ID, data: any) =>
-
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs/${id}`, {
- method: 'patch',
- data,
- });
+export type ICheck = {
+ count: number;
+ projects: Array<{
+ name: string;
+ }>;
+};
diff --git a/config-ui/src/plugins/components/scope-config/index.tsx
b/config-ui/src/plugins/components/scope-config/index.tsx
index 7dd5b7e05..0bc83870d 100644
--- a/config-ui/src/plugins/components/scope-config/index.tsx
+++ b/config-ui/src/plugins/components/scope-config/index.tsx
@@ -18,10 +18,11 @@
import { useState } from 'react';
import { LinkOutlined, EditOutlined } from '@ant-design/icons';
-import { Button, Modal } from 'antd';
+import { theme, Button, Modal, Flex, Space } from 'antd';
import styled from 'styled-components';
import API from '@/api';
+import { Message } from '@/components';
import { operator } from '@/utils';
import { PluginName } from '../plugin-name';
@@ -34,16 +35,39 @@ interface Props {
plugin: string;
connectionId: ID;
scopeId: ID;
+ scopeName: string;
id?: ID;
name?: string;
- onSuccess?: () => void;
+ onSuccess?: (id?: ID) => void;
}
-export const ScopeConfig = ({ plugin, connectionId, scopeId, id, name,
onSuccess }: Props) => {
- const [type, setType] = useState<'associate' | 'update'>();
+export const ScopeConfig = ({ plugin, connectionId, scopeId, scopeName, id,
name, onSuccess }: Props) => {
+ const [type, setType] = useState<'associate' | 'update' |
'relatedProjects'>();
+ const [relatedProjects, setRelatedProjects] = useState<Array<{ name: string;
scopes: string[] }>>([]);
+
+ const {
+ token: { colorPrimary },
+ } = theme.useToken();
const handleHideDialog = () => setType(undefined);
+ const handleCheckScopeConfig = async () => {
+ if (!id) return;
+
+ const [success, res] = await operator(() => API.scopeConfig.check(plugin,
id), { hideToast: true });
+
+ if (success) {
+ const projects = res.projects.map((it: any) => ({ name: it.name, scopes:
[] }));
+
+ if (projects.length !== 1) {
+ setRelatedProjects(projects);
+ setType('relatedProjects');
+ } else {
+ setType('update');
+ }
+ }
+ };
+
const handleAssociate = async (trId: ID) => {
const [success] = await operator(
() => API.scope.update(plugin, connectionId, scopeId, { scopeConfigId:
trId !== 'None' ? +trId : null }),
@@ -54,13 +78,13 @@ export const ScopeConfig = ({ plugin, connectionId,
scopeId, id, name, onSuccess
if (success) {
handleHideDialog();
- onSuccess?.();
+ onSuccess?.(id);
}
};
const handleUpdate = (trId: ID) => {
handleHideDialog();
- onSuccess?.();
+ onSuccess?.(id);
};
return (
@@ -74,17 +98,7 @@ export const ScopeConfig = ({ plugin, connectionId, scopeId,
id, name, onSuccess
setType('associate');
}}
/>
- {id && (
- <Button
- size="small"
- type="link"
- icon={<EditOutlined />}
- onClick={() => {
- // TO-DO: check if the scope config is associated with any scope
- setType('update');
- }}
- />
- )}
+ {id && <Button size="small" type="link" icon={<EditOutlined />}
onClick={handleCheckScopeConfig} />}
{type === 'associate' && (
<Modal
open
@@ -127,6 +141,33 @@ export const ScopeConfig = ({ plugin, connectionId,
scopeId, id, name, onSuccess
/>
</Modal>
)}
+ {type === 'relatedProjects' && (
+ <Modal
+ open
+ width={830}
+ centered
+ footer={null}
+ title={`Edit '${name}' for '${scopeName}'`}
+ onCancel={handleHideDialog}
+ >
+ <Message content="The change will apply to all following projects:"
/>
+ <ul style={{ marginTop: 15, marginLeft: 30 }}>
+ {relatedProjects.map((it) => (
+ <li style={{ color: colorPrimary }}>
+ {it.name}:{it.scopes.join(',')}
+ </li>
+ ))}
+ </ul>
+ <Flex justify="end">
+ <Space>
+ <Button onClick={handleHideDialog}>Cancel</Button>
+ <Button type="primary" onClick={() => setType('update')}>
+ Continue
+ </Button>
+ </Space>
+ </Flex>
+ </Modal>
+ )}
</Wrapper>
);
};
diff --git a/config-ui/src/routes/blueprint/connection-detail/index.tsx
b/config-ui/src/routes/blueprint/connection-detail/index.tsx
index b686d9e81..08c8d8a06 100644
--- a/config-ui/src/routes/blueprint/connection-detail/index.tsx
+++ b/config-ui/src/routes/blueprint/connection-detail/index.tsx
@@ -263,11 +263,12 @@ export const BlueprintConnectionDetailPage = () => {
{
title: 'Scope Config',
key: 'scopeConfig',
- render: (_, { id, scopeConfigId, scopeConfigName }) => (
+ render: (_, { id, name, scopeConfigId, scopeConfigName }) => (
<ScopeConfig
plugin={plugin}
connectionId={connectionId}
scopeId={id}
+ scopeName={name}
id={scopeConfigId}
name={scopeConfigName}
onSuccess={handleChangeScopeConfig}
diff --git a/config-ui/src/routes/connection/connection.tsx
b/config-ui/src/routes/connection/connection.tsx
index 8b4913903..ba6d5d66a 100644
--- a/config-ui/src/routes/connection/connection.tsx
+++ b/config-ui/src/routes/connection/connection.tsx
@@ -69,10 +69,13 @@ export const Connection = () => {
token: { colorPrimary },
} = theme.useToken();
+ const [modal, contextHolder] = Modal.useModal();
+
const dispatch = useAppDispatch();
const connection = useAppSelector((state) => selectConnection(state,
`${plugin}-${connectionId}`)) as IConnection;
const navigate = useNavigate();
+
const { ready, data } = useRefreshData(
() => API.scope.list(plugin, connectionId, { page, pageSize, blueprints:
true }),
[version, page, pageSize],
@@ -227,9 +230,46 @@ export const Connection = () => {
}
};
- const handleScopeConfigChange = () => {
- // TO-DO: check scope config change will effect the scope config
- setVersion(version + 1);
+ const handleScopeConfigChange = async (scopeConfigId?: ID) => {
+ if (!scopeConfigId) {
+ return;
+ }
+
+ const [success, res] = await operator(() => API.scopeConfig.check(plugin,
scopeConfigId), { hideToast: true });
+
+ if (success) {
+ modal.success({
+ closable: true,
+ centered: true,
+ width: 830,
+ title: 'Scope Config Saved',
+ content: (
+ <>
+ <div style={{ marginBottom: 16 }}>
+ The listed projects are impacted. Please re-transform the data
to apply the updated scope config.
+ </div>
+ <ul>
+ {res.projects.map((it: any) => (
+ <li style={{ marginBottom: 10 }}>
+ <Space>
+ <span>{it.name}</span>
+ <Button
+ size="small"
+ type="link"
+ onClick={() => navigate(PATHS.PROJECT(it.name, { tab:
'status' }))}
+ >
+ Re-transform Data
+ </Button>
+ </Space>
+ </li>
+ ))}
+ </ul>
+ </>
+ ),
+ footer: null,
+ onCancel: () => setVersion(version + 1),
+ });
+ }
};
return (
@@ -305,11 +345,12 @@ export const Connection = () => {
title: 'Scope Config',
key: 'scopeConfig',
width: 400,
- render: (_, { id, configId, configName }) => (
+ render: (_, { id, name, configId, configName }) => (
<ScopeConfig
plugin={plugin}
connectionId={connectionId}
scopeId={id}
+ scopeName={name}
id={configId}
name={configName}
onSuccess={handleScopeConfigChange}
@@ -515,6 +556,7 @@ export const Connection = () => {
)}
</Modal>
)}
+ {contextHolder}
</PageHeader>
);
};