Skip to content

Commit

Permalink
fix: notes
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Oseen committed Sep 26, 2023
1 parent 89bab66 commit 9335722
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 135 deletions.
4 changes: 3 additions & 1 deletion src/components/common/DockerNetworkName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ type Status = '' | 'warning' | 'error' | undefined;

interface Props {
name: string;
defaultValue?: string;
validateCallback?: (value: boolean) => void;
}

const DockerNetworkName: React.FC<Props> = ({ name, validateCallback }) => {
const DockerNetworkName: React.FC<Props> = ({ name, defaultValue, validateCallback }) => {
const { l } = usePrefixedTranslation('cmps.common.form.DockerNetworkName');

const { getExternalDockerNetworks } = useStoreActions(s => s.network);
Expand Down Expand Up @@ -67,6 +68,7 @@ const DockerNetworkName: React.FC<Props> = ({ name, validateCallback }) => {
}
onChange={validateNetworkName}
status={status}
defaultValue={defaultValue}
/>
</Form.Item>
);
Expand Down
50 changes: 17 additions & 33 deletions src/components/common/StatusBadge.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,39 @@
import React from 'react';
import { Status } from 'shared/types';
import { renderWithProviders } from 'utils/tests';
import StatusBadge from './StatusBadge';
import StatusTag from './StatusTag';

describe('StatusTag Component', () => {
const renderComponent = (status: Status, text?: string) => {
return renderWithProviders(<StatusBadge status={status} text={text} />);
const renderComponent = (status: Status) => {
const result = renderWithProviders(<StatusTag status={status} />);
return {
...result,
dot: result.container.querySelector('.ant-tag'),
};
};

it('should render the Starting status', () => {
const { container } = renderComponent(Status.Starting);
const element = container.querySelector(
'.ant-badge-status-dot.ant-badge-status-processing',
);

expect(element).not.toBeNull();
const { dot } = renderComponent(Status.Starting);
expect(dot).toHaveClass('ant-tag-blue');
});

it('should render the Started status', () => {
const { container } = renderComponent(Status.Started);
const element = container.querySelector(
'.ant-badge-status-dot.ant-badge-status-success',
);

expect(element).not.toBeNull();
const { dot } = renderComponent(Status.Started);
expect(dot).toHaveClass('ant-tag-green');
});

it('should render the Stopping status', () => {
const { container } = renderComponent(Status.Stopping);
const element = container.querySelector(
'.ant-badge-status-dot.ant-badge-status-processing',
);

expect(element).not.toBeNull();
const { dot } = renderComponent(Status.Stopping);
expect(dot).toHaveClass('ant-tag-blue');
});

it('should render the Stopped status', () => {
const { container } = renderComponent(Status.Stopped);
const element = container.querySelector(
'.ant-badge-status-dot.ant-badge-status-default',
);

expect(element).not.toBeNull();
const { dot } = renderComponent(Status.Stopped);
expect(dot).toHaveClass('ant-tag-red');
});

it('should render the Error status', () => {
const { container } = renderComponent(Status.Error);
const element = container.querySelector(
'.ant-badge-status-dot.ant-badge-status-error',
);

expect(element).not.toBeNull();
const { dot } = renderComponent(Status.Error);
expect(dot).toHaveClass('ant-tag-red');
});
});
64 changes: 29 additions & 35 deletions src/components/common/StatusTag.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,44 @@
import React from 'react';
import { render } from '@testing-library/react';
import { Status } from 'shared/types';
import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import StatusTag from './StatusTag';

const dockerServiceMock = injections.dockerService as jest.Mocked<
typeof injections.dockerService
>;
import StatusBadge from './StatusBadge';

describe('StatusTag Component', () => {
const renderComponent = (status: Status, externalNetworkName: string) => {
const network = getNetwork(0, 'test network', status);
network.externalNetworkName = externalNetworkName;
const initialState = {
network: {
networks: [network],
},
};
const result = renderWithProviders(<StatusTag networkId={0} />, { initialState });
const renderComponent = (status: Status, text?: string) => {
const result = render(<StatusBadge status={status} text={text} />);
return {
...result,
dot: result.container.querySelector('.ant-badge span:first-child'),
};
};

it('should render the Error status', async () => {
dockerServiceMock.getDockerExternalNetworks.mockResolvedValue([
'test-network-1',
'test-network-2',
]);
const docker_network_name = 'test-network-1';
it('should render the text', () => {
const { getByText } = renderComponent(Status.Starting, 'test text');
expect(getByText('test text')).toBeInTheDocument();
});

it('should render the Starting status', () => {
const { dot } = renderComponent(Status.Starting);
expect(dot).toHaveClass('ant-badge-status-processing');
});

it('should render the Started status', () => {
const { dot } = renderComponent(Status.Started);
expect(dot).toHaveClass('ant-badge-status-success');
});

it('should render the Stopping status', () => {
const { dot } = renderComponent(Status.Stopping);
expect(dot).toHaveClass('ant-badge-status-processing');
});

const { findByText } = renderComponent(Status.Started, docker_network_name);
const textElement = await findByText(`External: ${docker_network_name}`);
expect(textElement).toBeInTheDocument();
it('should render the Stopped status', () => {
const { dot } = renderComponent(Status.Stopped);
expect(dot).toHaveClass('ant-badge-status-default');
});
it('should render the Error status', async () => {
dockerServiceMock.getDockerExternalNetworks.mockResolvedValue([
'test-network-1',
'test-network-2',
]);
const docker_network_name = 'test-network-3';

const { findByText } = renderComponent(Status.Started, docker_network_name);
const textElement = await findByText(
`External Docker Network: ${docker_network_name} does not exist`,
);
expect(textElement).toBeInTheDocument();
it('should render the Error status', () => {
const { dot } = renderComponent(Status.Error);
expect(dot).toHaveClass('ant-badge-status-error');
});
});
45 changes: 6 additions & 39 deletions src/components/common/StatusTag.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,24 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Row, Tag } from 'antd';
import { useTheme } from 'hooks/useTheme';
import { Tag } from 'antd';
import { Status } from 'shared/types';
import { useStoreActions, useStoreState } from 'store';

export interface StatusTagProps {
networkId: number;
status: Status;
}

const StatusTag: React.FC<StatusTagProps> = ({ networkId }) => {
const StatusTag: React.FC<StatusTagProps> = ({ status }) => {
const { t } = useTranslation();

const { networks } = useStoreState(s => s.network);
const network = networks.find(n => n.id === networkId);
const { getExternalDockerNetworks } = useStoreActions(s => s.network);
const [dockerNetworks, setDockerNetworks] = useState<string[]>([]);

const { statusTag } = useTheme();

const statusColors = {
[Status.Starting]: 'blue',
[Status.Started]: 'green',
[Status.Stopping]: 'blue',
[Status.Stopped]: statusTag.stopped,
[Status.Stopped]: 'red',
[Status.Error]: 'red',
};

useEffect(() => {
(async () => {
const networks = await getExternalDockerNetworks();
setDockerNetworks(networks);
})();
}, [network?.externalNetworkName]);

const cmp =
network?.externalNetworkName &&
dockerNetworks.includes(network?.externalNetworkName) ? (
<Tag color="blue">{`External: ${network.externalNetworkName}`}</Tag>
) : (
<Tag color="error">{`External Docker Network: ${network?.externalNetworkName} does not exist`}</Tag>
);

return (
<Row>
{network && (
<Tag color={statusColors[network.status]}>
{t(`enums.status.${Status[network.status]}`)}
</Tag>
)}
{cmp}
</Row>
);
return <Tag color={statusColors[status]}>{t(`enums.status.${Status[status]}`)}</Tag>;
};

export default StatusTag;
9 changes: 9 additions & 0 deletions src/components/network/DockerNetworkModal.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ describe('DockerNetworkModal Component', () => {
});
});

it('should populate the existing external docker network value', async () => {
const network2 = getNetwork(1, 'test network 2', Status.Stopped);
network2.externalNetworkName = 'external_docker_network_99';
const { getByDisplayValue } = await renderComponent(network2);
await waitFor(() => {
expect(getByDisplayValue('external_docker_network_99')).toBeInTheDocument();
});
});

it('should display a creating message', async () => {
const { getByText, queryByText, getByLabelText, store } = await renderComponent(
network,
Expand Down
10 changes: 9 additions & 1 deletion src/components/network/DockerNetworkModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,15 @@ const DockerNetworkModal: React.FC<Props> = ({ network }) => {
disabled: setExternalDockerNetworkAsync.loading || !isDockerNetworkNameValid,
}}
>
<Form form={form} layout="vertical" colon={false} onFinish={handleSubmit}>
<Form
form={form}
layout="vertical"
colon={false}
onFinish={handleSubmit}
initialValues={{
networkName: network.externalNetworkName,
}}
>
<DockerNetworkName
name="networkName"
validateCallback={setIsDockerNetworkNameValid}
Expand Down
8 changes: 4 additions & 4 deletions src/components/network/NetworkActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,20 @@ const NetworkActions: React.FC<Props> = ({
case 'export':
onExportClick();
break;
case 'delete':
onDeleteClick();
break;
case 'docker':
onDockerNetworkClick();
break;
case 'delete':
onDeleteClick();
break;
}
}, []);

const items: MenuProps['items'] = [
{ key: 'rename', label: l('menuRename'), icon: <FormOutlined /> },
{ key: 'export', label: l('menuExport'), icon: <ExportOutlined /> },
{ key: 'delete', label: l('menuDelete'), icon: <CloseOutlined /> },
{ key: 'docker', label: l('menuDocker'), icon: <LinkOutlined /> },
{ key: 'delete', label: l('menuDelete'), icon: <CloseOutlined /> },
];

return (
Expand Down
18 changes: 15 additions & 3 deletions src/components/network/NetworkView.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ describe('NetworkView Component', () => {
id: string | undefined,
status?: Status,
images?: string[],
externalNetworkName?: string,
withBitcoinData = true,
) => {
const network = getNetwork(1, 'test network', status);
externalNetworkName ? (network.externalNetworkName = externalNetworkName) : null;
const bitcoinData = {
nodes: {
'1-backend1': {
Expand Down Expand Up @@ -200,6 +202,16 @@ describe('NetworkView Component', () => {
});
});

describe('external network', () => {
it('should display a message if their is a docker external network', async () => {
const msg = 'This network operates on an external docker network';
const networkName = 'external_docker_network_99';
const { getByText } = renderComponent('1', Status.Stopped, [], networkName);
expect(getByText(msg)).toBeInTheDocument();
expect(getByText(networkName)).toBeInTheDocument();
});
});

describe('node state', () => {
beforeEach(() => {
bitcoindServiceMock.getBlockchainInfo.mockResolvedValue({
Expand All @@ -213,22 +225,22 @@ describe('NetworkView Component', () => {
});

it('should fetch bitcoin data when mounted', async () => {
const { findByText } = renderComponent('1', Status.Started, [], false);
const { findByText } = renderComponent('1', Status.Started, [], undefined, false);
// wait for the new chain height to be displayed on mount
expect(await findByText('height: 321')).toBeInTheDocument();
});

it('should handle an error when fetching bitcoin data on mount', async () => {
bitcoindServiceMock.getBlockchainInfo.mockRejectedValue(new Error('test-err'));
const { findByText } = renderComponent('1', Status.Started, [], false);
const { findByText } = renderComponent('1', Status.Started, [], undefined, false);
expect(
await findByText('Failed to fetch the bitcoin block height'),
).toBeInTheDocument();
expect(await findByText('test-err')).toBeInTheDocument();
});

it('should not fetch bitcoin data if it is already in the store', async () => {
renderComponent('1', Status.Started, [], true);
renderComponent('1', Status.Started, [], undefined, true);
expect(bitcoindServiceMock.getBlockchainInfo).not.toHaveBeenCalled();
});
});
Expand Down
14 changes: 13 additions & 1 deletion src/components/network/NetworkView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ const NetworkView: React.FC<RouteComponentProps<MatchParams>> = ({ match }) => {
colors={theme.pageHeader}
title={network.name}
onBack={handleBackClick}
tags={<StatusTag networkId={networkId} />}
tags={<StatusTag status={network.status} />}
extra={
<NetworkActions
network={network}
Expand All @@ -195,6 +195,10 @@ const NetworkView: React.FC<RouteComponentProps<MatchParams>> = ({ match }) => {
const showNotice =
[Status.Stopped, Status.Starting].includes(network.status) &&
missingImages.length > 0;
const externalNetworkNotice =
[Status.Stopped, Status.Starting].includes(network.status) &&
network.externalNetworkName &&
network.externalNetworkName !== 'default';

return (
<Styled.NetworkView>
Expand All @@ -207,6 +211,14 @@ const NetworkView: React.FC<RouteComponentProps<MatchParams>> = ({ match }) => {
showIcon
/>
)}
{externalNetworkNotice && (
<Alert
type="info"
message={l('externalNetwork')}
description={network.externalNetworkName}
showIcon
/>
)}
{toggleAsync.error && (
<Alert
type="error"
Expand Down
Loading

0 comments on commit 9335722

Please sign in to comment.