console: add hook useOperationsFromQueryCollection

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5606
GitOrigin-RevId: eab15cb6aa928c9a471100252b85a4ce85e25e05
This commit is contained in:
Sooraj 2022-08-26 16:11:28 +05:30 committed by hasura-bot
parent a35bd278ad
commit 4ad498cd22
8 changed files with 175 additions and 0 deletions

View File

@ -263,4 +263,12 @@ export namespace MetadataSelector {
export const getAllDriversList = (m: MetadataResponse) =>
m.metadata?.sources.map(s => ({ source: s.name, kind: s.kind }));
export const getOperationsFromQueryCollection =
(queryCollectionName: string) => (m: MetadataResponse) => {
const queryCollectionDefinition = m.metadata?.query_collections?.find(
qs => qs.name === queryCollectionName
);
return queryCollectionDefinition?.definition?.queries ?? [];
};
}

View File

@ -0,0 +1 @@
export * from './useOperationsFromQueryCollection';

View File

@ -0,0 +1,10 @@
import { rest } from 'msw';
import { metadata } from './metadata';
const baseUrl = 'http://localhost:8080';
export const handlers = (url = baseUrl) => [
rest.post(`${url}/v1/metadata`, (req, res, ctx) => {
return res(ctx.json(metadata));
}),
];

View File

@ -0,0 +1,42 @@
import { MetadataResponse } from '@/features/MetadataAPI';
export const metadata: MetadataResponse = {
resource_version: 48,
metadata: {
version: 3,
sources: [],
remote_schemas: [],
inherited_roles: [],
query_collections: [
{
name: 'allowed-queries',
definition: {
queries: [
{
name: 'MyQuery',
query: 'query MyQuery {\n user {\n id\n }\n}\n',
},
],
},
},
],
allowlist: [
{
collection: 'allowed-queries',
scope: {
global: true,
},
},
],
},
};
export const metadata_with_no_query_collections: MetadataResponse = {
resource_version: 48,
metadata: {
version: 3,
sources: [],
remote_schemas: [],
inherited_roles: [],
},
};

View File

@ -0,0 +1,41 @@
import { ReactQueryDecorator } from '@/storybook/decorators/react-query';
import { ReduxDecorator } from '@/storybook/decorators/redux-decorator';
import ReactJson from 'react-json-view';
import { Meta, Story } from '@storybook/react';
import React from 'react';
import { useOperationsFromQueryCollection } from './useOperationsFromQueryCollection';
import { handlers } from './mocks/handlers.mock';
function UseOperationsFromQueryCollection() {
const operations = useOperationsFromQueryCollection('allowed-queries');
const error = operations.error;
return (
<div>
{operations.isSuccess ? (
<ReactJson collapsed src={operations.data} />
) : (
'no response'
)}
{error ? <ReactJson src={error} /> : null}
</div>
);
}
export const Primary: Story = () => {
return <UseOperationsFromQueryCollection />;
};
export default {
title: 'hooks/useOperationsFromQueryCollection',
decorators: [
ReduxDecorator({ tables: { currentDataSource: 'default' } }),
ReactQueryDecorator(),
],
parameters: {
msw: handlers(),
},
} as Meta;

View File

@ -0,0 +1,59 @@
import { setupServer } from 'msw/node';
import { rest } from 'msw';
import { renderHook } from '@testing-library/react-hooks';
import { metadata, metadata_with_no_query_collections } from './mocks/metadata';
import { useOperationsFromQueryCollection } from './useOperationsFromQueryCollection';
import { wrapper } from '../../../../hooks/__tests__/common/decorator';
const server = setupServer();
beforeAll(() => server.listen());
afterAll(() => server.close());
describe('useOperationsFromQueryCollection with valid data', () => {
beforeEach(() => {
server.use(
rest.post('/v1/metadata', (req, res, ctx) =>
res(ctx.status(200), ctx.json(metadata))
)
);
});
test('When useOperationsFromQueryCollection hook is called with query collection Name, then a valid list of operations are returned', async () => {
const { result, waitForValueToChange } = renderHook(
() => useOperationsFromQueryCollection('allowed-queries'),
{ wrapper }
);
await waitForValueToChange(() => result.current.isSuccess);
const operations = result.current.data!;
expect(operations).toHaveLength(1);
expect(operations[0].name).toEqual('MyQuery');
expect(operations[0].query).toEqual(
'query MyQuery {\n user {\n id\n }\n}\n'
);
});
});
describe('useOperationsFromQueryCollection with no query collections', () => {
beforeEach(() => {
server.use(
rest.post('/v1/metadata', (req, res, ctx) =>
res(ctx.status(200), ctx.json(metadata_with_no_query_collections))
)
);
});
test('When useOperationsFromQueryCollection is called with an invalid query collection, then empty array should be returned', async () => {
const { result, waitForValueToChange } = renderHook(
() => useOperationsFromQueryCollection('allowed-queries'),
{ wrapper }
);
await waitForValueToChange(() => result.current.isSuccess);
const operations = result.current.data!;
expect(operations).toHaveLength(0);
});
});

View File

@ -0,0 +1,6 @@
import { MetadataSelector, useMetadata } from '@/features/MetadataAPI';
export const useOperationsFromQueryCollection = (queryCollectionName: string) =>
useMetadata(
MetadataSelector.getOperationsFromQueryCollection(queryCollectionName)
);

View File

@ -742,9 +742,17 @@ export interface QueryCollection {
/**
* https://hasura.io/docs/latest/graphql/core/api-reference/schema-metadata-api/query-collections.html#add-collection-to-allowlist-syntax
*/
type AllowListScope =
| {
global: false;
roles: string[];
}
| { global: true };
export interface AllowList {
/** Name of a query collection to be added to the allow-list */
collection: CollectionName;
scope?: AllowListScope;
}
// //////////////////////////////