Skip to content

Commit e5d070f

Browse files
authored
AXON-738: preparing the layout for adding functionality (#655)
1 parent a9e4260 commit e5d070f

File tree

10 files changed

+576
-3
lines changed

10 files changed

+576
-3
lines changed

src/analyticsTypes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export enum AnalyticsView {
3939

4040
StartWorkPage = 'page:v2:jira:startWork',
4141

42+
// v3
43+
StartWorkPageV3 = 'page:v3:jira:startWork',
44+
4245
// Reserved for future use
4346

4447
Other = 'other',

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

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,36 @@
1+
import { Box, Button, Typography } from '@material-ui/core';
12
import React from 'react';
3+
import { AnalyticsView } from 'src/analyticsTypes';
4+
5+
import { AtlascodeErrorBoundary } from '../../common/ErrorBoundary';
6+
import { StartWorkControllerContext, useStartWorkController } from '../startWorkController';
7+
import { CreateBranchSection, TaskInfoSection, UpdateStatusSection } from './components';
28

39
const StartWorkPageV3: React.FunctionComponent = () => {
10+
const [state, controller] = useStartWorkController();
11+
412
return (
5-
<div>
6-
<h1>Start Work</h1>
7-
</div>
13+
<StartWorkControllerContext.Provider value={controller}>
14+
<AtlascodeErrorBoundary
15+
context={{ view: AnalyticsView.StartWorkPageV3 }}
16+
postMessageFunc={controller.postMessage}
17+
>
18+
<Box marginTop={7} maxWidth="654px" padding={3} marginX="auto">
19+
<Box marginBottom={2}>
20+
<Typography variant="h3" style={{ fontWeight: 700 }}>
21+
Start work
22+
</Typography>
23+
</Box>
24+
25+
<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>
31+
</Box>
32+
</AtlascodeErrorBoundary>
33+
</StartWorkControllerContext.Provider>
834
);
935
};
1036

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { render, screen } from '@testing-library/react';
2+
import React from 'react';
3+
4+
import { CreateBranchSection } from './CreateBranchSection';
5+
6+
jest.mock('../../../../vscode/theme/styles', () => ({
7+
VSCodeStylesContext: React.createContext({
8+
descriptionForeground: '#666666',
9+
foreground: '#000000',
10+
background: '#ffffff',
11+
}),
12+
}));
13+
14+
const mockController = {
15+
postMessage: jest.fn(),
16+
refresh: jest.fn(),
17+
openLink: jest.fn(),
18+
startWork: jest.fn(),
19+
closePage: jest.fn(),
20+
openJiraIssue: jest.fn(),
21+
openSettings: jest.fn(),
22+
};
23+
24+
const mockState: any = {
25+
issue: {
26+
key: 'TEST-123',
27+
summary: 'Test Issue',
28+
status: {
29+
id: '1',
30+
name: 'To Do',
31+
statusCategory: {
32+
key: 'new',
33+
colorName: 'blue',
34+
},
35+
},
36+
transitions: [],
37+
issuetype: {
38+
name: 'Task',
39+
iconUrl: 'test-icon.png',
40+
},
41+
},
42+
repoData: [],
43+
customTemplate: '{{prefix}}/{{issueKey}}-{{summary}}',
44+
customPrefixes: [],
45+
isSomethingLoading: false,
46+
};
47+
48+
describe('CreateBranchSection', () => {
49+
beforeEach(() => {
50+
jest.clearAllMocks();
51+
});
52+
53+
it('should render "Create branch" title', () => {
54+
render(<CreateBranchSection state={mockState} controller={mockController} />);
55+
56+
expect(screen.getByText('Create branch')).toBeDefined();
57+
});
58+
59+
it('should render "New local branch" label', () => {
60+
render(<CreateBranchSection state={mockState} controller={mockController} />);
61+
62+
expect(screen.getByText('New local branch')).toBeDefined();
63+
});
64+
65+
it('should render "Source branch" label', () => {
66+
render(<CreateBranchSection state={mockState} controller={mockController} />);
67+
68+
expect(screen.getByText('Source branch')).toBeDefined();
69+
});
70+
71+
it('should render "Push the new branch to remote" checkbox', () => {
72+
render(<CreateBranchSection state={mockState} controller={mockController} />);
73+
74+
expect(screen.getByText('Push the new branch to remote')).toBeDefined();
75+
const checkbox = screen.getByRole('checkbox');
76+
expect(checkbox).toBeDefined();
77+
});
78+
79+
it('should render settings button', () => {
80+
render(<CreateBranchSection state={mockState} controller={mockController} />);
81+
82+
const buttons = screen.getAllByRole('button');
83+
expect(buttons.length).toBeGreaterThan(0);
84+
});
85+
86+
it('should render with proper layout structure', () => {
87+
render(<CreateBranchSection state={mockState} controller={mockController} />);
88+
89+
expect(screen.getByText('Create branch')).toBeDefined();
90+
expect(screen.getByText('New local branch')).toBeDefined();
91+
expect(screen.getByText('Source branch')).toBeDefined();
92+
expect(screen.getByText('Push the new branch to remote')).toBeDefined();
93+
});
94+
});
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import {
2+
Box,
3+
Checkbox,
4+
FormControlLabel,
5+
Grid,
6+
IconButton,
7+
makeStyles,
8+
TextField,
9+
Theme,
10+
Typography,
11+
} from '@material-ui/core';
12+
import SettingsIcon from '@material-ui/icons/Settings';
13+
import { Autocomplete } from '@material-ui/lab';
14+
import React, { useContext } from 'react';
15+
16+
import { VSCodeStyles, VSCodeStylesContext } from '../../../../vscode/theme/styles';
17+
import { CreateBranchSectionProps } from '../types';
18+
19+
const useStyles = makeStyles((theme: Theme) => ({
20+
settingsButton: (props: VSCodeStyles) => ({
21+
'& .MuiSvgIcon-root': {
22+
fill: 'none',
23+
stroke: props.descriptionForeground,
24+
strokeWidth: 1.5,
25+
},
26+
}),
27+
}));
28+
29+
export const CreateBranchSection: React.FC<CreateBranchSectionProps> = ({ state, controller }) => {
30+
const vscStyles = useContext(VSCodeStylesContext);
31+
const classes = useStyles(vscStyles);
32+
33+
return (
34+
<Box
35+
border={1}
36+
borderRadius={3}
37+
borderColor="var(--vscode-list-inactiveSelectionBackground)"
38+
padding={3}
39+
marginBottom={2}
40+
>
41+
<Box marginBottom={2}>
42+
<Typography variant="h5" style={{ fontWeight: 700 }}>
43+
Create branch
44+
</Typography>
45+
</Box>
46+
47+
<Grid container spacing={2} direction="column">
48+
<Grid item>
49+
<Typography variant="body2">New local branch</Typography>
50+
<Grid container spacing={1} alignItems="center">
51+
<Grid item xs>
52+
<TextField
53+
fullWidth
54+
size="small"
55+
value="ALT-1156-bb-pr-creation-integration-is-cool-yeah-lets-go"
56+
variant="outlined"
57+
/>
58+
</Grid>
59+
<Grid item>
60+
<IconButton size="small" color="default" className={classes.settingsButton}>
61+
<SettingsIcon fontSize="small" />
62+
</IconButton>
63+
</Grid>
64+
</Grid>
65+
</Grid>
66+
67+
<Grid item xs={9}>
68+
<Typography variant="body2">Source branch</Typography>
69+
<Autocomplete
70+
options={[
71+
'bb-pr-creation-integration-is-cool-yeah-yeah-lets-go',
72+
'main',
73+
'develop',
74+
'feature/new-branch',
75+
]}
76+
value="bb-pr-creation-integration-is-cool-yeah-lets-go"
77+
renderInput={(params) => <TextField {...params} size="small" variant="outlined" fullWidth />}
78+
size="small"
79+
/>
80+
</Grid>
81+
82+
<Grid item>
83+
<FormControlLabel control={<Checkbox defaultChecked />} label="Push the new branch to remote" />
84+
</Grid>
85+
</Grid>
86+
</Box>
87+
);
88+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { render, screen } from '@testing-library/react';
2+
import React from 'react';
3+
4+
import { TaskInfoSection } from './TaskInfoSection';
5+
6+
const mockController = {
7+
postMessage: jest.fn(),
8+
refresh: jest.fn(),
9+
openLink: jest.fn(),
10+
startWork: jest.fn(),
11+
closePage: jest.fn(),
12+
openJiraIssue: jest.fn(),
13+
openSettings: jest.fn(),
14+
};
15+
16+
const mockState: any = {
17+
issue: {
18+
key: 'TEST-123',
19+
summary: 'Test Issue Summary',
20+
status: {
21+
id: '1',
22+
name: 'To Do',
23+
statusCategory: {
24+
key: 'new',
25+
colorName: 'blue',
26+
},
27+
},
28+
transitions: [],
29+
issuetype: {
30+
name: 'Task',
31+
iconUrl: 'test-icon.png',
32+
},
33+
},
34+
repoData: [],
35+
customTemplate: '{{prefix}}/{{issueKey}}-{{summary}}',
36+
customPrefixes: [],
37+
isSomethingLoading: false,
38+
};
39+
40+
describe('TaskInfoSection', () => {
41+
beforeEach(() => {
42+
jest.clearAllMocks();
43+
});
44+
45+
it('should render "For" label', () => {
46+
render(<TaskInfoSection state={mockState} controller={mockController} />);
47+
48+
expect(screen.getByText('For')).toBeDefined();
49+
});
50+
51+
it('should render issue key as link', () => {
52+
render(<TaskInfoSection state={mockState} controller={mockController} />);
53+
54+
const link = screen.getByText('TEST-123');
55+
expect(link).toBeDefined();
56+
});
57+
58+
it('should render issue summary', () => {
59+
render(<TaskInfoSection state={mockState} controller={mockController} />);
60+
61+
expect(screen.getByText('Test Issue Summary')).toBeDefined();
62+
});
63+
64+
it('should render issue type icon', () => {
65+
render(<TaskInfoSection state={mockState} controller={mockController} />);
66+
67+
const icon = screen.getByTitle('Task');
68+
expect(icon).toBeDefined();
69+
});
70+
71+
it('should call openJiraIssue when link is clicked', () => {
72+
render(<TaskInfoSection state={mockState} controller={mockController} />);
73+
74+
const link = screen.getByText('TEST-123');
75+
link.click();
76+
77+
expect(mockController.openJiraIssue).toHaveBeenCalledTimes(1);
78+
});
79+
80+
it('should render with proper layout structure', () => {
81+
render(<TaskInfoSection state={mockState} controller={mockController} />);
82+
83+
expect(screen.getByText('For')).toBeDefined();
84+
expect(screen.getByText('TEST-123')).toBeDefined();
85+
expect(screen.getByText('Test Issue Summary')).toBeDefined();
86+
expect(screen.getByTitle('Task')).toBeDefined();
87+
});
88+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Box, Grid, Link, Typography } from '@material-ui/core';
2+
import React from 'react';
3+
4+
import { TaskInfoSectionProps } from '../types';
5+
6+
export const TaskInfoSection: React.FC<TaskInfoSectionProps> = ({ state, controller }) => {
7+
return (
8+
<Box marginBottom={2}>
9+
<Grid container alignItems="center" spacing={1}>
10+
<Grid item>
11+
<Grid container alignItems="center" spacing={1} wrap="nowrap">
12+
<Grid item>
13+
<Typography variant="h5">For</Typography>
14+
</Grid>
15+
<Grid item>
16+
<Box
17+
border={1}
18+
borderRadius={3}
19+
padding={0.5}
20+
borderColor={'var(--vscode-list-inactiveSelectionBackground)'}
21+
>
22+
<Grid container alignItems="center" spacing={1} wrap="nowrap">
23+
<Grid item>
24+
<Box
25+
width="14px"
26+
height="14px"
27+
style={{
28+
backgroundImage: `url(${state.issue.issuetype.iconUrl})`,
29+
backgroundSize: 'contain',
30+
}}
31+
title={state.issue.issuetype.name}
32+
/>
33+
</Grid>
34+
<Grid item>
35+
<Typography variant="h5">
36+
<Link onClick={controller.openJiraIssue} style={{ cursor: 'pointer' }}>
37+
{state.issue.key}
38+
</Link>
39+
</Typography>
40+
</Grid>
41+
<Grid item>
42+
<Typography variant="h5">{state.issue.summary}</Typography>
43+
</Grid>
44+
</Grid>
45+
</Box>
46+
</Grid>
47+
</Grid>
48+
</Grid>
49+
</Grid>
50+
</Box>
51+
);
52+
};

0 commit comments

Comments
 (0)