Skip to content

Commit

Permalink
add clients UI, federation validation error logging (#148)
Browse files Browse the repository at this point in the history
* add clients UI, federation validation error logging

* remove clientVersions resolver & db fn as thats not used
add integration test for client resolver
  • Loading branch information
tot-ra authored Oct 6, 2022
1 parent ac03bb0 commit 3e301c0
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 30 deletions.
42 changes: 42 additions & 0 deletions client/clients/clientPersistedQueries.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// eslint-disable-next-line
import React from 'react';
import { useQuery } from '@apollo/client';

import PersistedQuery from '../persisted-queries/PersistedQuery';
import SpinnerCenter from '../components/SpinnerCenter';
import { CLIENT_VERSION_PERSISTED_QUERIES } from '../utils/queries';

const ClientPersistedQueries = ({ selectedVersion }) => {
if (!selectedVersion) {
return null;
}

const { loading, data } = useQuery(CLIENT_VERSION_PERSISTED_QUERIES, {
variables: { clientVersionId: selectedVersion },
});

if (loading) {
return <SpinnerCenter />;
}

if (!data) {
return <div style={{ padding: '10px' }}>No queries found</div>;
}

return (
<div style={{ padding: 10 }}>
{data?.persistedQueries.length > 0 && (
<strong>Persisted Queries</strong>
)}
{data?.persistedQueries.map((pq) => {
return (
<div key={pq.key}>
<PersistedQuery key={pq.key} query={pq} />
</div>
);
})}
</div>
);
};

export default ClientPersistedQueries;
73 changes: 73 additions & 0 deletions client/clients/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//eslint-disable-next-line
import React, { useState } from 'react';
import { HashRouter as Router } from 'react-router-dom';
import { useQuery } from '@apollo/client';
import { List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';

import SpinnerCenter from '../components/SpinnerCenter';
import { CLIENTS_LIST } from '../utils/queries';
import { ColumnPanel } from '../components/styled';
import ClientVersions from './versions';
import ClientPersistedQueries from './clientPersistedQueries';

export default function Clients() {
const { loading, data } = useQuery(CLIENTS_LIST);

const [selectedClient, setSelectedClient] = useState(null);
const [selectedVersion, setSelectedVersion] = useState(null);

if (loading) {
return <SpinnerCenter />;
}

if (!data || data.clients.length === 0) {
return <div style={{ padding: '10px' }}>No clients found</div>;
}

const clients = data.clients.map((client) => {
return (
<ListItem
selected={selectedClient === client.name}
key={client.name}
onClick={() => {
setSelectedClient(client.name);
}}
>
<ListItemText primary={client.name} />
<ListItemIcon>
<ChevronRightIcon />
</ListItemIcon>
</ListItem>
);
});

return (
<Router basename="/clients">
<div style={{ display: 'flex' }}>
<List
component="nav"
style={{ borderRight: '1px solid #eeeeee' }}
>
{clients}
</List>

<ColumnPanel
all="m"
style={{ borderRight: '1px solid #eeeeee' }}
>
<ClientVersions
clients={data.clients}
selectedClient={selectedClient}
selectedVersion={selectedVersion}
setSelectedVersion={setSelectedVersion}
/>
</ColumnPanel>

<div style={{ flexGrow: 1 }}>
<ClientPersistedQueries selectedVersion={selectedVersion} />
</div>
</div>
</Router>
);
}
57 changes: 57 additions & 0 deletions client/clients/versions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//eslint-disable-next-line
import React from 'react';
import { formatDistance } from 'date-fns';

import { List, ListItem } from '@material-ui/core';
import { FlexRow, EntryGrid } from '../components/styled';

const Versions = ({
clients,
selectedClient,
selectedVersion,
setSelectedVersion,
}) => {
let versions = null;

if (!selectedClient) {
return null;
}

clients.map((client) => {
if (selectedClient === client.name && client.versions) {
versions = client.versions.map((version) => (
<ListItem
selected={selectedVersion === version.id}
key={version.id}
onClick={() => setSelectedVersion(version.id)}
>
<EntryGrid>
<div style={{ cursor: 'pointer' }}>
<FlexRow>
<div>{version.version}</div>
</FlexRow>
<div>
Updated{' '}
{formatDistance(
new Date(version.updatedTime),
new Date(),
{
addSuffix: true,
}
)}
</div>
</div>
</EntryGrid>
</ListItem>
));
}
});

if (!versions) {
versions = <div>No versions found</div>;
}

return <List component="nav">{versions}</List>;
};

export default Versions;
8 changes: 6 additions & 2 deletions client/components/Main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import TopMenu from './TopMenu';
import TabPanel from './TabPanel';
import Schema from '../schema';
import PersistedQueries from '../persisted-queries';
import Clients from '../clients';

import ServicesTab from '../schema/Tab';
import PersistedQueriesTab from '../persisted-queries/Tab';
Expand All @@ -13,12 +14,15 @@ const UITabs = [
{
Title: <ServicesTab />,
href: '/schema',
icon: 'dashboard',
component: Schema,
},
{
Title: <span>Clients</span>,
href: '/clients',
component: Clients,
},
{
Title: <PersistedQueriesTab />,
icon: 'ac-document',
href: '/persisted-queries',
component: PersistedQueries,
},
Expand Down
22 changes: 16 additions & 6 deletions client/components/styled.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import styled from 'styled-components';
import { Container, Button } from '@material-ui/core';
import { Button } from '@material-ui/core';
import { colors, elevations } from '../utils';

export const EntryPanel = styled(Container)`
export const EntryPanel = styled.div`
transition: 0.2s ease-in;
box-shadow: ${elevations[2]};
cursor: ${({ onClick }) => onClick && 'pointer'};
Expand All @@ -24,6 +24,7 @@ export const EntryPanel = styled(Container)`
export const EntryName = styled.h3`
font-weight: 400;
margin: 0;
padding: 10px;
& > span {
font-weight: normal;
}
Expand All @@ -36,10 +37,6 @@ export const EntryGrid = styled.div`
& > :first-child {
flex: 2;
}
.cui4-icon {
margin: 0 5px;
}
`;

export const FlexCenter = styled.div`
Expand Down Expand Up @@ -80,3 +77,16 @@ export const CopyButton = styled(Button)`
right: 8px;
z-index: 2;
`;

export const ColumnPanel = styled.div`
min-width: 170px;
flex-shrink: 0;
`;

export const FlexRow = styled.div`
display: flex;
flex-flow: row nowrap;
overflow: hidden;
height: 100%;
justify-content: space-between;
`;
22 changes: 22 additions & 0 deletions client/utils/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,25 @@ export const SCHEMA_USAGE_SDL = gql`
}
}
`;

export const CLIENTS_LIST = gql`
query getClients {
clients {
name
versions {
id
version
updatedTime
}
}
}
`;

export const CLIENT_VERSION_PERSISTED_QUERIES = gql`
query gerClientPersistedQueries($clientVersionId: Int!) {
persistedQueries(clientVersionId: $clientVersionId) {
key
query
}
}
`;
6 changes: 6 additions & 0 deletions migrations/20221003232700_client_pq_rel.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ALTER TABLE `clients_persisted_queries_rel` ADD `added_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP AFTER `pq_key`;

ALTER TABLE `clients_persisted_queries_rel`
CHANGE `pq_key` `pq_key` VARCHAR(100)
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';
19 changes: 0 additions & 19 deletions src/database/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,25 +166,6 @@ const clientsModel = {
connection('clients')
.select('id', 'version', 'updated_time as updatedTime')
.where({ name }),

getClientVersionsSince: async ({ since }) => {
if (isNil(since)) {
return [];
}

return connection('clients')
.select([
'id',
'name',
'version',
'added_time as addedTime',
'updated_time',
])
.where((knex) => {
return knex.where('added_time', '>', since);
})
.limit(100);
},
};

export default clientsModel;
17 changes: 17 additions & 0 deletions src/database/persisted_queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ const PersistedQueriesModel = {
)[0].amount;
},

getVersionPersistedQueries: async function ({ version_id }) {
return await connection('persisted_queries')
.innerJoin(
'clients_persisted_queries_rel',
'persisted_queries.key',
'clients_persisted_queries_rel.pq_key'
)
.select([
'query',
'key',
'clients_persisted_queries_rel.added_time as addedTime',
])
.where({
'clients_persisted_queries_rel.version_id': version_id,
});
},

list: async function ({ searchFragment = '', limit = 100, offset = 0 }) {
return connection('persisted_queries')
.select(['query', 'key', 'added_time'])
Expand Down
44 changes: 44 additions & 0 deletions src/graphql/resolvers.itest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import resolvers from './resolvers';
import { cleanTables } from '../../test/integration/database';

import clientsModel from '../database/clients';

describe('app/graphql', () => {
beforeEach(async () => {
await cleanTables();
});

describe('POST /graphql', () => {
describe('Query { clients } ', () => {
it('returns empty set', async () => {
const result = await resolvers.Query.clients();

expect(result).toEqual([]);
});

it('returns two clients', async () => {
// ARRANGE
clientsModel.add({
name: 'client_a',
version: 'v1',
persistedQueryHash: 'abc',
});
clientsModel.add({
name: 'client_b',
version: 'v2',
persistedQueryHash: 'def',
});
await clientsModel.syncUniqueClientsToDb();

// ACT
const result = await resolvers.Query.clients();

// ASSERT
expect(result).toEqual([
{ name: 'client_a' },
{ name: 'client_b' },
]);
});
});
});
});
Loading

0 comments on commit 3e301c0

Please sign in to comment.