the finances skeleton — repo, prefix and permission key, before any feature
Published empty on purpose: identity is the expensive part to change later, the feature is the cheap part to add. One route, two placeholder panels, no tables and no sidecar.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import { useParams } from "react-router";
|
||||
|
||||
// The second panel, reading the section from the URL rather than from the panel beside it.
|
||||
export const FinancesDetail = () => {
|
||||
const { section } = useParams();
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-auto p-6">
|
||||
<h2 className="text-lg font-semibold text-duck-dark">Detail</h2>
|
||||
<p className="mt-1 text-sm text-duck-dark/60">
|
||||
Section from the URL: <code>{section ?? "(none)"}</code>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useClient } from "hooks/useClient";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
// Placeholder. It proves the route mounts and the panel renders, and nothing else.
|
||||
export const FinancesOverview = () => {
|
||||
const client = useClient();
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ["finances", "ping"],
|
||||
queryFn: () =>
|
||||
client.get<{ plugin: string; ok: boolean }>("/finances/ping"),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-auto p-6">
|
||||
<h2 className="text-lg font-semibold text-duck-dark">Finances</h2>
|
||||
<p className="mt-1 text-sm text-duck-dark/60">
|
||||
Nothing here yet — the skeleton is up and mounted.
|
||||
</p>
|
||||
<div className="mt-4 rounded-md border border-duck-dark/10 bg-duck-dark/[0.02] p-3 font-mono text-xs">
|
||||
<div className="mb-1 text-duck-dark/50">GET /api/finances/ping</div>
|
||||
{isLoading ? (
|
||||
<span className="text-duck-dark/40">…</span>
|
||||
) : (
|
||||
<span>{JSON.stringify(data)}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { LayoutNode } from "officerdev";
|
||||
|
||||
// The starting arrangement. The shell persists whatever the user makes of it, per plugin.
|
||||
//
|
||||
// Every `appType` must be a key from `panels.ts` — a mismatch falls back silently instead of rendering
|
||||
// what was meant.
|
||||
export const defaultLayout: LayoutNode = {
|
||||
type: "group",
|
||||
id: "finances-root",
|
||||
direction: "horizontal",
|
||||
children: [
|
||||
{
|
||||
node: {
|
||||
type: "panel",
|
||||
id: "finances-overview",
|
||||
appType: "finances-overview",
|
||||
},
|
||||
size: 40,
|
||||
},
|
||||
{
|
||||
node: {
|
||||
type: "panel",
|
||||
id: "finances-detail",
|
||||
appType: "finances-detail",
|
||||
},
|
||||
size: 60,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Wallet, ListTree } from "lucide-react";
|
||||
import type { AppRegistryMeta } from "officerdev";
|
||||
import { FinancesOverview } from "./FinancesOverview";
|
||||
import { FinancesDetail } from "./FinancesDetail";
|
||||
|
||||
// The panels this plugin contributes. The shell renders the screen around them; this plugin never does.
|
||||
//
|
||||
// These keys are stored in a user's saved layout, so renaming one is a data change rather than a rename.
|
||||
export const appRegistryMetas: AppRegistryMeta[] = [
|
||||
{
|
||||
key: "finances-overview",
|
||||
name: "Overview",
|
||||
icon: Wallet,
|
||||
component: FinancesOverview,
|
||||
availableOnPanel: false,
|
||||
},
|
||||
{
|
||||
key: "finances-detail",
|
||||
name: "Detail",
|
||||
icon: ListTree,
|
||||
component: FinancesDetail,
|
||||
availableOnPanel: false,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user