Skip to content

Commit

Permalink
Merge pull request #216 from atlassian/ARC-2729-add-images-and-update…
Browse files Browse the repository at this point in the history
…-content

ARC-2729 add images and update content
  • Loading branch information
rachellerathbone authored Dec 11, 2023
2 parents 6523db2 + d90a139 commit 567b6c5
Show file tree
Hide file tree
Showing 14 changed files with 496 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,23 +107,22 @@ export const notConnectedSpinnerContainer = css`
width: 100%;
`;

// TODO - delete this temp class
export const notConnectedTempImgPlaceholder = css`
background-color: lightgrey;
border: 1px solid lightgrey;
border-radius: 3px;
height: 160px;
margin: auto;
width: 160px;
export const connectionPanelContainerContainer = css`
margin: ${token('space.600')} auto;
max-height: 400px;
min-height: 400px;
max-width: 420px;
position: relative;
text-align: center;
`;

export const notConnectedStateHeader = css`
export const connectionPanelContainerHeader = css`
font-size: 20px;
font-weight: 500;
margin: ${token('space.200')} auto;
`;

export const notConnectedStateParagraph = css`
export const connectionPanelContainerParagraph = css`
font-size: 14px;
line-height: 20px;
margin-bottom: ${token('space.400')};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import {
act,
fireEvent,
render,
screen,
Expand Down Expand Up @@ -105,6 +106,12 @@ const servers: JenkinsServer[] = [
lastUpdatedOn: new Date()
},
pipelines: []
},
{
name: 'server eight',
uuid: '56046af9-d0eb-4efb-8896-iwer23rjesu',
pluginConfig: undefined,
pipelines: []
}
];

Expand Down Expand Up @@ -133,37 +140,38 @@ describe('Connection Panel Suite', () => {
expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED);
});

it('should correctly set state for two servers with different IPs', () => {
const twoServers: JenkinsServer[] = [servers[0], servers[1]];
const result = addConnectedState(twoServers);

expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED);
expect(result[1].connectedState).toEqual(ConnectedState.PENDING);
});

it('should correctly set state for multiple servers with duplicate IPs', () => {
const multipleServers: JenkinsServer[] = [servers[0], servers[2], servers[3]];
const result = addConnectedState(multipleServers);
const multipleServers: JenkinsServer[] = [servers[0], servers[2], servers[3], servers[7]];
const results = addConnectedState(multipleServers);

expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED);
expect(result[1].connectedState).toEqual(ConnectedState.CONNECTED);
expect(result[2].connectedState).toEqual(ConnectedState.DUPLICATE);
expect(results[0].connectedState).toEqual(ConnectedState.CONNECTED);
expect(results[1].connectedState).toEqual(ConnectedState.CONNECTED);
expect(results[2].connectedState).toEqual(ConnectedState.DUPLICATE);
expect(results[3].connectedState).toEqual(ConnectedState.PENDING);
});

it('should handle servers with no pluginConfig', () => {
const noPluginConfig: JenkinsServer[] = [servers[4]];
const result = addConnectedState(noPluginConfig);
it('should handle servers with missing data', () => {
const noPluginConfigAndNoPipelines: JenkinsServer[] = [servers[7]];
const noPluginConfigButHasPipelines: JenkinsServer[] = [servers[4]];
const hasPluginConfigButNoPipelines: JenkinsServer[] = [servers[6]];

const noPluginConfigAndNoPipelinesResult = addConnectedState(noPluginConfigAndNoPipelines);
const noPluginConfigButHasPipelinesResult = addConnectedState(noPluginConfigButHasPipelines);
const hasPluginConfigButNoPipelinesResult = addConnectedState(hasPluginConfigButNoPipelines);

expect(result[0].connectedState).toEqual(ConnectedState.PENDING);
expect(noPluginConfigButHasPipelinesResult[0].connectedState).toEqual(ConnectedState.CONNECTED);
expect(noPluginConfigAndNoPipelinesResult[0].connectedState).toEqual(ConnectedState.PENDING);
expect(hasPluginConfigButNoPipelinesResult[0].connectedState).toEqual(ConnectedState.CONNECTED);
});

it('should correctly set state for multiple servers with duplicate IPs and no pipelines', () => {
const duplicateServers: JenkinsServer[] = [servers[1], servers[5], servers[6]];
const result = addConnectedState(duplicateServers);

expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED);
expect(result[1].connectedState).toEqual(ConnectedState.PENDING);
expect(result[1].connectedState).toEqual(ConnectedState.CONNECTED);
expect(result[2].connectedState).toEqual(ConnectedState.DUPLICATE);
expect(result[2].originalConnection).toEqual(servers[5].name);
});
});

Expand Down Expand Up @@ -241,14 +249,7 @@ describe('Connection Panel Suite', () => {
const server: JenkinsServer = {
name: 'my server',
connectedState: ConnectedState.PENDING,
pluginConfig: {
ipAddress: '10.0.0.1',
lastUpdatedOn: new Date(),
autoBuildRegex: '',
autoBuildEnabled: true,
autoDeploymentsEnabled: false,
autoDeploymentsRegex: ''
},
pluginConfig: undefined,
uuid: 'djsnfudin-jhsdwefwe-238hnfuwef',
pipelines: []
};
Expand All @@ -261,11 +262,11 @@ describe('Connection Panel Suite', () => {
);

const nameLabel = screen.getByText(server.name);
const ipAddressLabel = screen.getByText(`IP address: ${server.pluginConfig?.ipAddress}`);
const ipAddressLabel = screen.queryByText(`IP address: ${server.pluginConfig?.ipAddress}`);
const statusLabel = screen.getByTestId('status-label');

expect(nameLabel).toBeInTheDocument();
expect(ipAddressLabel).toBeInTheDocument();
expect(ipAddressLabel).not.toBeInTheDocument();
expect(statusLabel).toHaveStyle({ color: '#a54900', backgroundColor: '#fff7d6' });
expect(statusLabel).toHaveTextContent('PENDING');
});
Expand Down Expand Up @@ -299,7 +300,8 @@ describe('Connection Panel Suite', () => {
// TODO - add test for Rename - will be done when I build the new server name screen

// TODO - add test for Connection settings - will be done when I build the new set up Jenkins screen
test('should handle server disconnection and refreshing correctly', async () => {

test('should handle server disconnection and refreshing servers correctly', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce(servers);

render(<ConnectionPanel />);
Expand All @@ -323,6 +325,53 @@ describe('Connection Panel Suite', () => {
});

describe('Connection Panel Main', () => {
test('should render panel content for PENDING server', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[7]]);

render(<ConnectionPanel />);

await waitFor(() => {
expect(screen.getByText('Connection pending')).toBeInTheDocument();
});
});

test('should render panel content for DUPLICATE server', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[5], servers[6]]);

render(<ConnectionPanel />);

await waitFor(() => {
expect(screen.getByText('Duplicate server')).toBeInTheDocument();
});
});

test('should render panel content for CONNECTED server without pipeline data', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[1]]);

await act(async () => {
render(<ConnectionPanel />);
await waitFor(() => {
expect(screen.getByText('No data received')).toBeInTheDocument();
expect(screen.queryByText('Pipeline')).not.toBeInTheDocument();
expect(screen.queryByText('Event')).not.toBeInTheDocument();
expect(screen.queryByText('Received')).not.toBeInTheDocument();
});
});
});

test('should render panel content for CONNECTED server with pipeline data', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[5]]);

render(<ConnectionPanel />);

await waitFor(() => {
expect(screen.queryByText('No data received')).not.toBeInTheDocument();
expect(screen.getByText('Pipeline')).toBeInTheDocument();
expect(screen.getByText('Event')).toBeInTheDocument();
expect(screen.getByText('Received')).toBeInTheDocument();
});
});

test('should handle server deletion correctly for DUPLICATE SERVERS', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce(servers);

Expand Down Expand Up @@ -403,7 +452,6 @@ describe('Connection Panel Suite', () => {

await waitFor(() => {
expect(screen.getByText(server.name)).toBeInTheDocument();

fireEvent.click(screen.getByText('Set up guide'));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,32 @@ export const addConnectedState = (servers: JenkinsServer[]): JenkinsServer[] =>
return servers
.slice() // Create a shallow copy to avoid mutating the original array
.sort((a, b) => b.pipelines.length - a.pipelines.length)
.map((server: JenkinsServer) => {
.map((server: JenkinsServer, index, array) => {
const ipAddress = server.pluginConfig?.ipAddress;
let connectedState = ConnectedState.PENDING;
let originalConnection: string | undefined;

if (ipAddress && ipAddressSet.has(ipAddress)) {
connectedState = ConnectedState.DUPLICATE;
} else if (server.pipelines.length > 0 && ipAddress) {

// Find the original connection with the same IP address
const originalServer = array.find(
(s) => s !== server && s.pluginConfig?.ipAddress === ipAddress &&
s.connectedState !== ConnectedState.DUPLICATE
);

if (originalServer) {
originalConnection = originalServer.name;
}
} else if (server.pluginConfig || server.pipelines.length) {
connectedState = ConnectedState.CONNECTED;
ipAddressSet.add(ipAddress);
if (ipAddress) ipAddressSet.add(ipAddress);
}

return {
...server,
connectedState
connectedState,
originalConnection
};
});
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import { cx } from '@emotion/css';
import Button, { Appearance, ButtonGroup } from '@atlaskit/button';
import { ConnectedState } from '../StatusLabel/StatusLabel';
import {
connectionPanelContainerContainer,
connectionPanelContainerHeader,
connectionPanelContainerParagraph
} from './ConnectionPanel.styles';
import { ConnectionPendingIcon } from '../icons/ConnectionPendingIcon';
import { NoDataIcon } from '../icons/NoDataIcon';
import { DuplicateServerIcon } from '../icons/DuplicateServerIcon';

type NotConnectedStateProps = {
connectedState: ConnectedState;
contentHeader: string,
contentInstructionOne: string,
contentInstructionTwo?: string,
buttonAppearance: Appearance,
firstButtonLabel: string,
secondButtonLabel?: string,
buttonOneOnClick(data?: any): void,
buttonTwoOnClick?(): void,
testId?: string
};

const ConnectionPanelContent = ({
connectedState,
contentHeader,
contentInstructionOne,
contentInstructionTwo,
buttonAppearance,
firstButtonLabel,
secondButtonLabel,
buttonOneOnClick,
buttonTwoOnClick,
testId
}: NotConnectedStateProps): JSX.Element => {
let icon;

if (connectedState === ConnectedState.CONNECTED) {
icon = <NoDataIcon />;
} else if (connectedState === ConnectedState.PENDING) {
icon = <ConnectionPendingIcon />;
} else {
icon = <DuplicateServerIcon />;
}

return (
<div className={cx(connectionPanelContainerContainer)}>
{icon}
<h3 className={cx(connectionPanelContainerHeader)}>{contentHeader}</h3>
<p className={cx(connectionPanelContainerParagraph)}>{contentInstructionOne}</p>
<p className={cx(connectionPanelContainerParagraph)}>{contentInstructionTwo}</p>
<ButtonGroup>
<Button
appearance={buttonAppearance}
onClick={buttonOneOnClick}
testId={testId}
>
{firstButtonLabel}
</Button>
{
secondButtonLabel
? <Button onClick={buttonTwoOnClick}>{secondButtonLabel}</Button>
: <></>
}
</ButtonGroup>
</div>
);
};

export { ConnectionPanelContent };
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactNode } from 'react';
import React, { ReactNode, useState } from 'react';
import { cx } from '@emotion/css';
import Tabs, { Tab, TabList, TabPanel } from '@atlaskit/tabs';
import {
Expand All @@ -13,6 +13,7 @@ import { NotConnectedState } from './NotConnectedState';
import { JenkinsServer } from '../../../../src/common/types';
import { ConnectedJenkinsServers } from './ConnectedJenkinsServers';
import { SetUpGuide, UpdateAvailable } from './SetUpGuide';
import { ConnectionPanelContent } from './ConnectionPanelContent';

type PanelProps = {
children: ReactNode,
Expand Down Expand Up @@ -52,6 +53,20 @@ const ConnectionPanelMain = ({
jenkinsServer,
refreshServers
}: ConnectionPanelMainProps): JSX.Element => {
const [selectedTabIndex, setSelectedTabIndex] = useState(0);

const handleClickSetupGuide = () => {
setSelectedTabIndex(1);
};

const handleTabSelect = (index: number) => {
setSelectedTabIndex(index);
};

const handleRefreshPanel = () => {
// TODO - ARC-2738 refresh functionality
};

return (
<div className={cx(connectionPanelMainContainer)}>
{
Expand All @@ -60,8 +75,9 @@ const ConnectionPanelMain = ({
connectedState={connectedState}
jenkinsServer={jenkinsServer}
refreshServers={refreshServers}
handleRefreshPanel={handleRefreshPanel}
/>
: <Tabs id="connection-panel-tabs">
: <Tabs id="connection-panel-tabs" selected={selectedTabIndex} onChange={handleTabSelect}>
<TabList>
{
connectedState === ConnectedState.PENDING
Expand All @@ -79,13 +95,28 @@ const ConnectionPanelMain = ({
{
connectedState === ConnectedState.CONNECTED
? <Panel connectedState={connectedState} data-testid="connectedServersPanel">
<ConnectedJenkinsServers connectedJenkinsServer={jenkinsServer} />
{
jenkinsServer.pipelines.length
? <ConnectedJenkinsServers connectedJenkinsServer={jenkinsServer} />
: <ConnectionPanelContent
connectedState={connectedState}
contentHeader="No data received"
contentInstructionOne="This server is connected but hasn't sent any data to Jira yet."
contentInstructionTwo="Use this server's set up guide to choose what data this server sends to Jira."
buttonAppearance="primary"
firstButtonLabel="Open set up guide"
secondButtonLabel="Refresh"
buttonOneOnClick={handleClickSetupGuide}
buttonTwoOnClick={handleRefreshPanel}
/>
}
</Panel>
: <Panel data-testid="notConnectedPanel">
<NotConnectedState
connectedState={connectedState}
jenkinsServer={jenkinsServer}
refreshServers={refreshServers}
handleRefreshPanel={handleRefreshPanel}
/>
</Panel>
}
Expand Down
Loading

0 comments on commit 567b6c5

Please sign in to comment.