Skip to content

Commit

Permalink
hive/app: strict null checks (#220)
Browse files Browse the repository at this point in the history
* fix src/lib/urql-cache.ts

* fix src/lib/mixpanel.ts

* fix: src/lib/hooks/use-route-selector.ts

* fix: src/lib/access/common.ts

* fix: src/components/v2/time-ago.tsx

* fix: src/components/v2/skeleton.tsx

* fix: src/components/v2/modals/delete-organization.tsx (verified functionality)

* fix: src/components/v2/modals/create-target.tsx

* fix: src/components/v2/modals/create-project.tsx

* fix: src/components/v2/modals/create-organization.tsx

* fix: src/components/v2/modals/create-channel.tsx

* fix: src/components/v2/modals/create-alert.tsx

* fix: packages/web/app/src/components/v2/dropdown.tsx

* fix: src/components/v2/data-wrapper.tsx

* fix: src/components/target/operations/Filters.tsx

* fix: pages/[orgId]/[projectId]/[targetId]/history.tsx

* fix: src/components/project/Switcher.tsx

* fix: src/components/organization/Switcher.tsx

* fix: src/components/organization/Permissions.tsx

* fix: pages/settings.tsx

* fix: packages/web/app/src/components/v2/tabs.tsx

* fix: packages/web/app/src/components/v2/avatar.tsx

* fix: packages/web/app/pages/join/[inviteCode].tsx

* fix: packages/web/app/pages/[orgId]/index.tsx

* fix: pages/[orgId]/members.tsx

* fix: pages/[orgId]/settings.tsx

* fix:  pages/[orgId]/subscription/index.tsx

* fix: pages/api/github/callback.ts

* fix: pages/api/github/connect/[orgId].ts

* fix: src/components/common/Navigation.tsx

* fix: src/components/common/UserSettings.tsx

* fix: src/components/common/LoadingAPI.tsx

* fix: packages/web/app/src/components/common/Feedback.tsx

* fix: packages/web/app/src/components/common/DataWrapper.tsx

* fix: src/components/admin/AdminStats.tsx

* fix: pages/index.tsx

* fix: pages/api/proxy.ts

* fix: src/components/auth/AuthProvider.tsx

* fix: pages/[orgId]/[projectId]/index.tsx

* fix:  pages/[orgId]/[projectId]/settings.tsx

* fix: src/components/organization/billing/Billing.tsx

* fix: src/components/organization/billing/BillingPaymentMethod.tsx

* fix: src/components/organization/billing/BillingPlanPicker.tsx

* fix: src/components/organization/billing/InvoicesList.tsx

* fix: pages/[orgId]/_new.tsx

* fix: pages/[orgId]/subscription/manage.tsx

* fix: pages/[orgId]/[projectId]/[targetId]/settings.tsx

* fix: src/components/target/operations/List.tsx

* fix: src/components/target/operations/Stats.tsx

* fix: src/components/target/Switcher.tsx

* fix: pages/[orgId]/[projectId]/[targetId]/index.tsx

* fix: src/components/organization/billing/PlanSummary.tsx

* fix: src/components/v2/modals/create-access-token.tsx

* fix: src/components/v2/header.tsx

* fix: src/components/layouts/project.tsx

* fix: src/components/layouts/target.tsx

* fix: src/components/layouts/organization.tsx

* fix: src/components/v2/activities.tsx

* fix: enable rule

* strict mode

* NOTE: This file should not be edited 😁

* run prettier
  • Loading branch information
n1ru4l committed Jul 8, 2022
1 parent 6ddcf90 commit f6ccd01
Show file tree
Hide file tree
Showing 71 changed files with 564 additions and 435 deletions.
9 changes: 8 additions & 1 deletion packages/web/app/modules.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable import/no-unused-modules */
declare module 'node-crisp-api';
declare module 'tailwindcss/colors';

Expand All @@ -8,3 +7,11 @@ declare module '@n1ru4l/react-time-ago' {
children: (args: { value: string }) => React.ReactElement;
}): React.ReactElement;
}

declare namespace NodeJS {
export interface ProcessEnv {
APP_BASE_URL: string;
GITHUB_APP_NAME: string;
GRAPHQL_ENDPOINT: string;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const ChangesBlock = ({
}: {
changes: SchemaChangeFieldsFragment[];
criticality: CriticalityLevel;
}): ReactElement => {
}): ReactElement | null => {
const filteredChanges = changes.filter(c => c.criticality === criticality);

if (!filteredChanges.length) {
Expand All @@ -71,7 +71,7 @@ const ChangesBlock = ({
);
};

const DiffView = ({ view, versionId }: { view: 'sdl' | 'list'; versionId: string }): ReactElement => {
const DiffView = ({ view, versionId }: { view: 'sdl' | 'list'; versionId: string }): ReactElement | null => {
const router = useRouteSelector();
const [compareQuery] = useQuery({
query: CompareDocument,
Expand Down Expand Up @@ -183,7 +183,10 @@ const ListPage = ({
<Button
variant="link"
onClick={() => {
onLoadMore(versions.nodes.at(-1).id);
const id = versions.nodes.at(-1)?.id;
if (typeof id == 'string') {
onLoadMore(id);
}
}}
>
Load more
Expand Down Expand Up @@ -265,14 +268,13 @@ export default function HistoryPage(): ReactElement {
},
requestPolicy: 'cache-and-network',
});
const latestVersionId = latestSchemaQuery.data?.target.latestSchemaVersion?.id;
const versionId = router.versionId || latestVersionId;
const versionId = router.versionId ?? latestSchemaQuery.data?.target?.latestSchemaVersion?.id;

return (
<>
<Title title="History" />
<TargetLayout value="history" className={latestVersionId ? 'flex h-full items-stretch gap-x-5' : ''}>
{() => (latestVersionId ? <Page versionId={versionId} /> : noSchema)}
<TargetLayout value="history" className={versionId ? 'flex h-full items-stretch gap-x-5' : ''}>
{() => (versionId ? <Page versionId={versionId} /> : noSchema)}
</TargetLayout>
</>
);
Expand Down
92 changes: 49 additions & 43 deletions packages/web/app/pages/[orgId]/[projectId]/[targetId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const SchemaServiceName = ({
}

return (
<Editable defaultValue={schema.service} isDisabled={mutation.fetching} onSubmit={submit}>
<Editable defaultValue={schema.service ?? ''} isDisabled={mutation.fetching} onSubmit={submit}>
<EditablePreview />
<EditableInput />
</Editable>
Expand All @@ -123,7 +123,7 @@ const Schemas = ({
filterService?: string;
}): ReactElement => {
if (project.type === ProjectType.Single) {
return <GraphQLBlock className="mb-6" sdl={schemas[0].source} url={schemas[0].url} />;
return <GraphQLBlock className="mb-6" sdl={schemas[0].source} url={schemas[0]?.url ?? ''} />;
}

return (
Expand All @@ -140,7 +140,7 @@ const Schemas = ({
<GraphQLBlock
key={schema.id}
sdl={schema.source}
url={schema.url}
url={schema.url ?? ''}
title={
<SchemaServiceName
version={version}
Expand Down Expand Up @@ -178,7 +178,7 @@ const SyncSchemaButton = ({
target: TargetFieldsFragment;
project: ProjectFieldsFragment;
organization: OrganizationFieldsFragment;
}): ReactElement => {
}): ReactElement | null => {
const [status, setStatus] = useState<'idle' | 'error' | 'success'>('idle');
const [mutation, mutate] = useMutation(SchemaSyncButton_SchemaSyncCDN);

Expand Down Expand Up @@ -230,9 +230,9 @@ function SchemaView({
organization: OrganizationFieldsFragment;
project: ProjectFieldsFragment;
target: TargetFieldsFragment;
}): ReactElement {
const [filterService, setFilterService] = useState<string | null>(null);
const [term, setTerm] = useState<string | null>(null);
}): ReactElement | null {
const [filterService, setFilterService] = useState<string>('');
const [term, setTerm] = useState<string>('');
const debouncedFilter = useDebouncedCallback((value: string) => {
setFilterService(value);
}, 500);
Expand Down Expand Up @@ -268,45 +268,51 @@ function SchemaView({
redirect: false,
});

if (!query.data?.target?.latestSchemaVersion?.schemas.nodes.length) {
return noSchema;
}

return (
<DataWrapper query={query}>
{() => (
<>
<div className="mb-5 flex flex-row items-center justify-between">
<div className="font-light text-gray-500">The latest published schema.</div>
<div className="flex flex-row items-center gap-4">
{isDistributed && (
<form
onSubmit={event => {
event.preventDefault();
}}
>
<InputGroup size="sm" variant="filled">
<Input type="text" placeholder="Find service" value={term} onChange={handleChange} />
<InputRightElement>
<IconButton aria-label="Reset" size="xs" variant="ghost" onClick={reset} icon={<VscClose />} />
</InputRightElement>
</InputGroup>
</form>
)}
{canManage && <MarkAsValid version={query.data.target.latestSchemaVersion} />}
{canManage && <SyncSchemaButton target={target} project={project} organization={organization} />}
{query => {
if (!query.data?.target?.latestSchemaVersion?.schemas.nodes.length) {
return noSchema;
}

return (
<>
<div className="mb-5 flex flex-row items-center justify-between">
<div className="font-light text-gray-500">The latest published schema.</div>
<div className="flex flex-row items-center gap-4">
{isDistributed && (
<form
onSubmit={event => {
event.preventDefault();
}}
>
<InputGroup size="sm" variant="filled">
<Input type="text" placeholder="Find service" value={term} onChange={handleChange} />
<InputRightElement>
<IconButton aria-label="Reset" size="xs" variant="ghost" onClick={reset} icon={<VscClose />} />
</InputRightElement>
</InputGroup>
</form>
)}
{canManage ? (
<>
<MarkAsValid version={query.data.target.latestSchemaVersion} />{' '}
<SyncSchemaButton target={target} project={project} organization={organization} />
</>
) : null}
</div>
</div>
</div>
<Schemas
organization={organization}
project={project}
target={query.data.target}
filterService={filterService}
version={query.data.target.latestSchemaVersion.id}
schemas={query.data.target.latestSchemaVersion.schemas.nodes ?? []}
/>
</>
)}
<Schemas
organization={organization}
project={project}
target={query.data.target}
filterService={filterService}
version={query.data.target.latestSchemaVersion.id}
schemas={query.data.target.latestSchemaVersion.schemas.nodes ?? []}
/>
</>
);
}}
</DataWrapper>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const OperationsView = ({
return { from, to };
}, [selectedPeriod]);

const updatePeriod = useCallback<ComponentProps<'select'>['onChange']>(
const updatePeriod = useCallback<Exclude<ComponentProps<'select'>['onChange'], undefined | null>>(
ev => {
router.push(`${href}?period=${ev.target.value}`);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ const ExtendBaseSchema = (props: { baseSchema: string }): ReactElement => {
options={{ readOnly: mutation.fetching }}
value={baseSchema}
height={300}
onChange={setBaseSchema}
onChange={value => setBaseSchema(value ?? '')}
/>
{mutation.data?.updateBaseSchema.error && (
<div className="text-red-500">{mutation.data.updateBaseSchema.error.message}</div>
Expand Down Expand Up @@ -504,7 +504,7 @@ const Page = ({ target, organization }: { target: TargetFieldsFragment; organiza
</form>
{touched.name && (errors.name || mutation.error) && (
<div className="mt-2 text-red-500">
{errors.name ?? mutation.error.graphQLErrors[0]?.message ?? mutation.error.message}
{errors.name ?? mutation.error?.graphQLErrors[0]?.message ?? mutation.error?.message}
</div>
)}
{mutation.data?.updateTargetName.error?.inputErrors?.name && (
Expand All @@ -516,7 +516,7 @@ const Page = ({ target, organization }: { target: TargetFieldsFragment; organiza

<ConditionalBreakingChanges />

{target && <ExtendBaseSchema baseSchema={target.baseSchema} />}
{target?.baseSchema?.length ? <ExtendBaseSchema baseSchema={target.baseSchema} /> : null}

{canDelete && (
<Card>
Expand Down
2 changes: 1 addition & 1 deletion packages/web/app/pages/[orgId]/[projectId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TargetQuery, TargetsDocument, VersionsDocument } from '@/graphql';
import { useClipboard } from '@/lib/hooks/use-clipboard';
import { useRouteSelector } from '@/lib/hooks/use-route-selector';

const TargetCard = ({ target }: { target: TargetQuery['target'] }): ReactElement => {
const TargetCard = ({ target }: { target: Exclude<TargetQuery['target'], null | undefined> }): ReactElement => {
const router = useRouteSelector();
const copyToClipboard = useClipboard();
const [versionsQuery] = useQuery({
Expand Down
12 changes: 5 additions & 7 deletions packages/web/app/pages/[orgId]/[projectId]/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ const GitHubIntegration = ({ gitRepository }: { gitRepository: string }): ReactE
return <Spinner />;
}

const hasGitHubIntegration = integrationQuery.data?.hasGitHubIntegration === true;

if (hasGitHubIntegration) {
if (integrationQuery.data?.gitHubIntegration) {
return (
<>
<form className="flex gap-x-2" onSubmit={handleSubmit}>
Expand All @@ -82,15 +80,15 @@ const GitHubIntegration = ({ gitRepository }: { gitRepository: string }): ReactE
value={values.gitRepository}
onChange={handleChange}
onBlur={handleBlur}
isInvalid={touched.gitRepository && Boolean(errors.gitRepository)}
isInvalid={!!touched.gitRepository && Boolean(errors.gitRepository)}
/>
<Button type="submit" variant="primary" size="large" className="px-10" disabled={isSubmitting}>
Save
</Button>
</form>
{touched.gitRepository && (errors.gitRepository || mutation.error) && (
<div className="mt-2 text-red-500">
{errors.gitRepository ?? mutation.error.graphQLErrors[0]?.message ?? mutation.error.message}
{errors.gitRepository ?? mutation.error?.graphQLErrors[0]?.message ?? mutation.error?.message}
</div>
)}
{mutation.data?.updateProjectGitRepository.error && (
Expand Down Expand Up @@ -195,7 +193,7 @@ const Page = ({
</form>
{touched.name && (errors.name || mutation.error) && (
<div className="mt-2 text-red-500">
{errors.name ?? mutation.error.graphQLErrors[0]?.message ?? mutation.error.message}
{errors.name ?? mutation.error?.graphQLErrors[0]?.message ?? mutation.error?.message}
</div>
)}
{mutation.data?.updateProjectName.error && (
Expand All @@ -206,7 +204,7 @@ const Page = ({
<Card>
<Heading className="mb-2">Git Repository</Heading>
<p className="mb-3 font-light text-gray-300">Connect the project with your Git repository</p>
<GitHubIntegration gitRepository={project?.gitRepository} />
{project?.gitRepository ? <GitHubIntegration gitRepository={project.gitRepository} /> : null}
</Card>

{canAccessProject(ProjectAccessScope.Delete, organization.me) && (
Expand Down
2 changes: 1 addition & 1 deletion packages/web/app/pages/[orgId]/_new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const NewPage: FC = () => {
const wrapperRef = useRef<HTMLDivElement>(null);

useEffect(() => {
wrapperRef.current.scrollIntoView({
wrapperRef.current?.scrollIntoView({
behavior: 'smooth',
});
}, [page]);
Expand Down
20 changes: 9 additions & 11 deletions packages/web/app/pages/[orgId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ export default function ProjectsPage(): ReactElement {
},
});

const isLoading = projectsWithTargetsQuery.fetching;

return (
<>
<Title title="Projects" />
Expand All @@ -104,9 +102,15 @@ export default function ProjectsPage(): ReactElement {
<>
<div className="grow">
<Heading className="mb-4">Active Projects</Heading>
{isLoading || projectsWithTargetsQuery.data.projects.total !== 0 ? (
{projectsWithTargetsQuery.data?.projects.total === 0 ? (
<EmptyList
title="Hive is waiting for your first project"
description='You can create a project by clicking the "Create Project" button'
docsUrl={`${process.env.NEXT_PUBLIC_DOCS_LINK}/get-started/projects`}
/>
) : (
<div className="grid grid-cols-2 gap-5">
{isLoading
{projectsWithTargetsQuery.fetching
? [1, 2].map(key => (
<Card key={key}>
<div className="flex gap-x-2">
Expand All @@ -120,16 +124,10 @@ export default function ProjectsPage(): ReactElement {
<Skeleton visible className="h-7" />
</Card>
))
: projectsWithTargetsQuery.data.projects.nodes.map(project => (
: projectsWithTargetsQuery.data?.projects.nodes.map(project => (
<ProjectCard key={project.id} project={project} />
))}
</div>
) : (
<EmptyList
title="Hive is waiting for your first project"
description='You can create a project by clicking the "Create Project" button'
docsUrl={`${process.env.NEXT_PUBLIC_DOCS_LINK}/get-started/projects`}
/>
)}
</div>

Expand Down
12 changes: 6 additions & 6 deletions packages/web/app/pages/[orgId]/members.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ const Page = ({ organization }: { organization: OrganizationFieldsFragment }) =>
});
}, [mutate, notify, router.organizationId]);

const org = organizationMembersQuery.data?.organization.organization;
const isPersonal = org && org.type === OrganizationType.Personal;
const org = organizationMembersQuery.data?.organization?.organization;
const isPersonal = org?.type === OrganizationType.Personal;
const members = org?.members.nodes;

useEffect(() => {
Expand All @@ -84,7 +84,7 @@ const Page = ({ organization }: { organization: OrganizationFieldsFragment }) =>
if (!org || isPersonal) return null;

const me = meQuery.data?.me;
const selectedMember = selectedMemberId && members.find(node => node.id === selectedMemberId);
const selectedMember = selectedMemberId ? members?.find(node => node.id === selectedMemberId) : null;

return (
<>
Expand Down Expand Up @@ -124,11 +124,11 @@ const Page = ({ organization }: { organization: OrganizationFieldsFragment }) =>
<TrashIcon />
</Button>
</div>
{members.map(node => {
{members?.map(node => {
const IconToUse = authProviderIcons[node.user.provider] ?? KeyIcon;

const isOwner = node.id === org.owner.id;
const isMe = node.id === me.id;
const isMe = node.id === me?.id;
const isDisabled = isOwner || isMe;

return (
Expand All @@ -140,7 +140,7 @@ const Page = ({ organization }: { organization: OrganizationFieldsFragment }) =>
checked={checked.includes(node.id)}
disabled={isDisabled}
/>
<Avatar src={isMe ? user.picture : ''} fallback={node.user.displayName[0]} shape="circle" />
<Avatar src={isMe ? user?.picture : ''} fallback={node.user.displayName[0]} shape="circle" />
<div className="grow overflow-hidden">
<h3 className="line-clamp-1 font-medium">{node.user.displayName}</h3>
<h4 className="text-sm font-light text-gray-500">{node.user.email}</h4>
Expand Down
Loading

0 comments on commit f6ccd01

Please sign in to comment.