Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARC-2723 add share modal #220

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/jenkins-for-jira-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@atlaskit/progress-tracker": "8.5.2",
"@atlaskit/spinner": "15.5.3",
"@atlaskit/tabs": "^13.4.9",
"@atlaskit/textarea": "^5.0.0",
"@atlaskit/textfield": "5.6.4",
"@atlaskit/theme": "12.5.5",
"@atlaskit/tokens": "^1.28.1",
Expand All @@ -36,6 +37,7 @@
"@types/react-dom": "17.0.20",
"@types/react-router": "5.1.20",
"@types/uuid": "8.3.4",
"algoliasearch": "^4.20.0",
"eslint-plugin-react-hooks": "4.6.0",
"launchdarkly-react-client-sdk": "^3.0.8",
"moment": "2.29.4",
Expand Down
22 changes: 22 additions & 0 deletions app/jenkins-for-jira-ui/src/api/fetchGlobalPageUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { invoke } from '@forge/bridge';

type FetchGlobalPageUrlContext = {
siteUrl: string;
appId: string;
environmentId: string;
};

const fetchGlobalPageUrl = async (): Promise<string> => {
const context: FetchGlobalPageUrlContext = await invoke('fetchAppData');
const {
siteUrl,
appId,
environmentId
} = context;

return `${siteUrl}/jira/apps/${appId}/${environmentId}`;
};

export {
fetchGlobalPageUrl
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('redirectFromGetStarted', () => {

(invoke as jest.Mock).mockResolvedValue(contextData);
await redirectFromGetStarted();
expect(invoke).toHaveBeenCalledWith('redirectFromGetStarted');
expect(invoke).toHaveBeenCalledWith('fetchAppData');
expect(router.navigate).toHaveBeenCalledWith(
`${contextData.siteUrl}/jira/settings/apps/${contextData.appId}/${contextData.environmentId}/`
);
Expand All @@ -33,7 +33,7 @@ describe('redirectFromGetStarted', () => {

(invoke as jest.Mock).mockResolvedValue(contextData);
await redirectFromGetStarted();
expect(invoke).toHaveBeenCalledWith('redirectFromGetStarted');
expect(invoke).toHaveBeenCalledWith('fetchAppData');
expect(router.navigate).not.toHaveBeenCalledWith(
`${contextData.siteUrl}/jira/settings/apps/${contextData.appId}/${contextData.environmentId}/`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Context {
}

const redirectFromGetStarted = async (): Promise<string> => {
const context: Context = await invoke('redirectFromGetStarted');
const context: Context = await invoke('fetchAppData');
const {
siteUrl,
appId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,6 @@ export const setUpGuideOrderListItemHeader = css`
margin-bottom: ${token('space.200')};
`;

export const setUpGuideLink = css`
background-color: inherit;
border: none;
color: ${token('color.link')};
padding: ${token('space.0')}
`;

export const setUpGuideInfoPanel = css`
background-color: #F7F8F9;
display: flex;
Expand All @@ -265,6 +258,13 @@ export const setUpGuideUpdateAvailableContainer = css`
width: 55%;
`;

export const setUpGuideUpdateAvailableLoadingContainer = css`
margin-top: ${token('space.1000')};
padding: ${token('space.1000')};
min-height: 180px;
text-align: center;
`;

export const setUpGuideUpdateAvailableIconContainer = css`
margin: ${token('space.0')} auto;
text-align: center;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React from 'react';
import {
act,
fireEvent,
render,
screen,
waitFor
act, fireEvent, render, screen, waitFor
} from '@testing-library/react';
import { ConnectionPanelTop } from './ConnectionPanelTop';
import { ConnectedState } from '../StatusLabel/StatusLabel';
import { addConnectedState, ConnectionPanel } from './ConnectionPanel';
import { EventType, JenkinsServer } from '../../../../src/common/types';
import * as getAllJenkinsServersModule from '../../api/getAllJenkinsServers';
import { ConnectionPanelMain } from './ConnectionPanelMain';

const servers: JenkinsServer[] = [
{
Expand Down Expand Up @@ -324,7 +321,7 @@ describe('Connection Panel Suite', () => {
});
});

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

Expand All @@ -338,7 +335,7 @@ describe('Connection Panel Suite', () => {
test('should render panel content for DUPLICATE server', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[5], servers[6]]);

render(<ConnectionPanel />);
render(<ConnectionPanel/>);

await waitFor(() => {
expect(screen.getByText('Duplicate server')).toBeInTheDocument();
Expand All @@ -348,8 +345,9 @@ describe('Connection Panel Suite', () => {
test('should render panel content for CONNECTED server without pipeline data', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[1]]);

render(<ConnectionPanel />);

await act(async () => {
render(<ConnectionPanel />);
await waitFor(() => {
expect(screen.getByText('No data received')).toBeInTheDocument();
expect(screen.queryByText('Pipeline')).not.toBeInTheDocument();
Expand Down Expand Up @@ -461,6 +459,56 @@ describe('Connection Panel Suite', () => {
expect(updateAvailableText).toBeInTheDocument();
});
});

test('should handle refreshing the panel for a server CONNECTED with pipeline data but no plugin config', async () => {
jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([servers[4]]);

const { rerender } = render(<ConnectionPanel />);

await waitFor(() => {
expect(screen.getByText('CONNECTED')).toBeInTheDocument();
expect(screen.getByText('Pipeline')).toBeInTheDocument();
expect(screen.getByText('Event')).toBeInTheDocument();
expect(screen.getByText('Received')).toBeInTheDocument();
expect(screen.queryByText('Refresh')).not.toBeInTheDocument();
expect(screen.queryByText('To receive build and deployment data from this server:')).not.toBeInTheDocument();
});

await waitFor(() => {
fireEvent.click(screen.getByText('Set up guide'));
});

await waitFor(() => {
expect(screen.getByText('Refresh')).toBeInTheDocument();
expect(screen.queryByText('To receive build and deployment data from this server:')).not.toBeInTheDocument();

const updatedServerData = {
...servers[1],
pluginConfig: {
ipAddress: '10.10.10.12',
lastUpdatedOn: new Date()
}
};

jest.spyOn(getAllJenkinsServersModule, 'getAllJenkinsServers').mockResolvedValueOnce([updatedServerData]);

// Rerender the component with the updated data
rerender(<ConnectionPanelMain
connectedState={ConnectedState.CONNECTED}
jenkinsServer={updatedServerData}
refreshServers={jest.fn()}
/>);
});

await waitFor(() => {
fireEvent.click(screen.getByText('Set up guide'));
});

await waitFor(() => {
fireEvent.click(screen.getByText('Refresh'));
expect(screen.getByText('To receive build and deployment data from this server:')).toBeInTheDocument();
});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import { cx } from '@emotion/css';
import Button, { Appearance, ButtonGroup } from '@atlaskit/button';
import Spinner from '@atlaskit/spinner';
import { ConnectedState } from '../StatusLabel/StatusLabel';
import {
connectionPanelContainerContainer,
connectionPanelContainerHeader,
connectionPanelContainerParagraph
connectionPanelContainerParagraph,
notConnectedSpinnerContainer
} from './ConnectionPanel.styles';
import { ConnectionPendingIcon } from '../icons/ConnectionPendingIcon';
import { NoDataIcon } from '../icons/NoDataIcon';
Expand All @@ -21,7 +23,8 @@ type NotConnectedStateProps = {
secondButtonLabel?: string,
buttonOneOnClick(data?: any): void,
buttonTwoOnClick?(): void,
testId?: string
testId?: string,
isLoading: boolean
};

const ConnectionPanelContent = ({
Expand All @@ -34,7 +37,8 @@ const ConnectionPanelContent = ({
secondButtonLabel,
buttonOneOnClick,
buttonTwoOnClick,
testId
testId,
isLoading
}: NotConnectedStateProps): JSX.Element => {
let icon;

Expand All @@ -48,24 +52,32 @@ const ConnectionPanelContent = ({

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>
{
isLoading
? <div className={cx(notConnectedSpinnerContainer)}>
<Spinner size='large' />
</div>
: <>
{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>
);
};
Expand Down
Loading