Skip to content
This repository was archived by the owner on Jan 31, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions apps/hub/src/components/command-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
CommandLoading,
cn,
} from "@rivet-gg/components";
import { useIsFetching } from "@tanstack/react-query";
import { useMatchRoute } from "@tanstack/react-router";
import {
type KeyboardEventHandler,
Expand All @@ -25,6 +26,7 @@ import { EnvironmentCommandPanelPage } from "./command-panel/command-panel-page/
import { GroupCommandPanelPage } from "./command-panel/command-panel-page/group-command-panel-page";
import { IndexCommandPanelPage } from "./command-panel/command-panel-page/index-command-panel-page";
import { ProjectCommandPanelPage } from "./command-panel/command-panel-page/project-command-panel-page";
import { ShimmerLine } from "./shimmer-line";

export function CommandPanel() {
const [isOpen, setOpen] = useState(false);
Expand Down Expand Up @@ -125,6 +127,11 @@ export function CommandPanel() {
[pages.length, search],
);

const isLoading =
useIsFetching({
predicate: (query) => !query.queryKey.includes("watch"),
}) > 0;

return (
<>
<Button
Expand All @@ -143,6 +150,7 @@ export function CommandPanel() {
<CommandDialog
commandProps={{
onKeyDown: handleKeyDown,
shouldFilter: !isLoading,
}}
open={isOpen}
onOpenChange={setOpen}
Expand All @@ -154,11 +162,13 @@ export function CommandPanel() {
placeholder="Type a command or search..."
/>
<CommandPanelNavigationProvider
isLoading={isLoading}
onClose={handleClose}
onChangePage={handlePageChange}
>
<CommandList>
<Suspense fallback={<CommandLoading>Hang on…</CommandLoading>}>
{isLoading ? <ShimmerLine className="-top-[1px]" /> : null}
<CommandEmpty>No results found.</CommandEmpty>
{!page ? <IndexCommandPanelPage /> : null}
{page?.key === "group" ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ export function CommandPanelNavigationProvider({
children,
onClose,
onChangePage,
isLoading,
}: {
children: ReactNode;
onClose: () => void;
onChangePage: (page: CommandPanelPage) => void;
isLoading: boolean;
}) {
const routerNavigate = useNavigate();

Expand All @@ -73,9 +75,16 @@ export function CommandPanelNavigationProvider({
[onClose, routerNavigate],
);

const handleChangePage = (page: CommandPanelPage) => {
if (isLoading) {
return;
}
onChangePage(page);
};

return (
<CommandPanelNavigationContext.Provider
value={{ changePage: onChangePage, close: onClose, navigate }}
value={{ changePage: handleChangePage, close: onClose, navigate }}
>
{children}
</CommandPanelNavigationContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function EnvironmentCommandPanelPage({
},
] = useSuspenseQueries({
queries: [
projectQueryOptions(projectNameId),
projectQueryOptions(projectId),
projectMetadataQueryOptions({ projectId, environmentId }),
],
});
Expand Down
2 changes: 2 additions & 0 deletions apps/hub/src/components/error-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const ErrorComponent = ({
<Button
onClick={() => {
router.invalidate();
queryClient.resetQueries();
queryClient.invalidateQueries();
reset?.();
}}
>
Expand Down
51 changes: 4 additions & 47 deletions apps/hub/src/components/get-started.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ import {
faChevronRight,
faCircleNodes,
faCode,
faCog,
faDiagramNext,
faGamepadAlt,
faHandWave,
faSparkles,
faToolbox,
faUpRightAndDownLeftFromCenter,
faWifiSlash,
} from "@rivet-gg/icons";
Expand Down Expand Up @@ -70,7 +67,7 @@ export function GetStarted() {
<Button
onClick={() => {
document
.getElementById("getting-started")
.getElementById("examples")
?.scrollIntoView({ behavior: "smooth" });
}}
endIcon={<Icon icon={faChevronDoubleDown} />}
Expand Down Expand Up @@ -109,49 +106,7 @@ export function GetStarted() {
</div>
</CardContent>
</Card>
<Card
id="getting-started"
asChild
className="max-w-xl w-full mx-auto my-6 scroll-mt-28"
>
<motion.div>
<CardHeader>
<CardTitle>Getting Started</CardTitle>
<CardDescription>
Learn how Rivet works and how you can customize it to suit your
needs.
</CardDescription>
</CardHeader>
<CardContent>
<motion.div
variants={containerVariants}
initial="hidden"
whileInView="show"
className="grid md:grid-cols-3 gap-4"
>
<ExampleLink
href="examples"
title="Intro to Rivet"
size="md"
icon={faHandWave}
/>
<ExampleLink
href="examples"
title="Initial Setup"
size="md"
icon={faToolbox}
/>
<ExampleLink
href="examples"
title="Configuration"
size="md"
icon={faCog}
/>
</motion.div>
</CardContent>
</motion.div>
</Card>
<Card asChild className="max-w-xl w-full mx-auto my-6">
<Card id="examples" asChild className="max-w-xl w-full mx-auto my-6">
<motion.div>
<CardHeader>
<CardTitle>Examples</CardTitle>
Expand All @@ -165,6 +120,7 @@ export function GetStarted() {
variants={containerVariants}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
className="grid md:grid-cols-3 gap-4"
>
<ExampleLink
Expand Down Expand Up @@ -214,6 +170,7 @@ export function GetStarted() {
variants={containerVariants}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
className="grid md:grid-cols-2 gap-4"
>
<ExampleLink
Expand Down
7 changes: 2 additions & 5 deletions apps/hub/src/components/header/header-route-loader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useRouterState } from "@tanstack/react-router";
import { ShimmerLine } from "../shimmer-line";

export function HeaderRouteLoader() {
const isLoading = useRouterState({
Expand All @@ -8,9 +9,5 @@ export function HeaderRouteLoader() {
if (!isLoading) {
return null;
}
return (
<div className="animate-in fade-in absolute inset-x-0 -bottom-1 w-full overflow-hidden">
<div className="animate-bounce-x from-secondary/0 via-primary to-secondary/0 relative -bottom-px h-1 bg-gradient-to-r" />
</div>
);
return <ShimmerLine className="-bottom-1" />;
}
35 changes: 29 additions & 6 deletions apps/hub/src/components/intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import {
CardTitle,
Skeleton,
} from "@rivet-gg/components";
import * as Sentry from "@sentry/react";
import { useSuspenseQuery } from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import { Navigate, useNavigate } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Suspense, useState } from "react";

Expand All @@ -27,7 +28,12 @@ enum Step {
ChoosePlan = 2,
}

export function Intro({ initialStep }: { initialStep?: Step }) {
interface IntroProps {
initialStep?: Step;
initialProjectName?: string;
}

export function Intro({ initialStep, initialProjectName }: IntroProps) {
const { mutateAsync, data: createdGroupResponse } = useGroupCreateMutation();
const { mutateAsync: createProject, data: projectCreationData } =
useProjectCreateMutation();
Expand All @@ -38,14 +44,13 @@ export function Intro({ initialStep }: { initialStep?: Step }) {
data
.flatMap((team) => team.projects)
.find((project) => project.gameId === projectCreationData?.gameId) ||
// biome-ignore lint/style/noNonNullAssertion: at this point user should have at least one project
data.find((team) => team.projects.length > 0)!.projects[0]!;
data.find((team) => team.projects.length > 0)?.projects[0];

const [step, setStep] = useState<Step>(
() => initialStep ?? (!project ? Step.CreateGroup : Step.CreateProject),
);

const groupId = createdGroupResponse?.groupId || project.developer.groupId;
const groupId = createdGroupResponse?.groupId || project?.developer.groupId;

const navigate = useNavigate();

Expand All @@ -60,7 +65,10 @@ export function Intro({ initialStep }: { initialStep?: Step }) {
exit={{ opacity: 0 }}
>
<GroupCreateProjectForm.Form
defaultValues={{ slug: "", name: "" }}
defaultValues={{
slug: "",
name: initialProjectName ?? "",
}}
onSubmit={async (values) => {
await createProject({
displayName: values.name,
Expand All @@ -80,6 +88,12 @@ export function Intro({ initialStep }: { initialStep?: Step }) {
</CardHeader>
<CardContent>
<div className="grid grid-cols-[auto_auto_min-content] items-center gap-4 ">
{initialProjectName ? (
<GroupCreateProjectForm.SetValue
name="name"
value={initialProjectName}
/>
) : null}
<GroupCreateProjectForm.Name className="contents space-y-0" />
<GroupCreateProjectForm.Slug className="contents space-y-0" />
<GroupCreateProjectForm.Submit
Expand All @@ -98,6 +112,15 @@ export function Intro({ initialStep }: { initialStep?: Step }) {
}

if (step === Step.ChoosePlan) {
if (!groupId || !project) {
// At this point those values should be defined, if not, we should redirect to the home page
// It's unlikely that this will happen, but it's better to be safe than sorry
Sentry.captureMessage(
"Group or project not defined in Intro component",
"fatal",
);
return <Navigate to="/" replace />;
}
return (
<Suspense
fallback={
Expand Down
17 changes: 17 additions & 0 deletions apps/hub/src/components/shimmer-line.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { cn } from "@rivet-gg/components";

interface ShimmerLineProps {
className?: string;
}
export const ShimmerLine = ({ className }: ShimmerLineProps) => {
return (
<div
className={cn(
"animate-in fade-in absolute inset-x-0 w-full overflow-hidden",
className,
)}
>
<div className="animate-bounce-x from-secondary/0 via-primary to-secondary/0 relative -bottom-px h-1 bg-gradient-to-r" />
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export type SubmitHandler = (
form: UseFormReturn<FormValues>,
) => Promise<void>;

const { Form, Submit } = createSchemaForm(formSchema);
export { Form, Submit };
const { Form, Submit, SetValue } = createSchemaForm(formSchema);
export { Form, Submit, SetValue };

export const Name = ({ className }: { className?: string }) => {
const { control } = useFormContext<FormValues>();
Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/domains/project/queries/backend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Event = z.infer<typeof Event>;

export const BackendEvent = z
.object({
dispatchEnvironment: z.string(),
dispatchEnvironment: z.string().optional(),
event: Event,
eventTimestamp: z.string(),
logs: z
Expand Down
8 changes: 6 additions & 2 deletions apps/hub/src/routes/_authenticated/_layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { LayoutGroup, motion } from "framer-motion";
import { z } from "zod";

function IndexRoute() {
const { initialStep } = Route.useSearch();
const { initialStep, project_name: projectName } = Route.useSearch();
return (
<>
<OnboardingBackground />
Expand All @@ -34,7 +34,10 @@ function IndexRoute() {
animate={{ opacity: 1, transition: { delay: 0.5 } }}
>
<LayoutGroup>
<Intro initialStep={initialStep} />
<Intro
initialProjectName={projectName}
initialStep={initialStep}
/>
</LayoutGroup>
</motion.div>
</div>
Expand All @@ -46,6 +49,7 @@ function IndexRoute() {
const searchSchema = z.object({
newbie: z.coerce.boolean().optional(),
initialStep: z.coerce.number().optional(),
project_name: z.coerce.string().optional(),
});

export const Route = createFileRoute("/_authenticated/_layout/")({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ function ProjectActorsRoute() {
if (data.length === 0) {
return (
<div className="w-full h-full flex flex-col justify-center">
<Icon icon={faActors} className="text-6xl mx-auto my-4" />
<h3 className="text-center font-bold text-xl max-w-md mb-2 mx-auto">
Deploy your first Actor
</h3>
<p className="text-center text-muted-foreground max-w-sm mx-auto">
Install Rivet to get started or use an existing template to get
started.
</p>
<div className="flex flex-col justify-center my-8">
<Icon icon={faActors} className="text-6xl mx-auto my-4" />
<h3 className="text-center font-bold text-xl max-w-md mb-2 mx-auto">
Deploy your first Actor
</h3>
<p className="text-center text-muted-foreground max-w-sm mx-auto">
Install Rivet to get started or use an existing template to get
started.
</p>
</div>
<GetStarted />
</div>
);
Expand Down
5 changes: 3 additions & 2 deletions packages/components/src/lib/create-schema-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ export const createSchemaForm = <Schema extends z.ZodSchema>(
name: Path;
value: PathValue<z.TypeOf<Schema>, Path>;
}) => {
const { setValue } = useFormContext<z.TypeOf<Schema>>();
const { setValue, reset } = useFormContext<z.TypeOf<Schema>>();
useEffect(() => {
setValue(props.name, props.value, { shouldDirty: true });
}, [props.name, setValue, props.value]);
reset({}, { keepDirty: true, keepValues: true, keepDirtyValues: true });
}, [props.name, setValue, reset, props.value]);
return null;
},
useContext: () => useFormContext<z.TypeOf<Schema>>(),
Expand Down
Loading