mirror of
https://github.com/hasura/graphql-engine.git
synced 2025-01-07 08:13:18 +03:00
console: add hook useOperationsFromQueryCollection
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5606 GitOrigin-RevId: eab15cb6aa928c9a471100252b85a4ce85e25e05
This commit is contained in:
parent
a35bd278ad
commit
4ad498cd22
@ -263,4 +263,12 @@ export namespace MetadataSelector {
|
|||||||
|
|
||||||
export const getAllDriversList = (m: MetadataResponse) =>
|
export const getAllDriversList = (m: MetadataResponse) =>
|
||||||
m.metadata?.sources.map(s => ({ source: s.name, kind: s.kind }));
|
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 ?? [];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from './useOperationsFromQueryCollection';
|
@ -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));
|
||||||
|
}),
|
||||||
|
];
|
@ -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: [],
|
||||||
|
},
|
||||||
|
};
|
@ -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;
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,6 @@
|
|||||||
|
import { MetadataSelector, useMetadata } from '@/features/MetadataAPI';
|
||||||
|
|
||||||
|
export const useOperationsFromQueryCollection = (queryCollectionName: string) =>
|
||||||
|
useMetadata(
|
||||||
|
MetadataSelector.getOperationsFromQueryCollection(queryCollectionName)
|
||||||
|
);
|
@ -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
|
* 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 {
|
export interface AllowList {
|
||||||
/** Name of a query collection to be added to the allow-list */
|
/** Name of a query collection to be added to the allow-list */
|
||||||
collection: CollectionName;
|
collection: CollectionName;
|
||||||
|
scope?: AllowListScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
// //////////////////////////////
|
// //////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user