mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
chore: enable rule of hooks (#7080)
This commit is contained in:
parent
ea73b9ab9b
commit
b02b1dbf2f
7 changed files with 135 additions and 112 deletions
|
|
@ -179,7 +179,7 @@ module.exports = {
|
|||
'react/jsx-no-useless-fragment': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'react-hooks/rules-of-hooks': 'off',
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
'unicorn/filename-case': 'off',
|
||||
'import/no-default-export': 'off',
|
||||
|
|
@ -206,13 +206,12 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
},
|
||||
// {
|
||||
// files: ['packages/web/app/**'],
|
||||
// excludedFiles: ['packages/web/app/src/pages/**'],
|
||||
// rules: {
|
||||
// 'import/no-unused-modules': ['error', { unusedExports: true }],
|
||||
// },
|
||||
// },
|
||||
{
|
||||
files: ['packages/web/app/**/*.stories.tsx', 'packages/web/docs/**'],
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['packages/web/docs/**'],
|
||||
settings: {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ function CollectedOperationsOverTime(props: {
|
|||
const dataRef = useRef<[string, number][]>();
|
||||
dataRef.current ||= operations.map(node => [node.date, node.count]);
|
||||
const data = dataRef.current;
|
||||
const chartStyles = useChartStyles();
|
||||
|
||||
return (
|
||||
<AutoSizer disableHeight>
|
||||
|
|
@ -93,7 +94,7 @@ function CollectedOperationsOverTime(props: {
|
|||
style={{ width: size.width, height: 200 }}
|
||||
theme={theme.theme}
|
||||
option={{
|
||||
...useChartStyles(),
|
||||
...chartStyles,
|
||||
grid: {
|
||||
left: 50,
|
||||
top: 50,
|
||||
|
|
|
|||
|
|
@ -130,13 +130,23 @@ export function ChangesBlock(
|
|||
}
|
||||
),
|
||||
): ReactElement | null {
|
||||
const changes = props.changesWithUsage ?? props.changes;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="mb-3 font-bold text-gray-900 dark:text-white">{props.title}</h2>
|
||||
<div className="list-inside list-disc space-y-2 text-sm leading-relaxed">
|
||||
{changes.map((change, key) => (
|
||||
{props.changesWithUsage?.map((change, key) => (
|
||||
<ChangeItem
|
||||
organizationSlug={props.organizationSlug}
|
||||
projectSlug={props.projectSlug}
|
||||
targetSlug={props.targetSlug}
|
||||
schemaCheckId={props.schemaCheckId}
|
||||
key={key}
|
||||
change={null}
|
||||
changeWithUsage={change}
|
||||
conditionBreakingChangeMetadata={props.conditionBreakingChangeMetadata ?? null}
|
||||
/>
|
||||
))}
|
||||
{props.changes?.map((change, key) => (
|
||||
<ChangeItem
|
||||
organizationSlug={props.organizationSlug}
|
||||
projectSlug={props.projectSlug}
|
||||
|
|
@ -144,6 +154,7 @@ export function ChangesBlock(
|
|||
schemaCheckId={props.schemaCheckId}
|
||||
key={key}
|
||||
change={change}
|
||||
changeWithUsage={null}
|
||||
conditionBreakingChangeMetadata={props.conditionBreakingChangeMetadata ?? null}
|
||||
/>
|
||||
))}
|
||||
|
|
@ -152,32 +163,34 @@ export function ChangesBlock(
|
|||
);
|
||||
}
|
||||
|
||||
// Obviously I'm not proud of this...
|
||||
// But I didn't want to spend too much time on this
|
||||
function isChangesBlock_SchemaChangeWithUsageFragment(
|
||||
fragment: any,
|
||||
): fragment is FragmentType<typeof ChangesBlock_SchemaChangeWithUsageFragment> {
|
||||
return (
|
||||
!!fragment[' $fragmentRefs'] &&
|
||||
'ChangesBlock_SchemaChangeWithUsageFragment' in fragment[' $fragmentRefs']
|
||||
function ChangeItem(
|
||||
props: {
|
||||
conditionBreakingChangeMetadata: FragmentType<
|
||||
typeof ChangesBlock_SchemaCheckConditionalBreakingChangeMetadataFragment
|
||||
> | null;
|
||||
organizationSlug: string;
|
||||
projectSlug: string;
|
||||
targetSlug: string;
|
||||
schemaCheckId: string;
|
||||
} & (
|
||||
| {
|
||||
change: FragmentType<typeof ChangesBlock_SchemaChangeFragment>;
|
||||
changeWithUsage: null;
|
||||
}
|
||||
| {
|
||||
change: null;
|
||||
changeWithUsage: FragmentType<typeof ChangesBlock_SchemaChangeWithUsageFragment>;
|
||||
}
|
||||
),
|
||||
) {
|
||||
const cchange = useFragment(ChangesBlock_SchemaChangeFragment, props.change);
|
||||
const cchangeWithUsage = useFragment(
|
||||
ChangesBlock_SchemaChangeWithUsageFragment,
|
||||
props.changeWithUsage,
|
||||
);
|
||||
}
|
||||
|
||||
function ChangeItem(props: {
|
||||
change:
|
||||
| FragmentType<typeof ChangesBlock_SchemaChangeWithUsageFragment>
|
||||
| FragmentType<typeof ChangesBlock_SchemaChangeFragment>;
|
||||
conditionBreakingChangeMetadata: FragmentType<
|
||||
typeof ChangesBlock_SchemaCheckConditionalBreakingChangeMetadataFragment
|
||||
> | null;
|
||||
organizationSlug: string;
|
||||
projectSlug: string;
|
||||
targetSlug: string;
|
||||
schemaCheckId: string;
|
||||
}) {
|
||||
const change = isChangesBlock_SchemaChangeWithUsageFragment(props.change)
|
||||
? useFragment(ChangesBlock_SchemaChangeWithUsageFragment, props.change)
|
||||
: useFragment(ChangesBlock_SchemaChangeFragment, props.change);
|
||||
// at least one prop must be provided :)
|
||||
const change = (cchange ?? cchangeWithUsage)!;
|
||||
|
||||
const metadata = useFragment(
|
||||
ChangesBlock_SchemaCheckConditionalBreakingChangeMetadataFragment,
|
||||
|
|
|
|||
|
|
@ -49,12 +49,10 @@ function OperationsFilter({
|
|||
operationStatsConnection,
|
||||
);
|
||||
|
||||
const clientFilteredOperations = clientOperationStatsConnection
|
||||
? useFragment(
|
||||
OperationsFilter_OperationStatsValuesConnectionFragment,
|
||||
clientOperationStatsConnection,
|
||||
)
|
||||
: null;
|
||||
const clientFilteredOperations = useFragment(
|
||||
OperationsFilter_OperationStatsValuesConnectionFragment,
|
||||
clientOperationStatsConnection,
|
||||
);
|
||||
|
||||
function getOperationHashes() {
|
||||
const items: string[] = [];
|
||||
|
|
@ -324,11 +322,12 @@ function OperationRow({
|
|||
}): ReactElement {
|
||||
const operation = useFragment(OperationRow_OperationStatsValuesFragment, operationStats);
|
||||
const requests = useFormattedNumber(operation.count);
|
||||
const clientsOperation = clientOperationStats
|
||||
? useFragment(OperationRow_OperationStatsValuesFragment, clientOperationStats)
|
||||
: undefined;
|
||||
const clientsOperation = useFragment(
|
||||
OperationRow_OperationStatsValuesFragment,
|
||||
clientOperationStats || null,
|
||||
);
|
||||
const hasClientOperation = clientOperationStats !== false;
|
||||
const clientsRequests = clientsOperation ? useFormattedNumber(clientsOperation.count) : null;
|
||||
const clientsRequests = useFormattedNumber(clientsOperation?.count);
|
||||
const hash = operation.operationHash || '';
|
||||
const change = useCallback(() => {
|
||||
if (hash) {
|
||||
|
|
@ -340,7 +339,7 @@ function OperationRow({
|
|||
if (hasClientOperation) {
|
||||
return (
|
||||
<div className="flex shrink-0 text-right text-gray-500">
|
||||
<span>{clientsRequests ?? 0}</span>
|
||||
<span>{clientsRequests === '-' ? 0 : clientsRequests}</span>
|
||||
<span className="ml-1 truncate text-gray-600">/ {requests}</span>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -425,10 +424,10 @@ function ClientRow({
|
|||
style: any;
|
||||
}): ReactElement {
|
||||
const client = useFragment(ClientRow_ClientStatsValuesFragment, props.client);
|
||||
const clientOperation =
|
||||
props.clientOperationStats === false
|
||||
? false
|
||||
: useFragment(ClientRow_ClientStatsValuesFragment, props.clientOperationStats);
|
||||
const clientOperation = useFragment(
|
||||
ClientRow_ClientStatsValuesFragment,
|
||||
props.clientOperationStats || null,
|
||||
);
|
||||
const requests = useFormattedNumber(client.count);
|
||||
const hash = client.name;
|
||||
const change = useCallback(() => {
|
||||
|
|
@ -438,7 +437,7 @@ function ClientRow({
|
|||
}, [onSelect, hash, selected]);
|
||||
|
||||
const Totals = () => {
|
||||
if (clientOperation !== false) {
|
||||
if (props.clientOperationStats !== false) {
|
||||
return (
|
||||
<div className="flex shrink-0 text-right text-gray-500">
|
||||
<span>{clientOperation?.count ?? 0}</span>
|
||||
|
|
@ -544,9 +543,10 @@ function ClientsFilter({
|
|||
setSelectedItems([]);
|
||||
}, [setSelectedItems]);
|
||||
|
||||
const operationConnection = operationStatsConnection
|
||||
? useFragment(ClientsFilter_ClientStatsValuesConnectionFragment, operationStatsConnection)
|
||||
: null;
|
||||
const operationConnection = useFragment(
|
||||
ClientsFilter_ClientStatsValuesConnectionFragment,
|
||||
operationStatsConnection ?? null,
|
||||
);
|
||||
|
||||
const renderRow = useCallback<ComponentType<ListChildComponentProps>>(
|
||||
({ index, style }) => {
|
||||
|
|
|
|||
|
|
@ -11,19 +11,9 @@ import { AlertTriangleIcon, TrashIcon } from '@/components/ui/icon';
|
|||
import { SubPageLayout, SubPageLayoutHeader } from '@/components/ui/page-content-layout';
|
||||
import { Input, Modal, Table, Tag, TBody, Td, TimeAgo, Tr } from '@/components/v2';
|
||||
import { InlineCode } from '@/components/v2/inline-code';
|
||||
import { graphql, useFragment } from '@/gql';
|
||||
import { FragmentType, graphql, useFragment } from '@/gql';
|
||||
import { Link, useRouter } from '@tanstack/react-router';
|
||||
|
||||
const CDNAccessTokeRowFragment = graphql(`
|
||||
fragment CDNAccessTokens_CdnAccessTokenRowFragment on CdnAccessToken {
|
||||
id
|
||||
firstCharacters
|
||||
lastCharacters
|
||||
alias
|
||||
createdAt
|
||||
}
|
||||
`);
|
||||
|
||||
const CDNAccessTokenCreateMutation = graphql(`
|
||||
mutation CDNAccessTokens_CDNAccessTokenCreateMutation($input: CreateCdnAccessTokenInput!) {
|
||||
createCdnAccessToken(input: $input) {
|
||||
|
|
@ -407,38 +397,9 @@ export function CDNAccessTokens(props: {
|
|||
</div>
|
||||
<Table>
|
||||
<TBody>
|
||||
{target?.data?.target?.cdnAccessTokens.edges?.map(edge => {
|
||||
const node = useFragment(CDNAccessTokeRowFragment, edge.node);
|
||||
|
||||
return (
|
||||
<Tr key={node.id}>
|
||||
<Td>
|
||||
{node.firstCharacters + new Array(10).fill('•').join('') + node.lastCharacters}
|
||||
</Td>
|
||||
<Td>{node.alias}</Td>
|
||||
<Td align="right">
|
||||
created <TimeAgo date={node.createdAt} />
|
||||
</Td>
|
||||
<Td align="right">
|
||||
<Button
|
||||
className="hover:text-red-500"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
void router.navigate({
|
||||
search: {
|
||||
page: 'cdn',
|
||||
cdn: 'delete',
|
||||
id: node.id,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{target?.data?.target?.cdnAccessTokens.edges?.map(edge => (
|
||||
<CDNAccessTokenRow cdnAccessToken={edge.node} key={edge.node.id} />
|
||||
))}
|
||||
</TBody>
|
||||
</Table>
|
||||
|
||||
|
|
@ -503,3 +464,49 @@ export function CDNAccessTokens(props: {
|
|||
</SubPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
const CDNAccessTokenRowFragment = graphql(`
|
||||
fragment CDNAccessTokens_CdnAccessTokenRowFragment on CdnAccessToken {
|
||||
id
|
||||
firstCharacters
|
||||
lastCharacters
|
||||
alias
|
||||
createdAt
|
||||
}
|
||||
`);
|
||||
|
||||
type CDNAccessTokenRowProps = {
|
||||
cdnAccessToken: FragmentType<typeof CDNAccessTokenRowFragment>;
|
||||
};
|
||||
|
||||
function CDNAccessTokenRow(props: CDNAccessTokenRowProps): React.ReactNode {
|
||||
const node = useFragment(CDNAccessTokenRowFragment, props.cdnAccessToken);
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Tr key={node.id}>
|
||||
<Td>{node.firstCharacters + new Array(10).fill('•').join('') + node.lastCharacters}</Td>
|
||||
<Td>{node.alias}</Td>
|
||||
<Td align="right">
|
||||
created <TimeAgo date={node.createdAt} />
|
||||
</Td>
|
||||
<Td align="right">
|
||||
<Button
|
||||
className="hover:text-red-500"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
void router.navigate({
|
||||
search: {
|
||||
page: 'cdn',
|
||||
cdn: 'delete',
|
||||
id: node.id,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,22 +271,13 @@ function ChecksPageContent(props: {
|
|||
},
|
||||
});
|
||||
|
||||
if (query.error) {
|
||||
return (
|
||||
<QueryError
|
||||
organizationSlug={props.organizationSlug}
|
||||
error={query.error}
|
||||
showLogoutButton={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const isLoading = query.fetching || query.stale;
|
||||
const renderLoading = useDebouncedLoader(isLoading);
|
||||
|
||||
const [hasSchemaChecks, setHasSchemaChecks] = useState(
|
||||
!!query.data?.target?.schemaChecks?.edges?.length,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading) {
|
||||
setHasSchemaChecks(!!query.data?.target?.schemaChecks?.edges?.length);
|
||||
|
|
@ -298,8 +289,19 @@ function ChecksPageContent(props: {
|
|||
const [paginationVariables, setPaginationVariables] = useState<Array<string | null>>(() => [
|
||||
null,
|
||||
]);
|
||||
|
||||
const onLoadMore = (cursor: string) => setPaginationVariables(cursors => [...cursors, cursor]);
|
||||
|
||||
if (query.error) {
|
||||
return (
|
||||
<QueryError
|
||||
organizationSlug={props.organizationSlug}
|
||||
error={query.error}
|
||||
showLogoutButton={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={cn(!hasSchemaChecks && 'w-full')}>
|
||||
|
|
|
|||
|
|
@ -166,6 +166,11 @@ function SchemaView(props: {
|
|||
});
|
||||
};
|
||||
|
||||
const schemas = useFragment(
|
||||
SchemaView_SchemaFragment,
|
||||
target.latestSchemaVersion?.schemas?.edges?.map(edge => edge.node),
|
||||
);
|
||||
|
||||
const isDistributed =
|
||||
project.type === ProjectType.Federation || project.type === ProjectType.Stitching;
|
||||
|
||||
|
|
@ -178,10 +183,6 @@ function SchemaView(props: {
|
|||
return noSchema;
|
||||
}
|
||||
|
||||
const schemas = useFragment(
|
||||
SchemaView_SchemaFragment,
|
||||
target.latestSchemaVersion?.schemas?.edges?.map(edge => edge.node),
|
||||
);
|
||||
const compositeSchemas = schemas?.filter(isCompositeSchema) as CompositeSchema[];
|
||||
const singleSchema = schemas?.filter(schema => !isCompositeSchema(schema))[0] as
|
||||
| SingleSchema
|
||||
|
|
|
|||
Loading…
Reference in a new issue