Fixes various bugs in the web app

This commit is contained in:
Mihovil Ilakovac 2023-07-05 16:07:20 +02:00
parent 023478498c
commit 03c2f685fb
8 changed files with 182 additions and 148 deletions

View File

@ -26,7 +26,11 @@ body {
}
input,
textarea {
@apply relative w-full cursor-default rounded-lg bg-white py-3 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-sky-300;
@apply relative w-full rounded-lg bg-white py-3 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-sky-300;
}
input[type="text"],
textarea {
appearance: none;
-webkit-appearance: none;
}

View File

@ -1,9 +1,13 @@
import { LoginForm } from "@wasp/auth/forms/Login";
import { Header } from "../components/Header";
export function LoginPage() {
return (
<div className="big-box">
<LoginForm />
</div>
<>
<Header />
<div className="big-box">
<LoginForm />
</div>
</>
);
}

View File

@ -107,7 +107,6 @@ const MainPage = () => {
value={appName}
onChange={(e) => setAppNameIfValid(e.target.value)}
disabled={currentStatus.status === "inProgress"}
className="cursor-pointer"
/>
</div>
<div>
@ -124,7 +123,6 @@ Based on it, our AI code agent will then generate a full stack web app in Wasp,
cols="50"
onChange={(e) => setAppDesc(e.target.value)}
disabled={currentStatus.status === "inProgress"}
className="cursor-pointer"
/>
</div>
<div className="grid md:grid-cols-2 gap-3">

View File

@ -10,6 +10,7 @@ import ParentSize from "@visx/responsive/lib/components/ParentSize";
import { poolOfExampleIdeas } from "../examples";
import logout from "@wasp/auth/logout";
import { WaspIcon } from "../components/WaspIcon";
import { Header } from "../components/Header";
export function Stats() {
const [filterOutExampleApps, setFilterOutExampleApps] = useState(false);
@ -101,150 +102,154 @@ export function Stats() {
}
return (
<div className="big-box">
<div className="flex justify-between items-center mb-4">
<h1 className="text-3xl font-semibold text-slate-800">Stats</h1>
<div>
<button className="button sm" onClick={logout}>
Logout
</button>
</div>
</div>
{isLoading && <p>Loading...</p>}
{error && <p>Error: {error.message}</p>}
{stats && stats.projects.length === 0 && (
<p className="text-sm text-slate-500">No projects created yet.</p>
)}
{stats && stats.projects.length > 0 && (
<>
<p className="text-sm text-slate-500 mb-2">
Number of projects created in the last 24 hours:{" "}
</p>
<div style={{ height: 300, width: "100%" }} className="mb-4">
<ParentSize>
{({ width, height }) => (
<BarChart
projects={filteredStats}
width={width}
height={height}
/>
)}
</ParentSize>
<>
<Header />
<div className="big-box">
<div className="flex justify-between items-center mb-4">
<h1 className="text-3xl font-semibold text-slate-800">Stats</h1>
<div>
<button className="button sm" onClick={logout}>
Logout
</button>
</div>
</div>
<div className="py-2 flex justify-between items-center">
<div className="flex gap-3">
<div className="flex items-center mb-4">
<input
id="filter"
type="checkbox"
checked={filterOutExampleApps}
onChange={(event) =>
setFilterOutExampleApps(event.target.checked)
}
className="w-4 h-4 text-sky-600 bg-gray-100 border-gray-300 rounded focus:ring-sky-500"
/>
<label
htmlFor="filter"
className="ml-2 text-sm font-medium text-gray-900"
>
Filter out example apps
</label>
</div>
<div className="flex items-center mb-4">
<input
id="default-checkbox"
type="checkbox"
checked={filterOutKnownUsers}
onChange={(event) =>
setFilterOutKnownUsers(event.target.checked)
}
className="w-4 h-4 text-sky-600 bg-gray-100 border-gray-300 rounded focus:ring-sky-500"
/>
<label
htmlFor="default-checkbox"
className="ml-2 text-sm font-medium text-gray-900"
>
Filter out known users
</label>
</div>
{isLoading && <p>Loading...</p>}
{error && <p>Error: {error.message}</p>}
{stats && stats.projects.length === 0 && (
<p className="text-sm text-slate-500">No projects created yet.</p>
)}
{stats && stats.projects.length > 0 && (
<>
<p className="text-sm text-slate-500 mb-2">
Number of projects created in the last 24 hours:{" "}
</p>
<div style={{ height: 300, width: "100%" }} className="mb-4">
<ParentSize>
{({ width, height }) => (
<BarChart
projects={filteredStats}
width={width}
height={height}
/>
)}
</ParentSize>
</div>
<p className="text-sm text-slate-500">
Number of displayed apps: {filteredStats.length}
</p>
</div>
<div className="py-2 flex justify-between items-center">
<div className="flex gap-3">
<div className="flex items-center mb-4">
<input
id="filter"
type="checkbox"
checked={filterOutExampleApps}
onChange={(event) =>
setFilterOutExampleApps(event.target.checked)
}
className="w-4 h-4 text-sky-600 bg-gray-100 border-gray-300 rounded focus:ring-sky-500"
/>
<label
htmlFor="filter"
className="ml-2 text-sm font-medium text-gray-900"
>
Filter out example apps
</label>
</div>
<div className="flex items-center mb-4">
<input
id="default-checkbox"
type="checkbox"
checked={filterOutKnownUsers}
onChange={(event) =>
setFilterOutKnownUsers(event.target.checked)
}
className="w-4 h-4 text-sky-600 bg-gray-100 border-gray-300 rounded focus:ring-sky-500"
/>
<label
htmlFor="default-checkbox"
className="ml-2 text-sm font-medium text-gray-900"
>
Filter out known users
</label>
</div>
</div>
<div className="relative overflow-x-auto shadow-md sm:rounded-lg">
<table className="w-full text-sm text-left text-slate-500">
<thead className="text-xs text-slate-700 uppercase bg-gray-50">
<tr>
<th scope="col" className="px-6 py-3">
App Name
</th>
<th scope="col" className="px-6 py-3">
Status
</th>
<th scope="col" className="px-6 py-3">
Created At
</th>
<th scope="col" className="px-6 py-3">
Time in Queue &rarr; Build
</th>
<th scope="col" className="px-6 py-3"></th>
</tr>
</thead>
<tbody>
{filteredStats.map((stat) => (
<tr className="bg-white border-b" key={stat.id}>
<th
scope="row"
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap flex items-center gap-2"
>
<Color value={getColorValue(stat.primaryColor)} />{" "}
<span title={stat.description}>{stat.name}</span>{" "}
{stat.user && (
<span
className="text-slate-300"
title={stat.user.email}
>
<WaspIcon className="w-5 h-5" />
</span>
)}
<p className="text-sm text-slate-500">
Number of displayed apps: {filteredStats.length}
</p>
</div>
<div className="relative overflow-x-auto shadow-md sm:rounded-lg">
<table className="w-full text-sm text-left text-slate-500">
<thead className="text-xs text-slate-700 uppercase bg-gray-50">
<tr>
<th scope="col" className="px-6 py-3">
App Name
</th>
<td className="px-6 py-4">
<StatusPill status={getStatusName(stat.status)} sm>
{getStatusText(stat.status)}
</StatusPill>
</td>
<td
className="px-6 py-4"
title={`${stat.createdAt.toLocaleDateString()} ${stat.createdAt.toLocaleTimeString()}`}
>
{format(stat.createdAt)}
</td>
<td className="px-6 py-4">
{getWaitingInQueueDuration(stat)} &rarr; {getDuration(stat)}
</td>
<td className="px-6 py-4">
<Link
to={`/result/${stat.id}`}
className="font-medium text-sky-600 hover:underline"
>
View the app &rarr;
</Link>
</td>
<th scope="col" className="px-6 py-3">
Status
</th>
<th scope="col" className="px-6 py-3">
Created At
</th>
<th scope="col" className="px-6 py-3">
Time in Queue &rarr; Build
</th>
<th scope="col" className="px-6 py-3"></th>
</tr>
))}
</tbody>
</table>
</div>
</>
)}
</div>
</thead>
<tbody>
{filteredStats.map((stat) => (
<tr className="bg-white border-b" key={stat.id}>
<th
scope="row"
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap flex items-center gap-2"
>
<Color value={getColorValue(stat.primaryColor)} />{" "}
<span title={stat.description}>{stat.name}</span>{" "}
{stat.user && (
<span
className="text-slate-300"
title={stat.user.email}
>
<WaspIcon className="w-5 h-5" />
</span>
)}
</th>
<td className="px-6 py-4">
<StatusPill status={getStatusName(stat.status)} sm>
{getStatusText(stat.status)}
</StatusPill>
</td>
<td
className="px-6 py-4"
title={`${stat.createdAt.toLocaleDateString()} ${stat.createdAt.toLocaleTimeString()}`}
>
{format(stat.createdAt)}
</td>
<td className="px-6 py-4">
{getWaitingInQueueDuration(stat)} &rarr;{" "}
{getDuration(stat)}
</td>
<td className="px-6 py-4">
<Link
to={`/result/${stat.id}`}
className="font-medium text-sky-600 hover:underline"
>
View the app &rarr;
</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
</>
)}
</div>
</>
);
}

View File

@ -1,4 +1,5 @@
import { generateAppJob } from "@wasp/jobs/generateAppJob.js";
import { log } from "./utils.js";
const maxProjectsInProgress = process.env.MAX_PROJECTS_IN_PROGRESS
? parseInt(process.env.MAX_PROJECTS_IN_PROGRESS, 10)
@ -12,7 +13,7 @@ export async function checkForPendingApps(
};
}
) {
console.log("Checking for pending apps");
log("Checking for pending apps");
const { Project } = context.entities;
const pendingProjects = await Project.findMany({

View File

@ -1,3 +1,5 @@
import { log } from "./utils.js";
export async function failStaleGenerations(
_args: void,
context: {
@ -8,7 +10,7 @@ export async function failStaleGenerations(
}
) {
// If a generation has been in progress for > 5 minutes, it fails it
console.log("Failing stale generations");
log("Failing stale generations");
const { Project, Log } = context.entities;
const now = getNowInUTC();
@ -26,9 +28,19 @@ export async function failStaleGenerations(
},
},
},
include: {
logs: {
select: {
id: true,
}
},
},
});
for (const project of staleProjects) {
if (project.logs.length === 0) {
continue;
}
await Project.update({
where: { id: project.id },
data: { status: "cancelled" },

View File

@ -1,5 +1,6 @@
import { spawn } from "child_process";
import { Mutex } from "async-mutex";
import { log } from "./utils.js";
const appGenerationResults: Record<string, any> = {};
@ -13,8 +14,7 @@ export async function generateApp(
};
}
) {
// Given the appID, it generates the app
console.log("Generating app");
log("Generating app");
const appId = args.appId;
const { Project, Log, File } = context.entities;

View File

@ -0,0 +1,10 @@
export function log(line: string): void {
const date = formatDate(new Date());
console.log(`[${date}] ${line}`);
}
function formatDate(date: Date): string {
return `${date.getDate()}-${
date.getMonth() + 1
}-${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
}