mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-29 03:53:14 +03:00
Add fun to the Wasp AI queue
This commit is contained in:
parent
3be17bdc9e
commit
0f4be2a6d5
95
wasp-ai/src/client/components/WaitingRoomContent.jsx
Normal file
95
wasp-ai/src/client/components/WaitingRoomContent.jsx
Normal file
@ -0,0 +1,95 @@
|
||||
import { availableColors } from "./Color";
|
||||
import Tilt from "react-parallax-tilt";
|
||||
|
||||
export function WaitingRoomContent() {
|
||||
return (
|
||||
<>
|
||||
<header className="relative mb-4 bg-slate-50 p-8 rounded-xl text-gray-500">
|
||||
<p className="text-gray-500">Hello there! 🤖</p>
|
||||
<br />
|
||||
<p>
|
||||
Thanks for trying out the AI web App Generator. Looks like it might be
|
||||
a couple of minutes before we can start building your app. In the
|
||||
meantime, you can take a look at some of our already generated apps
|
||||
below.
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
Come back to this page to check the status of your app at any time!
|
||||
</p>
|
||||
</header>
|
||||
<h3 class="text-xl font-semibold mb-4 text-slate-800">
|
||||
Examples of already generated apps:
|
||||
</h3>
|
||||
<div className="flex flex-row items-stretch gap-x-10">
|
||||
{showcaseSamples.map((sample) => (
|
||||
<ShowcaseCard {...sample} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const showcaseSamples = [
|
||||
{
|
||||
name: "TodoApp",
|
||||
specimenURL:
|
||||
"https://magic-app-generator.wasp-lang.dev/result/07ed440a-3155-4969-b3f5-2031fb1f622f",
|
||||
description:
|
||||
"A simple todo app with one main page that lists all the tasks." +
|
||||
" User can create new tasks by providing their description, toggle existing ones, or edit their description." +
|
||||
" User owns tasks. User can only see and edit their own tasks. Tasks are saved in the database.",
|
||||
color: availableColors.find((color) => color.name === "sky"),
|
||||
complexity: "simple",
|
||||
},
|
||||
{
|
||||
name: "MyPlants",
|
||||
specimenURL:
|
||||
"https://magic-app-generator.wasp-lang.dev/result/3bb5dca2-f134-4f96-89d6-0812deab6e0c",
|
||||
description:
|
||||
"An app where user can track their plants and their watering schedule." +
|
||||
"\nHome page lists all of the user's plants. For each plant, number of days left until it needs to be watered is shown, as well as the plant's name, and a 'Water' button." +
|
||||
" Home page also has a 'Add plant' button, that takes you to a new page where user can create a new plant." +
|
||||
"\nWhen creating a new plant, user should give it a name and specify how often it needs to be watered (in the number of days)." +
|
||||
" Plants are saved in the database. User can access only their own plants.",
|
||||
color: availableColors.find((color) => color.name === "green"),
|
||||
complexity: "moderate",
|
||||
},
|
||||
];
|
||||
|
||||
export function ShowcaseCard({ name, specimenURL, description, color }) {
|
||||
return (
|
||||
<Tilt
|
||||
tiltMaxAngleX={10}
|
||||
tiltMaxAngleY={10}
|
||||
perspective={1000}
|
||||
transitionSpeed={1000}
|
||||
scale={1.05}
|
||||
>
|
||||
<div
|
||||
className="h-full bg-slate-50 p-8 rounded-xl mt-2 flex flex-col items-center cursor-pointer hover:shadow-lg transition-all"
|
||||
onClick={() => {
|
||||
window.open(specimenURL, "_blank");
|
||||
}}
|
||||
>
|
||||
<div className="idea">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h4 className="text-xl font-semibold text-slate-700 mb-1">
|
||||
<span
|
||||
className="inline-block w-4 h-4 rounded-full mr-2"
|
||||
style={{ backgroundColor: color.color }}
|
||||
></span>
|
||||
{name}
|
||||
</h4>
|
||||
<button className="button sm gray">See how it looks</button>
|
||||
</div>
|
||||
<div className="text-base leading-relaxed text-slate-500 line-clamp-[10]">
|
||||
{description.split("\n").map((str) => (
|
||||
<p>{str}</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tilt>
|
||||
);
|
||||
}
|
@ -97,7 +97,7 @@ const MainPage = () => {
|
||||
id="appName"
|
||||
required
|
||||
type="text"
|
||||
placeholder="e.g. TodoApp or FlowerShop"
|
||||
placeholder="e.g. TodoApp or MyPlants"
|
||||
value={appName}
|
||||
onChange={(e) => setAppNameIfValid(e.target.value)}
|
||||
disabled={currentStatus.status === "inProgress"}
|
||||
@ -111,7 +111,7 @@ const MainPage = () => {
|
||||
id="appDesc"
|
||||
required
|
||||
placeholder="Describe your web app in a couple of sentences (check examples below).
|
||||
Based on it, our AI code agent will then generate a full stack web app in Wasp, React, NodeJS and Prisma for you!"
|
||||
Based on your description, our AI code agent will generate a full-stack web app in Wasp, React, NodeJS and Prisma!"
|
||||
value={appDesc}
|
||||
rows="5"
|
||||
cols="50"
|
||||
|
@ -11,6 +11,7 @@ import { useHistory } from "react-router-dom";
|
||||
import { Loader } from "../components/Loader";
|
||||
import { MyDialog } from "../components/Dialog";
|
||||
import { Logs } from "../components/Logs";
|
||||
import { WaitingRoomContent } from "../components/WaitingRoomContent";
|
||||
import { Header } from "../components/Header";
|
||||
import { Faq } from "../components/Faq";
|
||||
import {
|
||||
@ -42,20 +43,6 @@ export const ResultPage = () => {
|
||||
const [isMobileFileBrowserOpen, setIsMobileFileBrowserOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const backendStatusToPillStatus = {
|
||||
pending: "pending",
|
||||
"in-progress": "inProgress",
|
||||
success: "success",
|
||||
failure: "error",
|
||||
cancelled: "cancelled",
|
||||
};
|
||||
const backendStatusToPillText = {
|
||||
pending: "In the queue",
|
||||
"in-progress": "Generating app",
|
||||
success: "Finished",
|
||||
failure: "There was an error",
|
||||
cancelled: "The generation was cancelled",
|
||||
};
|
||||
if (!appGenerationResult?.project) {
|
||||
return;
|
||||
}
|
||||
@ -67,10 +54,7 @@ export const ResultPage = () => {
|
||||
) {
|
||||
setGenerationDone(true);
|
||||
}
|
||||
setCurrentStatus({
|
||||
status: backendStatusToPillStatus[appGenerationResult.project.status],
|
||||
message: backendStatusToPillText[appGenerationResult.project.status],
|
||||
});
|
||||
setCurrentStatus(getStatusPillData(appGenerationResult));
|
||||
}, [appGenerationResult, isError]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -230,8 +214,11 @@ export const ResultPage = () => {
|
||||
</header>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Logs logs={logs} status={currentStatus.status} onRetry={retry} />
|
||||
{currentStatus.status === "pending" &&
|
||||
appGenerationResult.numberOfProjectsAheadInQueue > 1 && (
|
||||
<WaitingRoomContent />
|
||||
)}
|
||||
|
||||
{interestingFilePaths.length > 0 && (
|
||||
<>
|
||||
@ -313,12 +300,52 @@ export const ResultPage = () => {
|
||||
</>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<Faq/>
|
||||
<Faq />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function getStatusPillData(generationResult) {
|
||||
const backendStatusToPillStatus = {
|
||||
pending: "pending",
|
||||
"in-progress": "inProgress",
|
||||
success: "success",
|
||||
failure: "error",
|
||||
cancelled: "cancelled",
|
||||
};
|
||||
|
||||
const queueCardinalNumber = getCardinalNumber(
|
||||
generationResult.numberOfProjectsAheadInQueue
|
||||
);
|
||||
|
||||
const backendStatusToPillText = {
|
||||
pending: `${queueCardinalNumber} in the queue`,
|
||||
"in-progress": "Generating app",
|
||||
success: "Finished",
|
||||
failure: "There was an error",
|
||||
cancelled: "The generation was cancelled",
|
||||
};
|
||||
|
||||
return {
|
||||
status: backendStatusToPillStatus[generationResult.project.status],
|
||||
message: backendStatusToPillText[generationResult.project.status],
|
||||
};
|
||||
}
|
||||
|
||||
function getCardinalNumber(number) {
|
||||
const lastDigit = number % 10;
|
||||
if (lastDigit === 1) {
|
||||
return `${number}st`;
|
||||
} else if (lastDigit === 2) {
|
||||
return `${number}nd`;
|
||||
} else if (lastDigit === 3) {
|
||||
return `${number}rd`;
|
||||
} else {
|
||||
return `${number}th`;
|
||||
}
|
||||
}
|
||||
|
||||
export default function RunTheAppModal({ disabled, onDownloadZip }) {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
return (
|
||||
@ -346,7 +373,7 @@ export default function RunTheAppModal({ disabled, onDownloadZip }) {
|
||||
<div className="mt-6 space-y-6">
|
||||
<p className="text-base leading-relaxed text-gray-500">
|
||||
Congrats, your full-stack web app is ready! 🎉
|
||||
<br/>
|
||||
<br />
|
||||
App is implemented in{" "}
|
||||
<a
|
||||
href="https://wasp-lang.dev"
|
||||
@ -356,7 +383,8 @@ export default function RunTheAppModal({ disabled, onDownloadZip }) {
|
||||
>
|
||||
Wasp
|
||||
</a>{" "}
|
||||
web framework, using React, Node.js and Prisma, and is completely full-stack (frontend + backend + database).
|
||||
web framework, using React, Node.js and Prisma, and is completely
|
||||
full-stack (frontend + backend + database).
|
||||
</p>
|
||||
|
||||
<WarningAboutAI />
|
||||
@ -371,7 +399,10 @@ export default function RunTheAppModal({ disabled, onDownloadZip }) {
|
||||
curl -sSL https://get.wasp-lang.dev/installer.sh | sh
|
||||
</pre>
|
||||
|
||||
<h2 className="font-bold mt-4"> 2. Download the generated app files and unzip them: </h2>
|
||||
<h2 className="font-bold mt-4">
|
||||
{" "}
|
||||
2. Download the generated app files and unzip them:{" "}
|
||||
</h2>
|
||||
<button
|
||||
className="button flex items-center justify-center gap-1 w-full mt-2"
|
||||
onClick={onDownloadZip}
|
||||
@ -380,11 +411,15 @@ export default function RunTheAppModal({ disabled, onDownloadZip }) {
|
||||
<PiDownloadDuotone className="inline-block" size={20} />
|
||||
</button>
|
||||
|
||||
<h2 className="font-bold mt-4"> 3. Position into the unzipped dir and run the app: </h2>
|
||||
<h2 className="font-bold mt-4">
|
||||
{" "}
|
||||
3. Position into the unzipped dir and run the app:{" "}
|
||||
</h2>
|
||||
<pre className="mt-2 bg-slate-800 p-4 rounded-lg text-sm text-slate-200">
|
||||
cd {"<your-app-name>"}
|
||||
<br />
|
||||
wasp db migrate-dev <span className="text-slate-400"># init the db</span>
|
||||
wasp db migrate-dev{" "}
|
||||
<span className="text-slate-400"># init the db</span>
|
||||
<br />
|
||||
wasp start
|
||||
</pre>
|
||||
@ -419,8 +454,9 @@ function WarningAboutAI() {
|
||||
<p className="text-sm leading-5 font-medium">⚠️ Experimental tech</p>
|
||||
<div className="mt-2 text-sm leading-5">
|
||||
<p>
|
||||
Since this is a GPT generated app, it might contain some mistakes, proportional to how complex the app is.
|
||||
If there are some in your app, check out {" "}
|
||||
Since this is a GPT generated app, it might contain some mistakes,
|
||||
proportional to how complex the app is. If there are some in your
|
||||
app, check out{" "}
|
||||
<a
|
||||
href="https://wasp-lang.dev/docs"
|
||||
target="_blank"
|
||||
@ -428,8 +464,9 @@ function WarningAboutAI() {
|
||||
className="font-medium text-yellow-600 hover:text-yellow-500 transition ease-in-out duration-150 underline"
|
||||
>
|
||||
Wasp docs
|
||||
</a>
|
||||
{" "}for help while fixing them, and also feel free to reach out to us on{" "}
|
||||
</a>{" "}
|
||||
for help while fixing them, and also feel free to reach out to us
|
||||
on{" "}
|
||||
<a
|
||||
href="https://discord.gg/rzdnErX"
|
||||
target="_blank"
|
||||
|
@ -66,8 +66,20 @@ export const getAppGenerationResult = (async (args, context) => {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const numberOfProjectsAheadInQueue =
|
||||
(await Project.count({
|
||||
where: {
|
||||
createdAt: {
|
||||
lt: project.createdAt,
|
||||
},
|
||||
status: "pending",
|
||||
},
|
||||
})) + 1;
|
||||
|
||||
return {
|
||||
project,
|
||||
numberOfProjectsAheadInQueue,
|
||||
};
|
||||
} catch (e) {
|
||||
throw new HttpError(404, "App not found.");
|
||||
|
Loading…
Reference in New Issue
Block a user