Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7f559bd

Browse files
feat(mr): update desc.
1 parent 1dcda7d commit 7f559bd

File tree

12 files changed

+190
-47
lines changed

12 files changed

+190
-47
lines changed

‎src/codingServer.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
ICreateMRResp,
1616
IBranchListResp,
1717
IMemberListResp,
18+
IMRContentResp,
1819
} from 'src/typings/respResult';
1920
import { PromiseAdapter, promiseFromEvent, parseQuery, parseCloneUrl } from 'src/common/utils';
2021
import { GitService } from 'src/common/gitService';
@@ -660,6 +661,30 @@ export class CodingServer {
660661
return fulfilled;
661662
}
662663

664+
public async updateMRDesc(iid: string, content: string) {
665+
try {
666+
const { repoApiPrefix } = await this.getApiPrefix();
667+
const resp: IMRContentResp = await got
668+
.put(`${repoApiPrefix}/merge/${iid}/update-content`, {
669+
form: {
670+
content,
671+
},
672+
searchParams: {
673+
access_token: this._session?.accessToken,
674+
},
675+
})
676+
.json();
677+
678+
if (resp.code) {
679+
return Promise.reject(resp);
680+
}
681+
682+
return resp;
683+
} catch (e) {
684+
return Promise.reject(e);
685+
}
686+
}
687+
663688
get loggedIn() {
664689
return this._loggedIn;
665690
}

‎src/panel.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ export class Panel {
162162
} catch (err) {}
163163
break;
164164
}
165+
case `mr.update.desc`: {
166+
try {
167+
const [iid, content] = args;
168+
const resp = await codingSrv.updateMRDesc(iid, content);
169+
this.broadcast(command, [iid, resp.data]);
170+
} catch (e) {}
171+
break;
172+
}
165173
default:
166174
break;
167175
}

‎src/typings/commonTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface IMRWebViewDetail {
3636
repoInfo: IRepoInfo;
3737
data: IMRDetail & {
3838
loading: boolean;
39+
editingDesc: boolean;
3940
};
4041
user: IUserItem;
4142
}

‎src/typings/respResult.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,12 @@ export interface IMemberItem {
229229
}
230230

231231
export interface IMemberListResp extends IListResponse<IMemberItem> {}
232+
233+
export interface IMRContent {
234+
body: string;
235+
body_plan: string;
236+
}
237+
238+
export interface IMRContentResp extends CodingResponse {
239+
data: IMRContent;
240+
}

‎webviews/App.tsx

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import React, { useRef, useState } from 'react';
2-
1+
import React, { FormEvent, useRef, useState } from 'react';
32
import { view } from '@risingstack/react-easy-state';
3+
44
import appStore from 'webviews/store/appStore';
55
import persistDataHook from 'webviews/hooks/persistDataHook';
66
import Activities from 'webviews/components/Activities';
77
import Reviewers from 'webviews/components/Reviewers';
88
import messageTransferHook from 'webviews/hooks/messageTransferHook';
9+
import EditButton from 'webviews/components/EditButton';
10+
import { requestUpdateMRContent } from 'webviews/service/mrService';
11+
912
import {
1013
EmptyWrapper,
1114
TitleWrapper,
@@ -17,13 +20,17 @@ import {
1720
Empty,
1821
BranchName,
1922
EditBtn,
20-
} from 'webviews/styles/MROverview';
23+
OperationBtn,
24+
SectionTitle,
25+
} from 'webviews/app.styles';
2126

2227
function App() {
23-
const { currentMR, updateMRTitle } = appStore;
24-
const [isEditing,setEditing] = useState(false);
28+
const { currentMR, updateMRTitle, toggleUpdatingDesc } = appStore;
29+
const [isEditingTitle,setEditingTitle] = useState(false);
2530
const [title, setTitle] = useState(currentMR?.data?.merge_request?.title);
2631
const inputRef = useRef<HTMLInputElement | null>(null);
32+
const [desc, setDesc] = useState(``);
33+
2734
const { repoInfo, data } = currentMR;
2835
const { merge_request: mergeRequest } = data || {};
2936

@@ -33,7 +40,7 @@ function App() {
3340
const handleKeyDown = async (event: any) => {
3441
if (event.key === 'Enter') {
3542
await updateMRTitle(title);
36-
setEditing(false);
43+
setEditingTitle(false);
3744
}
3845
};
3946

@@ -47,10 +54,23 @@ function App() {
4754
};
4855

4956
const handleEdit = () => {
50-
setEditing(true);
57+
setEditingTitle(true);
5158
inputRef.current?.focus();
5259
};
5360

61+
const onEditDesc = () => {
62+
toggleUpdatingDesc();
63+
setDesc(currentMR.data.merge_request.body_plan);
64+
};
65+
66+
const onChangeDesc = (ev: FormEvent<HTMLTextAreaElement>) => {
67+
setDesc(ev.currentTarget.value);
68+
};
69+
70+
const onSaveDesc = async () => {
71+
await requestUpdateMRContent(currentMR.iid, desc);
72+
};
73+
5474
if (!currentMR.iid) {
5575
return <EmptyWrapper>Please select an merge request first.</EmptyWrapper>;
5676
}
@@ -62,13 +82,13 @@ function App() {
6282
return (
6383
<div>
6484
<TitleWrapper>
65-
{isEditing ? (
85+
{isEditingTitle ? (
6686
<input
6787
type='text'
6888
value={title}
6989
ref={(ref) => (inputRef.current = ref)}
70-
onBlur={() => setEditing(false)}
71-
onFocus={() => setEditing(true)}
90+
onBlur={() => setEditingTitle(false)}
91+
onFocus={() => setEditingTitle(true)}
7292
onKeyDown={handleKeyDown}
7393
onChange={handleTitleChange}
7494
/>
@@ -91,14 +111,39 @@ function App() {
91111
</Row>
92112
<BodyWrap>
93113
<Body>
94-
<h3>Description</h3>
95-
<Desc>
96-
{mergeRequest?.body ? (
97-
<div dangerouslySetInnerHTML={{ __html: mergeRequest?.body }} />
98-
) : (
99-
<Empty>Empty</Empty>
114+
<SectionTitle>
115+
Description
116+
{!currentMR.data.editingDesc && <EditButton onClick={onEditDesc} />}
117+
{currentMR.data.editingDesc && (
118+
<>
119+
<OperationBtn className={`colored`} onClick={onSaveDesc}>
120+
Save
121+
</OperationBtn>
122+
<OperationBtn className={`colored secondary`} onClick={() => toggleUpdatingDesc()}>
123+
Cancel
124+
</OperationBtn>
125+
</>
100126
)}
101-
</Desc>
127+
</SectionTitle>
128+
{!currentMR.data.editingDesc && (
129+
<Desc>
130+
{mergeRequest?.body ? (
131+
<div dangerouslySetInnerHTML={{ __html: mergeRequest?.body }} />
132+
) : (
133+
<Empty>This MR has no description.</Empty>
134+
)}
135+
</Desc>
136+
)}
137+
{currentMR.data.editingDesc && (
138+
<textarea
139+
name='desc'
140+
id='mr-desc'
141+
cols={30}
142+
rows={20}
143+
value={desc}
144+
onChange={onChangeDesc}
145+
/>
146+
)}
102147
<h3>Activities</h3>
103148
<Activities />
104149
</Body>

‎webviews/styles/MROverview.tsx renamed to ‎webviews/app.styles.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,11 @@ export const Empty = styled.div`
5353
export const BranchName = styled.code`
5454
margin: 0 1ex;
5555
`;
56+
57+
export const OperationBtn = styled.button`
58+
margin-left: 1em;
59+
`;
60+
61+
export const SectionTitle = styled.h3`
62+
line-height: 28px;
63+
`;

‎webviews/components/EditButton.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
import EditIcon from 'webviews/assets/edit.svg';
5+
6+
const IconButton = styled.button`
7+
border: unset;
8+
background: unset;
9+
width: 20px;
10+
height: 20px;
11+
margin-left: 1ex;
12+
padding: 2px 0;
13+
vertical-align: middle;
14+
15+
:hover {
16+
cursor: pointer;
17+
}
18+
19+
:focus {
20+
outline: 1px solid var(--vscode-focusBorder);
21+
outline-offset: 2px;
22+
}
23+
24+
svg path {
25+
fill: var(--vscode-foreground);
26+
}
27+
`;
28+
29+
interface Props {
30+
onClick?: () => void;
31+
}
32+
33+
const EditButton = ({ onClick = () => null }: Props) => {
34+
return (
35+
<IconButton onClick={onClick}>
36+
<EditIcon />
37+
</IconButton>
38+
);
39+
};
40+
41+
export default EditButton;

‎webviews/components/Reviewers.tsx

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { view } from '@risingstack/react-easy-state';
44

55
import appStore from 'webviews/store/appStore';
66
import { Avatar, AuthorLink } from 'webviews/components/User';
7-
import EditIcon from 'webviews/assets/edit.svg';
7+
import EditButton from 'webviews/components/EditButton';
88

99
const Title = styled.div`
1010
margin-top: 15px;
@@ -15,36 +15,14 @@ const FlexCenter = styled.div`
1515
display: flex;
1616
align-items: center;
1717
`;
18-
const Item = styled(FlexCenter)`
18+
const Reviewer = styled(FlexCenter)`
1919
padding: 5px 0;
2020
justify-content: space-between;
2121
2222
a:first-child {
2323
margin-right: 5px;
2424
}
2525
`;
26-
const IconButton = styled.button`
27-
border: unset;
28-
background: unset;
29-
width: 20px;
30-
height: 20px;
31-
margin-left: 1ex;
32-
padding: 2px 0;
33-
vertical-align: middle;
34-
35-
:hover {
36-
cursor: pointer;
37-
}
38-
39-
:focus {
40-
outline: 1px solid var(--vscode-focusBorder);
41-
outline-offset: 2px;
42-
}
43-
44-
svg path {
45-
fill: var(--vscode-foreground);
46-
}
47-
`;
4826

4927
function Reviewers() {
5028
const { reviewers, currentMR } = appStore;
@@ -61,19 +39,17 @@ function Reviewers() {
6139
<div>
6240
<Title>
6341
Reviewers
64-
<IconButton onClick={onUpdateReviewer}>
65-
<EditIcon />
66-
</IconButton>
42+
<EditButton onClick={onUpdateReviewer} />
6743
</Title>
6844
{allReviewers.map((r) => {
6945
return (
70-
<Item key={r.reviewer.global_key}>
46+
<Reviewer key={r.reviewer.global_key}>
7147
<FlexCenter>
7248
<Avatar for={r.reviewer} />
7349
<AuthorLink for={r.reviewer} />
7450
</FlexCenter>
7551
{r.value === 100 && `👍`}
76-
</Item>
52+
</Reviewer>
7753
);
7854
})}
7955
</div>

‎webviews/hooks/messageTransferHook.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect } from 'react';
22
import appStore from 'webviews/store/appStore';
33
import { actions } from 'webviews/store/constants';
4+
import { IMRContent } from 'src/typings/respResult';
45

56
export default function messageTransferHook() {
67
useEffect(() => {
@@ -11,6 +12,8 @@ export default function messageTransferHook() {
1112
updateMRReviewers,
1213
updateMRComments,
1314
toggleMRLoading,
15+
updateMRDesc,
16+
toggleUpdatingDesc,
1417
} = appStore;
1518
const { command, res } = ev?.data;
1619

@@ -35,6 +38,12 @@ export default function messageTransferHook() {
3538
res && updateMRReviewers(res);
3639
break;
3740
}
41+
case actions.MR_UPDATE_DESC: {
42+
const [iid, resp] = res as [string, IMRContent];
43+
updateMRDesc(iid, resp);
44+
toggleUpdatingDesc();
45+
break;
46+
}
3847
default:
3948
break;
4049
}

‎webviews/service/mrService.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { vscode } from 'webviews/constants/vscode';
2+
import { actions } from 'webviews/store/constants';
3+
4+
export const requestUpdateMRContent = async (iid: string, content: string) => {
5+
await vscode.postMessage({
6+
command: actions.MR_UPDATE_DESC,
7+
args: [iid, content],
8+
});
9+
};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /