From ecbc4d0dc1e68507e335250d9c4c0699c3664376 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Wed, 25 May 2022 16:30:34 +0200 Subject: [PATCH] chore: enable noImplicitAny TypeScript rule --- packages/web/app/modules.d.ts | 9 +++++++++ .../[projectId]/[targetId]/history.tsx | 15 ++++++-------- packages/web/app/pages/[orgId]/members.tsx | 12 ++++++----- packages/web/app/pages/_app.tsx | 2 +- packages/web/app/pages/_document.tsx | 4 ++-- packages/web/app/pages/_error.tsx | 10 +++++++++- packages/web/app/pages/api/proxy.ts | 2 +- .../app/src/components/auth/AuthProvider.tsx | 2 +- .../app/src/components/common/Navigation.tsx | 2 +- .../web/app/src/components/common/Page.tsx | 4 ++-- .../src/components/organization/Switcher.tsx | 5 ++++- .../billing/BillingPlanPicker.tsx | 12 +++++------ .../components/target/operations/Stats.tsx | 16 ++++++++++----- .../web/app/src/components/v2/activities.tsx | 4 ++-- .../components/v2/modals/connect-schema.tsx | 18 ++++++++--------- packages/web/app/src/components/v2/table.tsx | 12 +++++------ packages/web/app/src/components/v2/tag.tsx | 20 ++++++++----------- packages/web/app/src/lib/gtag.ts | 4 ++-- packages/web/app/src/lib/urql.ts | 2 +- packages/web/app/tsconfig.json | 1 + 20 files changed, 88 insertions(+), 68 deletions(-) diff --git a/packages/web/app/modules.d.ts b/packages/web/app/modules.d.ts index 248e4aba2a..eb8a12a35e 100644 --- a/packages/web/app/modules.d.ts +++ b/packages/web/app/modules.d.ts @@ -1 +1,10 @@ +/* eslint-disable import/no-unused-modules */ declare module 'node-crisp-api'; +declare module 'tailwindcss/colors'; + +declare module '@n1ru4l/react-time-ago' { + export function TimeAgo(props: { + date: Date; + children: (args: { value: string }) => React.ReactElement; + }): React.ReactElement; +} diff --git a/packages/web/app/pages/[orgId]/[projectId]/[targetId]/history.tsx b/packages/web/app/pages/[orgId]/[projectId]/[targetId]/history.tsx index ad5ad28461..404b9d1ebf 100644 --- a/packages/web/app/pages/[orgId]/[projectId]/[targetId]/history.tsx +++ b/packages/web/app/pages/[orgId]/[projectId]/[targetId]/history.tsx @@ -39,6 +39,11 @@ const titleMap: Record = { Dangerous: 'Dangerous Changes', }; +const criticalityLevelMapping = { + [CriticalityLevel.Safe]: 'text-emerald-400', + [CriticalityLevel.Dangerous]: 'text-yellow-400', +} as Record; + const ChangesBlock = ({ changes, criticality, @@ -57,15 +62,7 @@ const ChangesBlock = ({

{titleMap[criticality]}

    {filteredChanges.map((change, key) => ( -
  • +
  • {labelize(change.message)}
  • ))} diff --git a/packages/web/app/pages/[orgId]/members.tsx b/packages/web/app/pages/[orgId]/members.tsx index d55503e207..737afbd2f4 100644 --- a/packages/web/app/pages/[orgId]/members.tsx +++ b/packages/web/app/pages/[orgId]/members.tsx @@ -1,4 +1,5 @@ import { ReactElement, useCallback, useEffect, useState } from 'react'; +import { IconProps } from '@chakra-ui/react'; import { useMutation, useQuery } from 'urql'; import { useUser } from '@/components/auth/AuthProvider'; @@ -18,6 +19,11 @@ import { OrganizationAccessScope, useOrganizationAccess } from '@/lib/access/org import { useNotifications } from '@/lib/hooks/use-notifications'; import { useRouteSelector } from '@/lib/hooks/use-route-selector'; +const authProviderIcons = { + [AuthProvider.Github]: GitHubIcon, + [AuthProvider.Google]: GoogleIcon, +} as Record | undefined>; + const Page = ({ organization }: { organization: OrganizationFieldsFragment }) => { useOrganizationAccess({ scope: OrganizationAccessScope.Members, @@ -119,11 +125,7 @@ const Page = ({ organization }: { organization: OrganizationFieldsFragment }) => {members.map(node => { - const IconToUse = - { - [AuthProvider.Github]: GitHubIcon, - [AuthProvider.Google]: GoogleIcon, - }[node.user.provider] || KeyIcon; + const IconToUse = authProviderIcons[node.user.provider] ?? KeyIcon; const isOwner = node.id === org.owner.id; const isMe = node.id === me.id; diff --git a/packages/web/app/pages/_app.tsx b/packages/web/app/pages/_app.tsx index 23266584e6..8352cb322c 100644 --- a/packages/web/app/pages/_app.tsx +++ b/packages/web/app/pages/_app.tsx @@ -32,7 +32,7 @@ if (process.env.NODE_ENV === 'development' && 'window' in globalThis) { function App({ Component, pageProps }: AppProps): ReactElement { useEffect(() => { - const handleRouteChange = url => { + const handleRouteChange = (url: string) => { gtag.pageview(url); const orgId = Router.query.orgId as string; diff --git a/packages/web/app/pages/_document.tsx b/packages/web/app/pages/_document.tsx index 74fa0bfd2c..ae8c373dc1 100644 --- a/packages/web/app/pages/_document.tsx +++ b/packages/web/app/pages/_document.tsx @@ -1,9 +1,9 @@ import 'regenerator-runtime/runtime'; -import Document, { Html, Head, Main, NextScript } from 'next/document'; +import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'; import { extractCritical } from '@emotion/server'; export default class MyDocument extends Document { - static async getInitialProps(ctx) { + static async getInitialProps(ctx: DocumentContext) { const initialProps = await Document.getInitialProps(ctx); const page = await ctx.renderPage(); const styles = extractCritical(page.html); diff --git a/packages/web/app/pages/_error.tsx b/packages/web/app/pages/_error.tsx index 849bbfe18a..d6b7160886 100644 --- a/packages/web/app/pages/_error.tsx +++ b/packages/web/app/pages/_error.tsx @@ -3,7 +3,15 @@ import type { NextPageContext } from 'next'; import * as Sentry from '@sentry/nextjs'; -const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => { +const MyError = ({ + statusCode, + hasGetInitialPropsRun, + err, +}: { + statusCode: number; + hasGetInitialPropsRun: boolean; + err: Error; +}) => { if (!hasGetInitialPropsRun && err) { // getInitialProps is not called in case of // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass diff --git a/packages/web/app/pages/api/proxy.ts b/packages/web/app/pages/api/proxy.ts index b0749b0605..8f660176e6 100644 --- a/packages/web/app/pages/api/proxy.ts +++ b/packages/web/app/pages/api/proxy.ts @@ -111,7 +111,7 @@ async function graphql(req: NextApiRequest, res: NextApiResponse) { if (isStream) { graphqlSpan.setHttpStatus(response.status); - const headers = {}; + const headers: Record = {}; response.headers.forEach((value, key) => { headers[key] = value; diff --git a/packages/web/app/src/components/auth/AuthProvider.tsx b/packages/web/app/src/components/auth/AuthProvider.tsx index a0571aec9f..ae865d2f4d 100644 --- a/packages/web/app/src/components/auth/AuthProvider.tsx +++ b/packages/web/app/src/components/auth/AuthProvider.tsx @@ -20,7 +20,7 @@ declare global { } function identifyOnCrisp(user: UserProfile): void { - const crisp = globalThis.$crisp; + const crisp = globalThis.window.$crisp; if (crisp) { pushIfNotEmpty(crisp, 'user:email', user.email); pushIfNotEmpty(crisp, 'user:nickname', user.name || user.nickname); diff --git a/packages/web/app/src/components/common/Navigation.tsx b/packages/web/app/src/components/common/Navigation.tsx index ad8da82ec6..fc07152e66 100644 --- a/packages/web/app/src/components/common/Navigation.tsx +++ b/packages/web/app/src/components/common/Navigation.tsx @@ -63,7 +63,7 @@ const NavigationContext = React.createContext<{ export const useNavigation = () => React.useContext(NavigationContext); -export const NavigationProvider = ({ children }) => { +export const NavigationProvider = ({ children }: { children: React.ReactNode }) => { const [state, setState] = React.useState({}); const [visible, setVisible] = React.useState(true); const show = React.useCallback(() => setVisible(true), [setVisible]); diff --git a/packages/web/app/src/components/common/Page.tsx b/packages/web/app/src/components/common/Page.tsx index 1167181d98..36356a20b0 100644 --- a/packages/web/app/src/components/common/Page.tsx +++ b/packages/web/app/src/components/common/Page.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactElement } from 'react'; import tw, { styled } from 'twin.macro'; import Link from 'next/link'; import { FiTarget } from 'react-icons/fi'; @@ -39,7 +39,7 @@ const MenuLink = styled.a(({ active }: { active?: boolean }) => [ const Menu = { Root: tw.ul`flex flex-col px-2 py-4`, - Title: ({ children, icon }) => { + Title: ({ children, icon }: { children: string; icon: ReactElement }) => { return (
  • diff --git a/packages/web/app/src/components/organization/Switcher.tsx b/packages/web/app/src/components/organization/Switcher.tsx index bdcc0d02f2..ece6ad216d 100644 --- a/packages/web/app/src/components/organization/Switcher.tsx +++ b/packages/web/app/src/components/organization/Switcher.tsx @@ -42,7 +42,10 @@ export const OrganizationSwitcher: React.FC<{ }; } - const menu = { + const menu: { + personal: Array<{ key: string; label: string }>; + organizations: Array<{ key: string; label: string }>; + } = { personal: [], organizations: [], }; diff --git a/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx b/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx index 25fc6dc114..15b6142017 100644 --- a/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx +++ b/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx @@ -121,6 +121,11 @@ const Plan = (plan: { ); }; +const billingPlanLookUpMap = { + [BillingPlanType.Hobby]: 'Free', + [BillingPlanType.Enterprise]: 'Contact Us', +} as Record; + export const BillingPlanPicker = ({ value, activePlan, @@ -139,12 +144,7 @@ export const BillingPlanPicker = ({ { if (!data.length) { return createEmptySeries({ interval, period }); } @@ -72,7 +72,7 @@ function fullSeries( } // Instead of creating a new array, we could move things around but this is easier - const newData = []; + const newData: Array<[string, number]> = []; for (let i = 0; i < data.length; i++) { const current = data[i]; @@ -100,6 +100,14 @@ function fullSeries( return newData; } +function times(amount: number, f: (index: number) => T) { + const items: Array = []; + for (const i = 0; i < amount; amount++) { + items[i] = f(i); + } + return items; +} + function createEmptySeries({ interval, period, @@ -114,9 +122,7 @@ function createEmptySeries({ const endAt = new Date(period.to).getTime(); const steps = Math.floor((endAt - startAt) / interval); - return Array(steps) - .fill(0) - .map((_, i) => [new Date(startAt + i * interval).toISOString(), 0]); + return times(steps, i => [new Date(startAt + i * interval).toISOString(), 0]); } function useChartStyles() { diff --git a/packages/web/app/src/components/v2/activities.tsx b/packages/web/app/src/components/v2/activities.tsx index 641caab16f..51b0a4f6b6 100644 --- a/packages/web/app/src/components/v2/activities.tsx +++ b/packages/web/app/src/components/v2/activities.tsx @@ -1,4 +1,4 @@ -import { ReactElement } from 'react'; +import React, { ReactElement } from 'react'; import NextLink from 'next/link'; import { useQuery } from 'urql'; @@ -197,7 +197,7 @@ export const getActivity = ( } }; -export const Activities = (props): ReactElement => { +export const Activities = (props: React.ComponentProps<'div'>): ReactElement => { const router = useRouteSelector(); const [organizationActivitiesQuery] = useQuery({ query: organizationActivitiesDocument, diff --git a/packages/web/app/src/components/v2/modals/connect-schema.tsx b/packages/web/app/src/components/v2/modals/connect-schema.tsx index 4a7f5079d4..eb7f8669a3 100644 --- a/packages/web/app/src/components/v2/modals/connect-schema.tsx +++ b/packages/web/app/src/components/v2/modals/connect-schema.tsx @@ -6,6 +6,11 @@ import { Button, CopyValue, Heading, Link, Modal, Tag } from '@/components/v2'; import { CreateCdnTokenDocument, ProjectDocument, ProjectType } from '@/graphql'; import { useRouteSelector } from '@/lib/hooks/use-route-selector'; +const taxonomy = { + [ProjectType.Federation]: 'supergraph schema', + [ProjectType.Stitching]: 'services', +} as Record; + export const ConnectSchemaModal = ({ isOpen, toggleModalOpen, @@ -56,11 +61,7 @@ export const ConnectSchemaModal = ({ Generating access...

    Hive is now generating an authentication token and an URL you can use to fetch your{' '} - {{ - [ProjectType.Federation]: 'supergraph schema', - [ProjectType.Stitching]: 'services', - }[project.type] || 'schema'} - . + {taxonomy[project.type] ?? 'schema'}.

    )} @@ -69,11 +70,8 @@ export const ConnectSchemaModal = ({ <>

    With high-availability and multi-zone CDN service based on Cloudflare, Hive allows you to access the - {{ - [ProjectType.Federation]: 'supergraph', - [ProjectType.Stitching]: 'list of services', - }[project.type] || 'schema'}{' '} - of your API, through a secured external service, that's always up regardless of Hive. + {taxonomy[project.type] ?? 'schema'} of your API, through a secured external service, that's always up + regardless of Hive.

    You can use the following endpoint: diff --git a/packages/web/app/src/components/v2/table.tsx b/packages/web/app/src/components/v2/table.tsx index 50745e60c5..01466d455e 100644 --- a/packages/web/app/src/components/v2/table.tsx +++ b/packages/web/app/src/components/v2/table.tsx @@ -1,15 +1,15 @@ import { ReactElement } from 'react'; import clsx from 'clsx'; -type Column = { key: string; align?: 'right'; width?: 'auto' }; +type Column = { key: TKey; align?: 'right'; width?: 'auto' }; -export const Table = ({ +export function Table({ dataSource, columns, }: { - dataSource?: { id: string }[]; - columns: Column[] | ReadonlyArray; -}): ReactElement => { + dataSource?: Array<{ id: string } & Record>; + columns: Array> | ReadonlyArray>; +}): ReactElement { return ( @@ -32,4 +32,4 @@ export const Table = ({
    ); -}; +} diff --git a/packages/web/app/src/components/v2/tag.tsx b/packages/web/app/src/components/v2/tag.tsx index 5973253941..33caf28499 100644 --- a/packages/web/app/src/components/v2/tag.tsx +++ b/packages/web/app/src/components/v2/tag.tsx @@ -1,27 +1,23 @@ import { ReactElement, ReactNode } from 'react'; import clsx from 'clsx'; +const colors = { + green: 'bg-green-500/10 text-green-500', + yellow: 'bg-yellow-500/10 text-yellow-500', + gray: 'bg-gray-500/10 text-gray-500', +} as const; + export const Tag = ({ children, color = 'gray', className, }: { - color?: 'red' | 'green' | 'yellow' | 'gray'; + color?: 'green' | 'yellow' | 'gray'; className?: string; children: ReactNode; }): ReactElement => { return ( - + {children} ); diff --git a/packages/web/app/src/lib/gtag.ts b/packages/web/app/src/lib/gtag.ts index 25ce12c8e9..ae593d2a25 100644 --- a/packages/web/app/src/lib/gtag.ts +++ b/packages/web/app/src/lib/gtag.ts @@ -1,7 +1,7 @@ import type { NextWebVitalsMetric } from 'next/app'; import { GA_TRACKING_ID } from '@/constants'; -export const pageview = (url): void => { +export const pageview = (url: string): void => { if (!GA_TRACKING_ID) { return; } @@ -11,7 +11,7 @@ export const pageview = (url): void => { }; // https://developers.google.com/analytics/devguides/collection/gtagjs/events -export const event = ({ action, category, label, value }): void => { +export const event = ({ action, category, label, value }: any): void => { if (!GA_TRACKING_ID) { return; } diff --git a/packages/web/app/src/lib/urql.ts b/packages/web/app/src/lib/urql.ts index 493ca6ab83..0a6cff53dc 100644 --- a/packages/web/app/src/lib/urql.ts +++ b/packages/web/app/src/lib/urql.ts @@ -5,7 +5,7 @@ import { captureException } from '@sentry/nextjs'; import { Mutation } from './urql-cache'; import { networkStatusExchange } from './urql-exchanges/state'; -const noKey = () => null; +const noKey = (): null => null; const SERVER_BASE_PATH = '/api/proxy'; diff --git a/packages/web/app/tsconfig.json b/packages/web/app/tsconfig.json index cd16d3204c..23dc8bf797 100644 --- a/packages/web/app/tsconfig.json +++ b/packages/web/app/tsconfig.json @@ -11,6 +11,7 @@ "noImplicitThis": true, "strictBindCallApply": true, "alwaysStrict": true, + "noImplicitAny": true, "forceConsistentCasingInFileNames": true, "noEmit": true,