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>
);