fix: quick add opens create ui

Add createKey to quick-add manifests and client create dialog host.

FAB and command palette open in-place create UIs instead of navigating away.
This commit is contained in:
ginnoir
2026-07-04 11:47:35 -05:00
parent 76f68548b2
commit 68a573c4d6
24 changed files with 1017 additions and 20 deletions
+2
View File
@@ -67,6 +67,8 @@ export type QuickAddAction = {
icon?: string;
/** Navigation target used by the FAB sheet and command palette. */
url: string;
/** Client-side create dialog key (see quick-add create registry). */
createKey?: string;
action?: (ctx: WidgetContext) => void | Promise<void>;
};
+3 -1
View File
@@ -43,6 +43,7 @@ export type SerializedQuickAddItem = {
label: string;
icon?: string;
url: string;
createKey?: string;
moduleId: string;
moduleName: string;
};
@@ -95,11 +96,12 @@ export async function fireItemToggleHooks(payload: ItemTogglePayload): Promise<v
export function getQuickAdds(): SerializedQuickAddItem[] {
return [...modules.values()].flatMap((manifest) =>
(manifest.quickAdds ?? []).map(({ id, label, icon, url }) => ({
(manifest.quickAdds ?? []).map(({ id, label, icon, url, createKey }) => ({
id,
label,
icon,
url,
createKey,
moduleId: manifest.id,
moduleName: manifest.name,
})),
+9
View File
@@ -41,6 +41,15 @@ const bangsManifest: ModuleManifest = {
render: (props) => <BangWidgetServer {...props} />,
},
],
quickAdds: [
{
id: "bangs.record",
label: "Record bang",
icon: "sparkles",
url: "/",
createKey: "bangs.record",
},
],
};
export default bangsManifest;
+2
View File
@@ -226,12 +226,14 @@ const manifest: ModuleManifest = {
label: "New event",
icon: "calendar-plus",
url: "/calendar",
createKey: "calendar.event",
},
{
id: "calendar.new-calendar",
label: "New calendar",
icon: "calendar-days",
url: "/calendar",
createKey: "calendar.calendar",
},
],
};
+32 -10
View File
@@ -42,9 +42,17 @@ type Props = {
existingPlant?: PlantDetailDto;
defaultContainerId?: string | null;
containers: ContainerDto[];
onSuccess?: (plantId: string) => void;
onCancel?: () => void;
};
export function PlantForm({ existingPlant, defaultContainerId, containers }: Props) {
export function PlantForm({
existingPlant,
defaultContainerId,
containers,
onSuccess,
onCancel,
}: Props) {
const router = useRouter();
const [error, setError] = useState<string | null>(null);
const [isPending, startTransition] = useTransition();
@@ -121,11 +129,19 @@ export function PlantForm({ existingPlant, defaultContainerId, containers }: Pro
try {
if (existingPlant) {
await updatePlant({ id: existingPlant.id, ...input });
router.push(`/garden/plants/${existingPlant.id}`);
router.refresh();
if (onSuccess) {
onSuccess(existingPlant.id);
} else {
router.push(`/garden/plants/${existingPlant.id}`);
router.refresh();
}
} else {
const plant = await createPlant(input);
router.push(`/garden/plants/${plant.id}`);
if (onSuccess) {
onSuccess(plant.id);
} else {
router.push(`/garden/plants/${plant.id}`);
}
}
} catch {
setError("Something went wrong. Please try again.");
@@ -352,12 +368,18 @@ export function PlantForm({ existingPlant, defaultContainerId, containers }: Pro
{error && <p className="text-sm text-red-500">{error}</p>}
<div className="flex gap-2 justify-end">
<a
href={existingPlant ? `/garden/plants/${existingPlant.id}` : "/garden"}
className="btn btn-ghost"
>
Cancel
</a>
{onCancel ? (
<button type="button" className="btn btn-ghost" onClick={onCancel}>
Cancel
</button>
) : (
<a
href={existingPlant ? `/garden/plants/${existingPlant.id}` : "/garden"}
className="btn btn-ghost"
>
Cancel
</a>
)}
<button type="submit" className="btn btn-primary" disabled={isPending || uploading}>
{isPending ? "Saving…" : existingPlant ? "Save" : "Create"}
</button>
+3
View File
@@ -203,18 +203,21 @@ const gardenManifest: ModuleManifest = {
label: "Add plant",
icon: "leaf",
url: "/garden/plants/new",
createKey: "garden.plant",
},
{
id: "garden.add-container",
label: "Add container",
icon: "box",
url: "/garden/containers/new",
createKey: "garden.container",
},
{
id: "garden.log-care",
label: "Log plant care",
icon: "droplets",
url: "/garden?logCare=1",
createKey: "garden.log-care",
},
],
};
+2
View File
@@ -1,3 +1,5 @@
"use server";
import { and, desc, eq, lte, sql } from "drizzle-orm";
import { db } from "@/lib/db";
import { getCurrentSession } from "@/lib/session";
+3
View File
@@ -93,18 +93,21 @@ const manifest: ModuleManifest = {
label: "Add to shopping",
icon: "shopping-cart",
url: "/lists",
createKey: "lists.add-shopping",
},
{
id: "lists.add-task",
label: "Add to tasks",
icon: "list-checks",
url: "/lists",
createKey: "lists.add-task",
},
{
id: "lists.new-list",
label: "New list",
icon: "list-plus",
url: "/lists",
createKey: "lists.new-list",
},
],
};
+1
View File
@@ -106,6 +106,7 @@ const manifest: ModuleManifest = {
label: "New note",
icon: "file-plus",
url: "/notes/new",
createKey: "notes.note",
},
],
};