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

mintsweet 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 31e684198 feat(config-ui): support jira dev panel configuration (#5461)
31e684198 is described below

commit 31e68419899af480732fe9532092aa3e50bcf2b3
Author: 青湛 <[email protected]>
AuthorDate: Tue Jun 13 20:39:03 2023 +0800

    feat(config-ui): support jira dev panel configuration (#5461)
---
 config-ui/src/plugins/register/jira/api.ts         |   8 +
 .../jira/transformation-fields/cross-domain.tsx    | 167 +++++++++++++++++----
 .../register/jira/transformation-fields/styled.ts  |  17 +++
 .../src/plugins/register/jira/transformation.tsx   |   6 +-
 4 files changed, 171 insertions(+), 27 deletions(-)

diff --git a/config-ui/src/plugins/register/jira/api.ts 
b/config-ui/src/plugins/register/jira/api.ts
index 764a3f755..cf1068b30 100644
--- a/config-ui/src/plugins/register/jira/api.ts
+++ b/config-ui/src/plugins/register/jira/api.ts
@@ -29,3 +29,11 @@ export const getBoards = (prefix: string, params: 
GetBoardsParams) =>
 export const getIssueType = (prefix: string) => 
request(`${prefix}/api/2/issuetype`);
 
 export const getField = (prefix: string) => request(`${prefix}/api/2/field`);
+
+export const getApplicationTypes = (connectionId: ID, query: { key: string }) 
=>
+  request(`/plugins/jira/connections/${connectionId}/application-types`, {
+    data: query,
+  });
+
+export const getDevPanelCommits = (connectionId: ID, query: { key: string; 
applicationType: string }) =>
+  request(`/plugins/jira/connections/${connectionId}/dev-panel-commits`, { 
data: query });
diff --git 
a/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx 
b/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx
index f27065ab8..bce16432d 100644
--- a/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx
+++ b/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx
@@ -17,22 +17,34 @@
  */
 
 import { useState, useEffect } from 'react';
-import { Radio, Icon, Collapse, InputGroup, Button, Intent } from 
'@blueprintjs/core';
+import { Radio, Icon, Collapse, InputGroup, Button, Intent, RadioGroup } from 
'@blueprintjs/core';
 
-import { ExternalLink, IconButton } from '@/components';
+import { ExternalLink, IconButton, Dialog, FormItem } from '@/components';
 import JiraIssueTipsImg from '@/images/jira-issue-tips.png';
+import { operator } from '@/utils';
+
+import * as API from '../api';
 
 import * as S from './styled';
 
 interface Props {
+  connectionId: ID;
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const CrossDomain = ({ transformation, setTransformation }: Props) => {
+export const CrossDomain = ({ connectionId, transformation, setTransformation 
}: Props) => {
   const [radio, setRadio] = useState<'repo' | 'commitSha'>('repo');
   const [repoTips, setRepoTips] = useState(false);
   const [repoLinks, setRepoLinks] = useState([]);
+  const [isOpen, setIsOpen] = useState(false);
+  const [step, setStep] = useState(1);
+  const [issueKey, setIssueKey] = useState('');
+  const [searching, setSearching] = useState(false);
+  const [applicationTypes, setApplicationTypes] = useState<string[]>([]);
+  const [applicationType, setApplicationType] = useState<string>();
+  const [operating, setOperating] = useState(false);
+  const [devPanelCommits, setDevPanelCommits] = useState<string[]>([]);
 
   useEffect(() => {
     if (transformation.remotelinkCommitShaPattern) {
@@ -88,6 +100,49 @@ export const CrossDomain = ({ transformation, 
setTransformation }: Props) => {
     });
   };
 
+  const handleShowDevPanel = () => setIsOpen(true);
+  const handleHideDevPanel = () => setIsOpen(false);
+
+  const handleSearch = async () => {
+    const [success, res] = await operator(() => 
API.getApplicationTypes(connectionId, { key: issueKey }), {
+      setOperating: setSearching,
+      hideToast: true,
+    });
+
+    if (success) {
+      setApplicationTypes(res);
+    }
+  };
+
+  const handleSubmit = async () => {
+    if (step === 1 && applicationType) {
+      const [success, res] = await operator(
+        () => API.getDevPanelCommits(connectionId, { key: issueKey, 
applicationType }),
+        {
+          setOperating,
+          hideToast: true,
+        },
+      );
+
+      if (success) {
+        setStep(2);
+        setDevPanelCommits(res);
+        return;
+      }
+    }
+
+    handleHideDevPanel();
+  };
+
+  const handleCancel = () => {
+    if (step === 1) {
+      handleHideDevPanel();
+      return;
+    }
+
+    setStep(1);
+  };
+
   return (
     <S.CrossDomain>
       <h2>Cross-domain</h2>
@@ -96,7 +151,7 @@ export const CrossDomain = ({ transformation, 
setTransformation }: Props) => {
         <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugCountPer1kLinesOfCode";>
           Bug Count per 1k Lines of Code
         </ExternalLink>{' '}
-        or man hour distribution on different work types. Connect `commits` 
and `issues` to measure metrics such as{' '}
+        or man hour distribution on different work types.
       </p>
       <div className="radio">
         <div className="radio-item">
@@ -104,7 +159,7 @@ export const CrossDomain = ({ transformation, 
setTransformation }: Props) => {
           <div className="content">
             <h5>Connect Jira issues and commits via Jira issues’ remote links 
that match the following pattern</h5>
             <p onClick={handleToggleRepoTips}>
-              The default pattern shows how to match and parse GitLab(Cloud) 
commits from issue remote links. See More{' '}
+              Input pattern(s) to match and parse commits and repo identifiers 
from issue remote links. See examples{' '}
               <Icon icon={!repoTips ? 'chevron-down' : 'chevron-up'} style={{ 
marginLeft: 8, cursor: 'pointer' }} />
             </p>
             <Collapse isOpen={repoTips}>
@@ -116,7 +171,7 @@ export const CrossDomain = ({ transformation, 
setTransformation }: Props) => {
                   <div className="input">
                     <InputGroup
                       key={i}
-                      
placeholder="https://gitlab.com/{namespace}/{repo_name}/-/commit/{commit_sha}";
+                      placeholder="E.g. 
https://gitlab.com/{namespace}/{repo_name}/-/commit/{commit_sha}";
                       value={link}
                       onChange={(e) => handleChangeRepoLinks(i, 
e.target.value)}
                     />
@@ -139,30 +194,90 @@ export const CrossDomain = ({ transformation, 
setTransformation }: Props) => {
         <div className="radio-item">
           <Radio checked={radio === 'commitSha'} onChange={() => 
handleChangeRadio('commitSha')} />
           <div className="content">
-            <h5>Connect Jira issues and commits via Jira’s development 
panel</h5>
-            <p>
-              Choose this if you’ve enabled{' '}
-              <ExternalLink 
link="https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/";>
-                issue’ development panel
+            <h5>
+              Connect Jira issues and commits via{' '}
+              <ExternalLink link="Links to: 
https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/";>
+                development panel
               </ExternalLink>
-              . Usually, it happens when you’re using BitBucket for source 
code management.
-            </p>
-            {radio === 'commitSha' && (
-              <InputGroup
-                fill
-                placeholder="/commit/([0-9a-f]{40})$"
-                value={transformation.remotelinkCommitShaPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    remotelinkCommitShaPattern: e.target.value,
-                  })
-                }
-              />
-            )}
+            </h5>
+            <p>Finish the configuration so DevLake can get your Git data from 
your Jira development panel.</p>
+            {radio === 'commitSha' && <Button text="Configure" 
onClick={handleShowDevPanel} />}
           </div>
         </div>
       </div>
+      <Dialog
+        style={{ width: 820 }}
+        isOpen={isOpen}
+        title="Configure the `Application Type` and `Commit Pattern` by 
sending request(s) to Jira."
+        okText={step === 1 ? 'Next' : 'Save'}
+        okDisabled={(step === 1 && !applicationType) || (step === 2 && 
!transformation.remotelinkCommitShaPattern)}
+        okLoading={operating}
+        cancelText={step === 2 ? 'Prev' : 'Cancel'}
+        onOk={handleSubmit}
+        onCancel={handleCancel}
+      >
+        <S.DialogBody>
+          {step === 1 && (
+            <>
+              <FormItem
+                label="Jira Issue Key"
+                subLabel="Input any issue key that has connected commit(s) in 
the development panel"
+                required
+              >
+                <div className="search">
+                  <InputGroup
+                    placeholder="Please enter..."
+                    value={issueKey}
+                    onChange={(e) => setIssueKey(e.target.value)}
+                  />
+                  <Button loading={searching} disabled={!issueKey} text="See 
Results" onClick={handleSearch} />
+                </div>
+              </FormItem>
+              {applicationTypes.length > 0 && (
+                <FormItem label="Application Type" subLabel="Please choose an 
application type." required>
+                  <RadioGroup
+                    selectedValue={applicationType}
+                    onChange={(e) => setApplicationType((e.target as 
HTMLInputElement).value)}
+                  >
+                    {applicationTypes.map((at) => (
+                      <Radio key={at} value={at} label={at} />
+                    ))}
+                  </RadioGroup>
+                </FormItem>
+              )}
+            </>
+          )}
+          {step === 2 && (
+            <>
+              <FormItem label="Jira Issue Key">{issueKey}</FormItem>
+              <FormItem label="Application Type">{applicationType}</FormItem>
+              <FormItem label="Commit Url Preview" subLabel="The latest five 
commit(s) associated with the issue.">
+                <ul>
+                  {devPanelCommits.map((commit) => (
+                    <li key={commit}>{commit}</li>
+                  ))}
+                </ul>
+              </FormItem>
+              <FormItem
+                label="Commit Pattern"
+                subLabel={
+                  <>
+                    Input pattern(s) to match and parse commits and repo 
identifiers from above commit URLs. See
+                    examples
+                  </>
+                }
+                required
+              >
+                <InputGroup
+                  placeholder="eg. 
https://gitlab.com/{namespace}/{repo_name}/commit/{commit_sha}";
+                  value={transformation.remotelinkCommitShaPattern}
+                  onChange={(e) => setTransformation({ ...transformation, 
remotelinkCommitShaPattern: e.target.value })}
+                />
+              </FormItem>
+            </>
+          )}
+        </S.DialogBody>
+      </Dialog>
     </S.CrossDomain>
   );
 };
diff --git 
a/config-ui/src/plugins/register/jira/transformation-fields/styled.ts 
b/config-ui/src/plugins/register/jira/transformation-fields/styled.ts
index 84cfaa482..2ea1165bb 100644
--- a/config-ui/src/plugins/register/jira/transformation-fields/styled.ts
+++ b/config-ui/src/plugins/register/jira/transformation-fields/styled.ts
@@ -38,3 +38,20 @@ export const CrossDomain = styled.div`
     }
   }
 `;
+
+export const DialogBody = styled.div`
+  ul {
+    padding: 8px 16px;
+    background: #efefef;
+  }
+
+  .search {
+    display: flex;
+    align-items: center;
+
+    .bp4-input-group {
+      margin-right: 24px;
+      width: 360px;
+    }
+  }
+`;
diff --git a/config-ui/src/plugins/register/jira/transformation.tsx 
b/config-ui/src/plugins/register/jira/transformation.tsx
index 7f13e9e22..8f4024774 100644
--- a/config-ui/src/plugins/register/jira/transformation.tsx
+++ b/config-ui/src/plugins/register/jira/transformation.tsx
@@ -245,7 +245,11 @@ export const JiraTransformation = ({ entities, 
connectionId, transformation, set
         </div>
       )}
       {entities.includes('CROSS') && (
-        <CrossDomain transformation={transformation} 
setTransformation={setTransformation} />
+        <CrossDomain
+          connectionId={connectionId}
+          transformation={transformation}
+          setTransformation={setTransformation}
+        />
       )}
     </S.TransformationWrapper>
   );

Reply via email to