mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2025-12-21 08:40:10 -06:00
refactor(frontend): extract spinner and loading components (#13)
This commit is contained in:
@@ -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';
|
||||
|
||||
13
frontend/app/src/components/ui/loading.tsx
Normal file
13
frontend/app/src/components/ui/loading.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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} />;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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} />;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user