refactor(frontend): extract spinner and loading components (#13)

This commit is contained in:
Luca Steeb
2023-12-21 12:43:55 +07:00
committed by GitHub
parent 46a9d66d30
commit a67c1d6657
15 changed files with 46 additions and 93 deletions

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import { useRef, useState, useMemo } from 'react';
import { scaleTime, scaleLinear } from '@visx/scale';
import appleStock, { AppleStock } from '@visx/mock-data/lib/mocks/appleStock';

View File

@@ -0,0 +1,13 @@
import { Icons } from '@/components/ui/icons.tsx';
export function Spinner() {
return <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />;
}
export function Loading() {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Spinner />
</div>
);
}

View File

@@ -2,11 +2,10 @@ import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Icons } from '@/components/ui/icons';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Spinner } from '@/components/ui/loading.tsx';
const schema = z.object({
email: z.string().email('Invalid email address'),
@@ -73,9 +72,7 @@ export function UserLoginForm({ className, ...props }: UserLoginFormProps) {
)}
</div>
<Button disabled={props.isLoading}>
{props.isLoading && (
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
)}
{props.isLoading && <Spinner />}
Sign In
</Button>
</div>

View File

@@ -2,11 +2,10 @@ import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Icons } from '@/components/ui/icons';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Spinner } from '@/components/ui/loading.tsx';
const schema = z.object({
name: z.string().min(3, 'Name must be at least 3 characters long'),
@@ -96,9 +95,7 @@ export function UserRegisterForm({
)}
</div>
<Button disabled={props.isLoading}>
{props.isLoading && (
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
)}
{props.isLoading && <Spinner />}
Create Account
</Button>
</div>

View File

@@ -7,7 +7,7 @@ import {
import api from '@/lib/api';
import queryClient from '@/query-client';
import { useContextFromParent } from '@/lib/outlet';
import { Icons } from '@/components/ui/icons';
import { Loading } from '@/components/ui/loading.tsx';
const authMiddleware = async (currentUrl: string) => {
try {
@@ -69,11 +69,7 @@ export default function Auth() {
});
if (!user || !memberships) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
return <Outlet context={ctx} />;

View File

@@ -20,7 +20,6 @@ import api, {
import invariant from 'tiny-invariant';
import { useAtom } from 'jotai';
import { currTenantAtom } from '@/lib/atoms';
import { Icons } from '@/components/ui/icons';
import { FilterOption } from '@/components/molecules/data-table/data-table-toolbar';
import {
Dialog,
@@ -38,6 +37,7 @@ import {
ArrowPathRoundedSquareIcon,
} from '@heroicons/react/24/outline';
import { useApiError } from '@/lib/hooks';
import { Loading } from '@/components/ui/loading.tsx';
export default function Events() {
return (
@@ -171,11 +171,7 @@ function EventsTable() {
// }, [listEventsQuery.data?.pagination]);
if (listEventsQuery.isLoading) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
const tableColumns = columns({
@@ -285,11 +281,7 @@ function EventDataSection({ event }: { event: Event }) {
});
if (getEventDataQuery.isLoading || !getEventDataQuery.data) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
const eventData = getEventDataQuery.data;

View File

@@ -48,7 +48,7 @@ import {
} from '@/lib/outlet';
import { useAtom } from 'jotai';
import { currTenantAtom } from '@/lib/atoms';
import { Icons } from '@/components/ui/icons';
import { Loading, Spinner } from '@/components/ui/loading.tsx';
function Main() {
const { user, memberships } = useOutletContext<
@@ -70,11 +70,7 @@ function Main() {
});
if (!user || !memberships) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
return (
@@ -231,7 +227,7 @@ function TenantSwitcher({ className, memberships }: TenantSwitcherProps) {
const [open, setOpen] = React.useState(false);
if (!currTenant) {
return <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />;
return <Spinner />;
}
return (

View File

@@ -1,4 +1,3 @@
import { Icons } from '@/components/ui/icons';
import { Separator } from '@/components/ui/separator';
import { queries } from '@/lib/api';
import { currTenantAtom } from '@/lib/atoms';
@@ -11,6 +10,7 @@ import { ServerStackIcon } from '@heroicons/react/24/outline';
import { Button } from '@/components/ui/button';
import { DataTable } from '@/components/molecules/data-table/data-table';
import { columns } from './components/step-runs-columns';
import { Loading } from '@/components/ui/loading.tsx';
export default function ExpandedWorkflowRun() {
const [tenant] = useAtom(currTenantAtom);
@@ -24,11 +24,7 @@ export default function ExpandedWorkflowRun() {
});
if (workerQuery.isLoading || !workerQuery.data) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
const worker = workerQuery.data;

View File

@@ -4,10 +4,10 @@ import { queries } from '@/lib/api';
import invariant from 'tiny-invariant';
import { useAtom } from 'jotai';
import { currTenantAtom } from '@/lib/atoms';
import { Icons } from '@/components/ui/icons';
import { relativeDate } from '@/lib/utils';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Loading } from '@/components/ui/loading.tsx';
export default function Workers() {
const [tenant] = useAtom(currTenantAtom);
@@ -18,11 +18,7 @@ export default function Workers() {
});
if (listWorkersQuery.isLoading || !listWorkersQuery.data?.rows) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
return (

View File

@@ -1,4 +1,3 @@
import { Icons } from '@/components/ui/icons';
import { Separator } from '@/components/ui/separator';
import { JobRun, StepRun, StepRunStatus, queries, Event } from '@/lib/api';
import CronPrettifier from 'cronstrue';
@@ -22,6 +21,7 @@ import { RunStatus } from '../components/run-statuses';
import { ColumnDef } from '@tanstack/react-table';
import { useState } from 'react';
import { Code } from '@/components/ui/code';
import { Loading } from '@/components/ui/loading.tsx';
export default function ExpandedWorkflowRun() {
const [expandedStepRuns, setExpandedStepRuns] = useState<string[]>([]);
@@ -37,11 +37,7 @@ export default function ExpandedWorkflowRun() {
});
if (runQuery.isLoading || !runQuery.data) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
const run = runQuery.data;
@@ -266,8 +262,7 @@ function StepStatusSection({ stepRun }: { stepRun: StepRun }) {
}`;
break;
case 'PREVIOUS_STEP_TIMED_OUT':
statusText =
'This step was cancelled because the previous step timed out';
statusText = `This step was cancelled because the previous step timed out`;
break;
default:
break;
@@ -324,11 +319,7 @@ function EventDataSection({ event }: { event: Event }) {
});
if (getEventDataQuery.isLoading || !getEventDataQuery.data) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
const eventData = getEventDataQuery.data;

View File

@@ -1,4 +1,4 @@
import { DataTable } from '../../../components/molecules/data-table/data-table';
import { DataTable } from '@/components/molecules/data-table/data-table.tsx';
import { columns } from './components/workflow-runs-columns';
import { Separator } from '@/components/ui/separator';
import { useMemo, useState } from 'react';
@@ -11,8 +11,8 @@ import { useQuery } from '@tanstack/react-query';
import invariant from 'tiny-invariant';
import { useAtom } from 'jotai';
import { currTenantAtom } from '@/lib/atoms';
import { Icons } from '@/components/ui/icons';
import { queries } from '@/lib/api';
import { Loading } from '@/components/ui/loading.tsx';
export default function WorkflowRuns() {
return (
@@ -56,11 +56,7 @@ function WorkflowRunsTable() {
});
if (listWorkflowRunsQuery.isLoading) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
return (

View File

@@ -1,5 +1,4 @@
import { DataTable } from '@/components/molecules/data-table/data-table';
import { Icons } from '@/components/ui/icons';
import { Separator } from '@/components/ui/separator';
import api, { Workflow, queries } from '@/lib/api';
import { currTenantAtom } from '@/lib/atoms';
@@ -19,6 +18,7 @@ import { Code } from '@/components/ui/code';
import { Badge } from '@/components/ui/badge';
import { relativeDate } from '@/lib/utils';
import { Square3Stack3DIcon } from '@heroicons/react/24/outline';
import { Loading } from '@/components/ui/loading.tsx';
export async function loader({
params,
@@ -37,8 +37,7 @@ export async function loader({
throw error;
} else if (isAxiosError(error)) {
// TODO: handle error better
redirect('/unauthorized');
throw new Error('unauthorized');
throw redirect('/unauthorized');
}
}
@@ -49,11 +48,7 @@ export default function ExpandedWorkflow() {
const workflow = useLoaderData() as Awaited<ReturnType<typeof loader>>;
if (!workflow) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
return (
@@ -116,11 +111,7 @@ function WorkflowDefinition() {
getWorkflowDefinitionQuery.isLoading ||
!getWorkflowDefinitionQuery.data
) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
const workflowDefinition = getWorkflowDefinitionQuery.data;

View File

@@ -5,7 +5,7 @@ import { queries } from '@/lib/api';
import invariant from 'tiny-invariant';
import { useAtom } from 'jotai';
import { currTenantAtom } from '@/lib/atoms';
import { Icons } from '@/components/ui/icons';
import { Loading } from '@/components/ui/loading.tsx';
export default function Workflows() {
const [tenant] = useAtom(currTenantAtom);
@@ -16,11 +16,7 @@ export default function Workflows() {
});
if (listWorkflowsQuery.isLoading) {
return (
<div className="flex flex-row flex-1 w-full h-full">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
</div>
);
return <Loading />;
}
return (

View File

@@ -2,8 +2,7 @@ import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Icons } from '@/components/ui/icons';
import { Spinner } from '@/components/ui/loading.tsx';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
@@ -127,9 +126,7 @@ export function TenantCreateForm({
)}
</div>
<Button disabled={props.isLoading || !isSlugSuffixed}>
{props.isLoading && (
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
)}
{props.isLoading && <Spinner />}
Create
</Button>
</div>

View File

@@ -1,4 +1,4 @@
import React from 'react';
import { FC } from 'react';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const routes = [
@@ -140,7 +140,7 @@ const routes = [
const router = createBrowserRouter(routes, { basename: '/' });
const Router: React.FC = () => {
const Router: FC = () => {
return <RouterProvider router={router} />;
};