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

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

commit 899310b819b5ae065d001d2679a37e6f04ac9d48
Author: mintsweet <0x1304...@gmail.com>
AuthorDate: Wed Sep 11 16:41:02 2024 +1200

    feat: adjust the part of github scope config cicd
---
 config-ui/src/api/scope-config/index.ts            |  18 +++-
 config-ui/src/api/scope-config/types.ts            |   5 +
 .../components/check-matched-items/index.tsx       |  93 +++++++++++++++++++
 .../src/plugins/components/deployments/index.tsx   | 102 +++++++++++++++++++++
 config-ui/src/plugins/components/index.ts          |   2 +
 .../plugins/components/scope-config-form/index.tsx |   2 +
 .../src/plugins/register/github/transformation.tsx |  34 ++++---
 7 files changed, 244 insertions(+), 12 deletions(-)

diff --git a/config-ui/src/api/scope-config/index.ts 
b/config-ui/src/api/scope-config/index.ts
index 41547d9c0..f29786b56 100644
--- a/config-ui/src/api/scope-config/index.ts
+++ b/config-ui/src/api/scope-config/index.ts
@@ -18,7 +18,7 @@
 
 import { request } from '@/utils';
 
-import { ICheck } from './types';
+import { ICheck, ITransform2deployments } from './types';
 
 export const list = (plugin: string, connectionId: ID) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`);
@@ -40,3 +40,19 @@ export const update = (plugin: string, connectionId: ID, id: 
ID, data: any) =>
 
 export const check = (plugin: string, id: ID): Promise<ICheck> =>
   request(`/plugins/${plugin}/scope-config/${id}/projects`);
+
+export const deployments = (plugin: string, connectionId: ID): 
Promise<string[]> =>
+  request(`/plugins/${plugin}/connections/${connectionId}/deployments`);
+
+export const transform2deployments = (
+  plugin: string,
+  connectionId: ID,
+  data: {
+    deploymentPattern: string;
+    productionPattern: string;
+  } & Pagination,
+): Promise<{ total: number; data: ITransform2deployments[] }> =>
+  
request(`/plugins/${plugin}/connections/${connectionId}/transform-to-deployments`,
 {
+    method: 'post',
+    data,
+  });
diff --git a/config-ui/src/api/scope-config/types.ts 
b/config-ui/src/api/scope-config/types.ts
index 4c779c658..e61992aca 100644
--- a/config-ui/src/api/scope-config/types.ts
+++ b/config-ui/src/api/scope-config/types.ts
@@ -22,3 +22,8 @@ export type ICheck = {
     name: string;
   }>;
 };
+
+export type ITransform2deployments = {
+  name: string;
+  url: string;
+};
diff --git a/config-ui/src/plugins/components/check-matched-items/index.tsx 
b/config-ui/src/plugins/components/check-matched-items/index.tsx
new file mode 100644
index 000000000..ce9c2b12b
--- /dev/null
+++ b/config-ui/src/plugins/components/check-matched-items/index.tsx
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { useState, useReducer } from 'react';
+import { SearchOutlined, PlusOutlined } from '@ant-design/icons';
+import { Flex, Button, Tag } from 'antd';
+
+import API from '@/api';
+import type { ITransform2deployments } from '@/api/scope-config/types';
+import { ExternalLink } from '@/components';
+
+const reducer = (state: ITransform2deployments[], action: { type: string; 
payload: ITransform2deployments[] }) => {
+  switch (action.type) {
+    case 'APPEND':
+      return [...state, ...action.payload];
+    default:
+      return state;
+  }
+};
+
+interface Props {
+  plugin: string;
+  connectionId: ID;
+  transformation: any;
+}
+
+export const CheckMatchedItems = ({ plugin, connectionId, transformation }: 
Props) => {
+  const [page, setPage] = useState(1);
+  const [total, setTotal] = useState(0);
+  const [loading, setLoading] = useState(false);
+
+  const [state, dispatch] = useReducer(reducer, []);
+
+  const handleLoadItems = async () => {
+    setLoading(true);
+    const res = await API.scopeConfig.transform2deployments(plugin, 
connectionId, {
+      deploymentPattern: transformation.deploymentPattern,
+      productionPattern: transformation.productionPattern,
+      page,
+      pageSize: 10,
+    });
+
+    dispatch({ type: 'APPEND', payload: res.data });
+
+    setPage(page + 1);
+    setTotal(res.total);
+    setLoading(false);
+  };
+
+  return (
+    <Flex vertical gap="small">
+      <div>
+        <Button ghost type="primary" loading={loading} icon={<SearchOutlined 
/>} onClick={handleLoadItems}>
+          Check Matched Items
+        </Button>
+      </div>
+      {!!state.length && (
+        <Flex vertical gap="small">
+          <h3>Matched Items</h3>
+          <Flex wrap="wrap" gap="small">
+            {state.map((it) => (
+              <Tag key={it.url} color="blue">
+                <ExternalLink link={it.url}>{it.name}</ExternalLink>
+              </Tag>
+            ))}
+          </Flex>
+          {total > state.length && (
+            <div>
+              <Button type="link" size="small" loading={loading} 
icon={<PlusOutlined />} onClick={handleLoadItems}>
+                See More
+              </Button>
+            </div>
+          )}
+        </Flex>
+      )}
+    </Flex>
+  );
+};
diff --git a/config-ui/src/plugins/components/deployments/index.tsx 
b/config-ui/src/plugins/components/deployments/index.tsx
new file mode 100644
index 000000000..b3b0d6a58
--- /dev/null
+++ b/config-ui/src/plugins/components/deployments/index.tsx
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { useState, useEffect } from 'react';
+import { Space, Select, Input } from 'antd';
+import { useRequest } from '@mints/hooks';
+
+import API from '@/api';
+import { PageLoading } from '@/components';
+
+interface Props {
+  plugin: string;
+  connectionId: ID;
+  transformation: any;
+  setTransformation: React.Dispatch<React.SetStateAction<any>>;
+}
+
+export const Deployments = ({ plugin, connectionId, transformation, 
setTransformation }: Props) => {
+  const [type, setType] = useState('regex');
+
+  const { loading, data } = useRequest(() => 
API.scopeConfig.deployments(plugin, connectionId), [plugin, connectionId]);
+
+  useEffect(() => {
+    if (transformation.envNamePattern) {
+      setType('regex');
+    }
+  }, [transformation]);
+
+  const handleChangeType = (t: string) => {
+    if (t === 'regex') {
+      setTransformation({
+        ...transformation,
+        envNameList: [],
+      });
+    }
+
+    if (t === 'select') {
+      setTransformation({
+        ...transformation,
+        envNamePattern: '',
+      });
+    }
+
+    setType(t);
+  };
+
+  const handleChangeRegex = (e: React.ChangeEvent<HTMLInputElement>) => {
+    const envNamePattern = e.target.value;
+    setTransformation({
+      ...transformation,
+      envNamePattern,
+      envNameList: [],
+    });
+  };
+
+  const handleChangeSelect = (value: string[]) => {
+    setTransformation({
+      ...transformation,
+      envNamePattern: '',
+      envNameList: value,
+    });
+  };
+
+  if (loading || !data) {
+    return <PageLoading />;
+  }
+
+  return (
+    <Space>
+      <Select value={type} onChange={handleChangeType}>
+        <Select.Option value="select">is one of</Select.Option>
+        <Select.Option value="regex">matches</Select.Option>
+      </Select>
+      {type === 'regex' ? (
+        <Input placeholder="(?i)prod(.*)" onChange={handleChangeRegex} />
+      ) : (
+        <Select mode="tags" style={{ width: 180 }} maxTagCount={2} 
onChange={handleChangeSelect}>
+          {data.map((d) => (
+            <Select.Option key={d} value={d}>
+              {d}
+            </Select.Option>
+          ))}
+        </Select>
+      )}
+    </Space>
+  );
+};
diff --git a/config-ui/src/plugins/components/index.ts 
b/config-ui/src/plugins/components/index.ts
index 337e446fe..4cbfa01e5 100644
--- a/config-ui/src/plugins/components/index.ts
+++ b/config-ui/src/plugins/components/index.ts
@@ -16,12 +16,14 @@
  *
  */
 
+export * from './check-matched-items';
 export * from './connection-form';
 export * from './connection-list';
 export * from './connection-select';
 export * from './connection-status';
 export * from './data-scope-remote';
 export * from './data-scope-select';
+export * from './deployments';
 export * from './plugin-name';
 export * from './scope-config';
 export * from './scope-config-form';
diff --git a/config-ui/src/plugins/components/scope-config-form/index.tsx 
b/config-ui/src/plugins/components/scope-config-form/index.tsx
index 5c27d84d4..06b4e27c6 100644
--- a/config-ui/src/plugins/components/scope-config-form/index.tsx
+++ b/config-ui/src/plugins/components/scope-config-form/index.tsx
@@ -243,6 +243,8 @@ export const ScopeConfigForm = ({
 
               {plugin === 'github' && (
                 <GitHubTransformation
+                  plugin={plugin}
+                  connectionId={connectionId}
                   entities={entities}
                   transformation={transformation}
                   setTransformation={setTransformation}
diff --git a/config-ui/src/plugins/register/github/transformation.tsx 
b/config-ui/src/plugins/register/github/transformation.tsx
index 0d6473c4d..9114e72eb 100644
--- a/config-ui/src/plugins/register/github/transformation.tsx
+++ b/config-ui/src/plugins/register/github/transformation.tsx
@@ -23,15 +23,25 @@ import { theme, Form, Collapse, Input, Tag, Checkbox } from 
'antd';
 
 import { HelpTooltip, ExternalLink } from '@/components';
 import { DOC_URL } from '@/release';
+import { CheckMatchedItems, Deployments } from '@/plugins';
 
 interface Props {
+  plugin: string;
+  connectionId: ID;
   entities: string[];
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
   setHasError: React.Dispatch<React.SetStateAction<boolean>>;
 }
 
-export const GitHubTransformation = ({ entities, transformation, 
setTransformation, setHasError }: Props) => {
+export const GitHubTransformation = ({
+  plugin,
+  connectionId,
+  entities,
+  transformation,
+  setTransformation,
+  setHasError,
+}: Props) => {
   const [useCustom, setUseCustom] = useState(false);
 
   useEffect(() => {
@@ -77,6 +87,8 @@ export const GitHubTransformation = ({ entities, 
transformation, setTransformati
       style={{ background: token.colorBgContainer }}
       size="large"
       items={renderCollapseItems({
+        plugin,
+        connectionId,
         entities,
         panelStyle,
         transformation,
@@ -89,6 +101,8 @@ export const GitHubTransformation = ({ entities, 
transformation, setTransformati
 };
 
 const renderCollapseItems = ({
+  plugin,
+  connectionId,
   entities,
   panelStyle,
   transformation,
@@ -96,6 +110,8 @@ const renderCollapseItems = ({
   useCustom,
   onChangeUseCustom,
 }: {
+  plugin: string;
+  connectionId: ID;
   entities: string[];
   panelStyle: React.CSSProperties;
   transformation: any;
@@ -245,16 +261,11 @@ const renderCollapseItems = ({
           </Checkbox>
           <div style={{ margin: '8px 0', paddingLeft: 28 }}>
             <span>If its environment name matches</span>
-            <Input
-              style={{ width: 180, margin: '0 8px' }}
-              placeholder="(?i)prod(.*)"
-              value={transformation.envNamePattern}
-              onChange={(e) =>
-                onChangeTransformation({
-                  ...transformation,
-                  envNamePattern: e.target.value,
-                })
-              }
+            <Deployments
+              plugin={plugin}
+              connectionId={connectionId}
+              transformation={transformation}
+              setTransformation={onChangeTransformation}
             />
             <span>, this deployment is a ‘Production Deployment’</span>
           </div>
@@ -296,6 +307,7 @@ const renderCollapseItems = ({
             <span>, this deployment is a ‘Production Deployment’</span>
             <HelpTooltip content="If you leave this field empty, all 
Deployments will be tagged as in the Production environment. " />
           </div>
+          <CheckMatchedItems plugin={plugin} connectionId={connectionId} 
transformation={transformation} />
         </>
       ),
     },

Reply via email to