Skip to content

Commit 15d58e5

Browse files
committed
AXON-762: moving functionality to a new page
1 parent df643ba commit 15d58e5

18 files changed

+1233
-154
lines changed

src/react/atlascode/startwork/v3/StartWorkPageV3.tsx

Lines changed: 211 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,187 @@
1-
import { Box, Button, Typography } from '@material-ui/core';
2-
import React from 'react';
1+
import { emptyTransition, Transition } from '@atlassianlabs/jira-pi-common-models';
2+
import { Box, Button, CircularProgress, Typography } from '@material-ui/core';
3+
import React, { useCallback, useEffect, useState } from 'react';
34
import { AnalyticsView } from 'src/analyticsTypes';
45

6+
import { StartWorkActionType } from '../../../../lib/ipc/fromUI/startWork';
7+
import { RepoData } from '../../../../lib/ipc/toUI/startWork';
8+
import { Branch } from '../../../../typings/git';
59
import { AtlascodeErrorBoundary } from '../../common/ErrorBoundary';
610
import { StartWorkControllerContext, useStartWorkController } from '../startWorkController';
7-
import { CreateBranchSection, TaskInfoSection, UpdateStatusSection } from './components';
11+
import { CreateBranchSection, SuccessAlert, TaskInfoSection, UpdateStatusSection } from './components';
12+
import { generateBranchName, getDefaultSourceBranch } from './utils/branchUtils';
813

914
const StartWorkPageV3: React.FunctionComponent = () => {
1015
const [state, controller] = useStartWorkController();
16+
const [pushBranchEnabled, setPushBranchEnabled] = useState(true);
17+
const [localBranch, setLocalBranch] = useState('');
18+
const [sourceBranch, setSourceBranch] = useState<Branch>({ type: 0, name: '' });
19+
const [selectedRepository, setSelectedRepository] = useState<RepoData | undefined>(state.repoData[0]);
20+
const [selectedBranchType, setSelectedBranchType] = useState<{ kind: string; prefix: string }>({
21+
kind: '',
22+
prefix: '',
23+
});
24+
const [upstream, setUpstream] = useState('');
25+
const [transitionIssueEnabled, setTransitionIssueEnabled] = useState(true);
26+
const [selectedTransition, setSelectedTransition] = useState<Transition>(emptyTransition);
27+
const [branchSetupEnabled, setBranchSetupEnabled] = useState(true);
28+
const [submitState, setSubmitState] = useState<'initial' | 'submitting' | 'submit-success'>('initial');
29+
const [submitResponse, setSubmitResponse] = useState<{
30+
transistionStatus?: string;
31+
branch?: string;
32+
upstream?: string;
33+
}>({});
34+
35+
// Initialize form with default values
36+
useEffect(() => {
37+
if (state.repoData.length > 0) {
38+
const defaultRepo = state.repoData[0];
39+
setSelectedRepository(defaultRepo);
40+
const defaultSourceBranch = getDefaultSourceBranch(defaultRepo);
41+
setSourceBranch(defaultSourceBranch);
42+
43+
// Set default branch type
44+
if (defaultRepo.branchTypes && defaultRepo.branchTypes.length > 0) {
45+
setSelectedBranchType(defaultRepo.branchTypes[0]);
46+
}
47+
48+
// Set default upstream
49+
setUpstream(defaultRepo.workspaceRepo.mainSiteRemote.remote.name);
50+
}
51+
}, [state.repoData]);
52+
53+
// Generate branch name when dependencies change
54+
useEffect(() => {
55+
if (selectedRepository && selectedBranchType.prefix) {
56+
const generatedName = generateBranchName(
57+
selectedRepository,
58+
selectedBranchType,
59+
state.issue,
60+
state.customTemplate,
61+
);
62+
setLocalBranch(generatedName);
63+
}
64+
}, [selectedRepository, selectedBranchType, state.issue, state.customTemplate]);
65+
66+
const handleRepositoryChange = useCallback((repository: RepoData) => {
67+
setSelectedRepository(repository);
68+
const defaultSourceBranch = getDefaultSourceBranch(repository);
69+
setSourceBranch(defaultSourceBranch);
70+
71+
// Set default branch type for new repository
72+
if (repository.branchTypes && repository.branchTypes.length > 0) {
73+
setSelectedBranchType(repository.branchTypes[0]);
74+
}
75+
76+
// Set default upstream for new repository
77+
setUpstream(repository.workspaceRepo.mainSiteRemote.remote.name);
78+
}, []);
79+
80+
const handleBranchTypeChange = useCallback((branchType: { kind: string; prefix: string }) => {
81+
setSelectedBranchType(branchType);
82+
}, []);
83+
84+
const handleUpstreamChange = useCallback((newUpstream: string) => {
85+
setUpstream(newUpstream);
86+
}, []);
87+
88+
const handleTransitionIssueEnabledChange = useCallback((enabled: boolean) => {
89+
setTransitionIssueEnabled(enabled);
90+
}, []);
91+
92+
const handleSelectedTransitionChange = useCallback((transition: Transition) => {
93+
setSelectedTransition(transition);
94+
}, []);
95+
96+
const handleBranchSetupEnabledChange = useCallback((enabled: boolean) => {
97+
setBranchSetupEnabled(enabled);
98+
}, []);
99+
100+
const handleCreateBranch = useCallback(async () => {
101+
setSubmitState('submitting');
102+
103+
try {
104+
console.log('Form data:', {
105+
transitionIssueEnabled,
106+
selectedTransition,
107+
branchSetupEnabled,
108+
pushBranchEnabled,
109+
localBranch,
110+
sourceBranch,
111+
selectedRepository,
112+
selectedBranchType,
113+
upstream,
114+
});
115+
116+
// TODO: Replace with actual API call
117+
if (!selectedRepository) {
118+
throw new Error('No repository selected');
119+
}
120+
121+
const response = await controller.startWork(
122+
transitionIssueEnabled,
123+
selectedTransition,
124+
branchSetupEnabled,
125+
selectedRepository.workspaceRepo,
126+
sourceBranch,
127+
localBranch,
128+
upstream,
129+
pushBranchEnabled,
130+
);
131+
132+
// Send message to refresh tree views after successful start work
133+
controller.postMessage({
134+
type: StartWorkActionType.RefreshTreeViews,
135+
});
136+
137+
setSubmitResponse(response);
138+
setSubmitState('submit-success');
139+
} catch (error) {
140+
console.error('Error creating branch:', error);
141+
setSubmitState('initial');
142+
}
143+
}, [
144+
controller,
145+
transitionIssueEnabled,
146+
selectedTransition,
147+
branchSetupEnabled,
148+
pushBranchEnabled,
149+
localBranch,
150+
sourceBranch,
151+
selectedRepository,
152+
selectedBranchType,
153+
upstream,
154+
]);
155+
156+
const formState = {
157+
pushBranchEnabled,
158+
localBranch,
159+
sourceBranch,
160+
selectedRepository,
161+
selectedBranchType,
162+
upstream,
163+
branchSetupEnabled,
164+
};
165+
166+
const formActions = {
167+
onPushBranchChange: setPushBranchEnabled,
168+
onLocalBranchChange: setLocalBranch,
169+
onSourceBranchChange: setSourceBranch,
170+
onRepositoryChange: handleRepositoryChange,
171+
onBranchTypeChange: handleBranchTypeChange,
172+
onUpstreamChange: handleUpstreamChange,
173+
onBranchSetupEnabledChange: handleBranchSetupEnabledChange,
174+
};
175+
176+
const updateStatusFormState = {
177+
transitionIssueEnabled,
178+
selectedTransition,
179+
};
180+
181+
const updateStatusFormActions = {
182+
onTransitionIssueEnabledChange: handleTransitionIssueEnabledChange,
183+
onSelectedTransitionChange: handleSelectedTransitionChange,
184+
};
11185

12186
return (
13187
<StartWorkControllerContext.Provider value={controller}>
@@ -22,12 +196,41 @@ const StartWorkPageV3: React.FunctionComponent = () => {
22196
</Typography>
23197
</Box>
24198

199+
{submitState === 'submit-success' && <SuccessAlert submitResponse={submitResponse} />}
200+
25201
<TaskInfoSection state={state} controller={controller} />
26-
<CreateBranchSection state={state} controller={controller} />
27-
<UpdateStatusSection state={state} controller={controller} />
28-
<Button variant="contained" color="primary">
29-
Create branch
30-
</Button>
202+
<CreateBranchSection
203+
state={state}
204+
controller={controller}
205+
formState={formState}
206+
formActions={formActions}
207+
/>
208+
<UpdateStatusSection
209+
state={state}
210+
controller={controller}
211+
formState={updateStatusFormState}
212+
formActions={updateStatusFormActions}
213+
/>
214+
215+
{submitState !== 'submit-success' && (
216+
<Button
217+
variant="contained"
218+
color="primary"
219+
disabled={submitState === 'submitting'}
220+
onClick={handleCreateBranch}
221+
endIcon={
222+
submitState === 'submitting' ? <CircularProgress color="inherit" size={20} /> : null
223+
}
224+
>
225+
Create branch
226+
</Button>
227+
)}
228+
229+
{submitState === 'submit-success' && (
230+
<Button variant="contained" color="default" onClick={controller.closePage}>
231+
Close
232+
</Button>
233+
)}
31234
</Box>
32235
</AtlascodeErrorBoundary>
33236
</StartWorkControllerContext.Provider>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Grid, TextField, Typography } from '@material-ui/core';
2+
import { Autocomplete } from '@material-ui/lab';
3+
import React, { useCallback } from 'react';
4+
5+
import { RepoData } from '../../../../../lib/ipc/toUI/startWork';
6+
7+
interface BranchPrefixSelectorProps {
8+
selectedRepository: RepoData | undefined;
9+
selectedBranchType: { kind: string; prefix: string };
10+
customPrefixes: string[];
11+
onBranchTypeChange: (branchType: { kind: string; prefix: string }) => void;
12+
}
13+
14+
export const BranchPrefixSelector: React.FC<BranchPrefixSelectorProps> = ({
15+
selectedRepository,
16+
selectedBranchType,
17+
customPrefixes,
18+
onBranchTypeChange,
19+
}) => {
20+
// Convert custom prefixes to branch types format
21+
const convertedCustomPrefixes = customPrefixes.map((prefix) => {
22+
const normalizedCustomPrefix = prefix.endsWith('/') ? prefix : prefix + '/';
23+
return { prefix: normalizedCustomPrefix, kind: prefix };
24+
});
25+
26+
const handleBranchTypeChange = useCallback(
27+
(event: React.ChangeEvent<{}>, value: { kind: string; prefix: string } | null) => {
28+
if (value) {
29+
onBranchTypeChange(value);
30+
}
31+
},
32+
[onBranchTypeChange],
33+
);
34+
35+
const hasOptions = (selectedRepository?.branchTypes?.length || 0) > 0 || convertedCustomPrefixes.length > 0;
36+
37+
// Don't render if no options available
38+
if (!hasOptions) {
39+
return null;
40+
}
41+
42+
return (
43+
<Grid item xs={6}>
44+
<Typography variant="body2">Branch prefix</Typography>
45+
<Autocomplete
46+
options={[...(selectedRepository?.branchTypes || []), ...convertedCustomPrefixes]}
47+
groupBy={(option) =>
48+
(selectedRepository?.branchTypes || []).map((type) => type.kind).includes(option.kind)
49+
? 'Repo Branch Type'
50+
: 'Custom Prefix'
51+
}
52+
getOptionLabel={(option) => option.kind}
53+
renderInput={(params) => <TextField {...params} size="small" variant="outlined" fullWidth />}
54+
size="small"
55+
disableClearable
56+
value={selectedBranchType}
57+
onChange={handleBranchTypeChange}
58+
/>
59+
</Grid>
60+
);
61+
};

0 commit comments

Comments
 (0)