Skip to content
This repository was archived by the owner on Mar 25, 2021. It is now read-only.

Commit 70105af

Browse files
committed
feat: Add useTopics model hook and query for topics listing
- This commit adds a new `useTopics` model hook, which makes GraphQL requests to the server to administer Kafka topics. - The hook returns a set of sub-hooks, with just the `useGetTopics` sub-hook implemented for now. `useGetTopics` returns the list of topics (including name, number of partitions and number of replicas). Contributes to: #124 Signed-off-by: Andrew Borley <[email protected]>
1 parent 2689890 commit 70105af

File tree

12 files changed

+204
-6
lines changed

12 files changed

+204
-6
lines changed

client/Bootstrap/index.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import { init } from 'i18n';
88
import { ApolloProvider } from '@apollo/client';
99

1010
import { apolloClient } from 'Bootstrap/GraphQLClient';
11-
import { ConfigFeatureFlagProvider, FeatureFlag } from 'Contexts';
11+
import {
12+
ConfigFeatureFlagProvider,
13+
FeatureFlag,
14+
LoggingProvider,
15+
} from 'Contexts';
1216
import { Home } from 'Panels/Home';
13-
import { LoggingProvider } from 'Contexts';
1417

1518
init(); //Bootstrap i18next support
1619
ReactDOM.render(

client/Models/README.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Models
2+
3+
This directory contains custom [React Hooks](https://reactjs.org/docs/hooks-intro.html#motivation). Unlike the [Hooks](../Hooks/README.md), these hooks encapsulate specific business logic for views to utilise.
4+
5+
## Test approach
6+
7+
Elements should be tested in a functional manor. See [Test Driven Development](../../docs/Test.md#style-of-test).
8+
9+
## Expected files
10+
11+
For a given model `useFoo`, the expected files are as follows:
12+
13+
```
14+
Models/
15+
index.ts
16+
types.ts
17+
useFoo/
18+
README.md
19+
useFoo.ts
20+
useFoo.spec.ts
21+
useFoo.assets.ts
22+
useFoo.types.ts
23+
```
24+
25+
Where:
26+
27+
- index.ts acts as a barrel file, exporting the hooks defined in the Hooks directory
28+
- types.ts acts as a barrel file, exporting all the public types of each context
29+
- README.md is the readme for this hook, detailing design choices and usage
30+
- useFoo.ts is the hook implementation
31+
- useFoo.spec.ts are the tests for this hook
32+
- useFoo.assets.ts are the test assets for this hook
33+
- useFoo.types.ts are the types for this hook
34+
35+
## Implemented hooks
36+
37+
- [`useTopics`](./useTopics/README.md) - a hook providing sub-hooks to administer Kafka topics via GraphQL queries.

client/Models/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
export * from './useTopics';

client/Models/useTopics/Hook.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
import { GET_TOPICS } from 'Queries/Topics';
6+
import { useQuery } from '@apollo/client';
7+
import { useTopicsType } from './useTopics.types';
8+
9+
export const useTopics = (): useTopicsType => {
10+
const useGetTopics = () => useQuery(GET_TOPICS);
11+
return {
12+
useGetTopics,
13+
};
14+
};

client/Models/useTopics/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# useTopics
2+
3+
The `useTopics` hook returns sub-hooks to administer Kafka topics via GraphQL queries to the server `/api` endpoint. The sub-hooks returned by the `useTopics` hook are:
4+
5+
- `useGetTopics()` - returns the list of topics, including name, partitions count and replicas count, as an [Apollo `QueryResult` object](https://www.apollographql.com/docs/react/api/react/hooks/#result).

client/Models/useTopics/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
export * from './Hook';
6+
export * from './useTopics.types';
7+
export * from './useTopics.assets';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
import { generateMockDataResponseForGQLRequest } from 'utils/test/withApollo/withApollo.util';
6+
import { topicsType } from './useTopics.types';
7+
import { GET_TOPICS } from 'Queries/Topics';
8+
9+
export const mockGetTopicsResponse: topicsType = {
10+
topics: [
11+
{ name: 'testtopic1', partitions: 1, replicas: 1 },
12+
{ name: 'testtopic2', partitions: 2, replicas: 2 },
13+
{ name: 'testtopic3', partitions: 3, replicas: 3 },
14+
],
15+
};
16+
17+
const successRequest = generateMockDataResponseForGQLRequest(
18+
GET_TOPICS,
19+
mockGetTopicsResponse
20+
);
21+
22+
export const mockGetTopicsRequests = {
23+
successRequest,
24+
};
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
import React from 'react';
6+
import { renderHook, act } from '@testing-library/react-hooks';
7+
import { withApolloProviderReturning, apolloMockResponse } from 'utils/test';
8+
import { useTopics } from './Hook';
9+
import {
10+
mockGetTopicsRequests,
11+
mockGetTopicsResponse,
12+
} from './useTopics.assets';
13+
14+
describe('`useTopics` hook', () => {
15+
describe('`useGetTopics` hook', () => {
16+
it('returns the expected content', async () => {
17+
const { result, rerender } = renderHook(
18+
() => useTopics().useGetTopics(),
19+
{
20+
wrapper: ({ children }) =>
21+
withApolloProviderReturning(
22+
[mockGetTopicsRequests.successRequest],
23+
<React.Fragment>{children}</React.Fragment>
24+
),
25+
}
26+
);
27+
28+
expect(result.current.loading).toBe(true);
29+
expect(result.current.data).toBeUndefined();
30+
31+
await act(async () => {
32+
await apolloMockResponse();
33+
});
34+
rerender();
35+
36+
expect(result.current.loading).toBe(false);
37+
expect(result.current.data).toEqual(mockGetTopicsResponse);
38+
});
39+
});
40+
});
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
import { QueryResult } from '@apollo/client';
6+
7+
/** the shape of the object returned by the useTopics hook */
8+
export type useTopicsType = {
9+
useGetTopics: () => QueryResult<topicsType>;
10+
};
11+
12+
/** the shape of the `data` returned by the useGetTopics hook */
13+
export type topicsType = {
14+
topics: topicType[];
15+
};
16+
17+
export type topicType = {
18+
name: string;
19+
partitions: number;
20+
replicas: number;
21+
};

client/Panels/Home/Home.steps.tsx

+22-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
import { Given, When, Then, Fusion } from 'jest-cucumber-fusion';
66
import { RenderResult } from '@testing-library/react';
77
import merge from 'lodash.merge';
8-
import { renderWithCustomConfigFeatureFlagContext } from 'utils/test';
8+
import {
9+
renderWithCustomConfigFeatureFlagContext,
10+
withApolloProviderReturning,
11+
apolloMockResponse,
12+
} from 'utils/test';
13+
import { mockGetTopicsRequests } from 'Models';
914
import { Home } from '.';
1015
import React, { ReactElement } from 'react';
1116

@@ -31,7 +36,10 @@ Given('a Home component', () => {
3136
When('it is rendered', () => {
3237
renderResult = renderWithCustomConfigFeatureFlagContext(
3338
coreConfigFromContext,
34-
component
39+
withApolloProviderReturning(
40+
[mockGetTopicsRequests.successRequest],
41+
component
42+
)
3543
);
3644
showVersionSet = true;
3745
});
@@ -47,18 +55,28 @@ When('it is rendered with no version', () => {
4755
},
4856
},
4957
}),
50-
component
58+
withApolloProviderReturning(
59+
[mockGetTopicsRequests.successRequest],
60+
component
61+
)
5162
);
5263
showVersionSet = false;
5364
});
5465

55-
Then('it should display the expected text', () => {
66+
Then('it should display the expected text', async () => {
5667
const { getByText, queryByText } = renderResult;
5768
expect(getByText('Welcome to the Strimzi UI')).toBeInTheDocument();
5869
const versionString = `Version: ${coreConfigFromContext.client.about.version}`;
5970
showVersionSet
6071
? expect(getByText(versionString)).toBeInTheDocument()
6172
: expect(queryByText(versionString)).not.toBeInTheDocument();
73+
74+
const loadingTopicsString = 'Loading...';
75+
expect(getByText(loadingTopicsString)).toBeInTheDocument();
76+
77+
await apolloMockResponse();
78+
expect(queryByText(loadingTopicsString)).not.toBeInTheDocument();
79+
expect(getByText('Number of topics: 3')).toBeInTheDocument();
6280
});
6381

6482
Fusion('Home.feature');

client/Panels/Home/Home.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import get from 'lodash.get';
77
import image from 'Images/logo.png';
88
import './style.scss';
99
import { useConfigFeatureFlag, useLogger } from 'Hooks';
10+
import { useTopics } from 'Models';
1011

1112
const Home: FunctionComponent = ({ children }) => {
1213
const { client, featureFlags, isComplete } = useConfigFeatureFlag();
@@ -17,11 +18,19 @@ const Home: FunctionComponent = ({ children }) => {
1718
const { debug } = useLogger('Home');
1819
debug(`Client version to display: ${version}`);
1920

21+
const { useGetTopics } = useTopics();
22+
const { data, loading } = useGetTopics();
23+
2024
return (
2125
<div className='home'>
2226
<img src={image} alt='Strimzi logo' />
2327
<p>Welcome to the Strimzi UI</p>
2428
{showVersion && isComplete && <p>{`Version: ${version}`}</p>}
29+
{loading || !data ? (
30+
<p>Loading...</p>
31+
) : (
32+
<p>{`Number of topics: ${data.topics.length}`}</p>
33+
)}
2534
{children}
2635
</div>
2736
);

client/Queries/Topics/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright Strimzi authors.
3+
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
4+
*/
5+
import gql from 'graphql-tag';
6+
7+
export const GET_TOPICS = gql`
8+
query {
9+
topics {
10+
name
11+
partitions
12+
replicas
13+
}
14+
}
15+
`;

0 commit comments

Comments
 (0)