@nubase/create 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/backend/src/api/routes/dashboard.ts +122 -0
- package/templates/backend/src/index.ts +3 -1
- package/templates/frontend/src/config.tsx +4 -0
- package/templates/frontend/src/dashboards/analytics.ts +67 -0
- package/templates/schema/src/api-endpoints.ts +25 -9
- package/templates/schema/src/{schema → endpoints}/auth/get-me.ts +1 -1
- package/templates/schema/src/{schema → endpoints}/auth/index.ts +0 -2
- package/templates/schema/src/{schema → endpoints}/auth/login-complete.ts +3 -3
- package/templates/schema/src/{schema → endpoints}/auth/login-start.ts +2 -2
- package/templates/schema/src/{schema → endpoints}/auth/login.ts +1 -1
- package/templates/schema/src/{schema → endpoints}/auth/signup.ts +3 -3
- package/templates/schema/src/endpoints/dashboard/active-users.ts +6 -0
- package/templates/schema/src/endpoints/dashboard/browser-stats.ts +6 -0
- package/templates/schema/src/endpoints/dashboard/index.ts +6 -0
- package/templates/schema/src/endpoints/dashboard/recent-activity.ts +6 -0
- package/templates/schema/src/endpoints/dashboard/revenue-chart.ts +6 -0
- package/templates/schema/src/endpoints/dashboard/sales-chart.ts +6 -0
- package/templates/schema/src/endpoints/dashboard/total-revenue.ts +6 -0
- package/templates/schema/src/endpoints/index.ts +3 -0
- package/templates/schema/src/{schema → endpoints}/ticket/get-ticket.ts +2 -2
- package/templates/schema/src/{schema → endpoints}/ticket/get-tickets.ts +3 -3
- package/templates/schema/src/{schema → endpoints}/ticket/index.ts +0 -1
- package/templates/schema/src/{schema → endpoints}/ticket/patch-ticket.ts +3 -3
- package/templates/schema/src/{schema → endpoints}/ticket/post-ticket.ts +3 -3
- package/templates/schema/src/index.ts +1 -2
- package/templates/schema/src/resources/index.ts +3 -0
- package/templates/schema/src/{schema/ticket/ticket-base.ts → resources/ticket.ts} +1 -1
- package/templates/schema/src/{schema/auth → resources}/workspace.ts +1 -1
- /package/templates/schema/src/{schema → endpoints}/auth/logout.ts +0 -0
- /package/templates/schema/src/{schema → endpoints}/ticket/delete-ticket.ts +0 -0
- /package/templates/schema/src/{schema/auth → resources}/user.ts +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createHttpHandler } from "@nubase/backend";
|
|
2
|
+
import { apiEndpoints } from "schema";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dashboard widget endpoints.
|
|
6
|
+
* These return hardcoded data for demonstration - real implementations would query the database.
|
|
7
|
+
*/
|
|
8
|
+
export const dashboardHandlers = {
|
|
9
|
+
/** Revenue chart - returns series data for area/line/bar charts. */
|
|
10
|
+
getRevenueChart: createHttpHandler({
|
|
11
|
+
endpoint: apiEndpoints.getRevenueChart,
|
|
12
|
+
handler: async () => ({
|
|
13
|
+
type: "series",
|
|
14
|
+
config: {
|
|
15
|
+
keys: ["desktop", "mobile"],
|
|
16
|
+
},
|
|
17
|
+
data: [
|
|
18
|
+
{ category: "January", desktop: 186, mobile: 80 },
|
|
19
|
+
{ category: "February", desktop: 305, mobile: 200 },
|
|
20
|
+
{ category: "March", desktop: 237, mobile: 120 },
|
|
21
|
+
{ category: "April", desktop: 73, mobile: 190 },
|
|
22
|
+
{ category: "May", desktop: 209, mobile: 130 },
|
|
23
|
+
{ category: "June", desktop: 214, mobile: 140 },
|
|
24
|
+
],
|
|
25
|
+
}),
|
|
26
|
+
}),
|
|
27
|
+
|
|
28
|
+
/** Browser stats - returns proportional data for pie/donut charts. */
|
|
29
|
+
getBrowserStats: createHttpHandler({
|
|
30
|
+
endpoint: apiEndpoints.getBrowserStats,
|
|
31
|
+
handler: async () => ({
|
|
32
|
+
type: "proportional",
|
|
33
|
+
data: [
|
|
34
|
+
{ label: "Chrome", value: 275 },
|
|
35
|
+
{ label: "Safari", value: 200 },
|
|
36
|
+
{ label: "Firefox", value: 187 },
|
|
37
|
+
{ label: "Edge", value: 173 },
|
|
38
|
+
{ label: "Other", value: 90 },
|
|
39
|
+
],
|
|
40
|
+
}),
|
|
41
|
+
}),
|
|
42
|
+
|
|
43
|
+
/** Total revenue KPI - returns single value with trend. */
|
|
44
|
+
getTotalRevenue: createHttpHandler({
|
|
45
|
+
endpoint: apiEndpoints.getTotalRevenue,
|
|
46
|
+
handler: async () => ({
|
|
47
|
+
type: "kpi",
|
|
48
|
+
value: "$45,231.89",
|
|
49
|
+
label: "Total Revenue",
|
|
50
|
+
trend: "+20.1% from last month",
|
|
51
|
+
trendDirection: "up",
|
|
52
|
+
}),
|
|
53
|
+
}),
|
|
54
|
+
|
|
55
|
+
/** Active users KPI - returns single value with trend. */
|
|
56
|
+
getActiveUsers: createHttpHandler({
|
|
57
|
+
endpoint: apiEndpoints.getActiveUsers,
|
|
58
|
+
handler: async () => ({
|
|
59
|
+
type: "kpi",
|
|
60
|
+
value: "+2,350",
|
|
61
|
+
label: "Active Users",
|
|
62
|
+
trend: "+180.1% from last month",
|
|
63
|
+
trendDirection: "up",
|
|
64
|
+
}),
|
|
65
|
+
}),
|
|
66
|
+
|
|
67
|
+
/** Sales chart - returns series data for bar charts. */
|
|
68
|
+
getSalesChart: createHttpHandler({
|
|
69
|
+
endpoint: apiEndpoints.getSalesChart,
|
|
70
|
+
handler: async () => ({
|
|
71
|
+
type: "series",
|
|
72
|
+
config: {
|
|
73
|
+
keys: ["sales"],
|
|
74
|
+
},
|
|
75
|
+
data: [
|
|
76
|
+
{ category: "Mon", sales: 12 },
|
|
77
|
+
{ category: "Tue", sales: 19 },
|
|
78
|
+
{ category: "Wed", sales: 3 },
|
|
79
|
+
{ category: "Thu", sales: 5 },
|
|
80
|
+
{ category: "Fri", sales: 2 },
|
|
81
|
+
{ category: "Sat", sales: 8 },
|
|
82
|
+
{ category: "Sun", sales: 15 },
|
|
83
|
+
],
|
|
84
|
+
}),
|
|
85
|
+
}),
|
|
86
|
+
|
|
87
|
+
/** Recent activity - returns table data. */
|
|
88
|
+
getRecentActivity: createHttpHandler({
|
|
89
|
+
endpoint: apiEndpoints.getRecentActivity,
|
|
90
|
+
handler: async () => ({
|
|
91
|
+
type: "table",
|
|
92
|
+
columns: [
|
|
93
|
+
{ key: "user", label: "User", width: "30%" },
|
|
94
|
+
{ key: "action", label: "Action", width: "40%" },
|
|
95
|
+
{ key: "time", label: "Time", width: "30%" },
|
|
96
|
+
],
|
|
97
|
+
rows: [
|
|
98
|
+
{ user: "John Doe", action: "Created a new ticket", time: "2 min ago" },
|
|
99
|
+
{
|
|
100
|
+
user: "Jane Smith",
|
|
101
|
+
action: "Updated project settings",
|
|
102
|
+
time: "5 min ago",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
user: "Bob Johnson",
|
|
106
|
+
action: "Closed ticket #123",
|
|
107
|
+
time: "10 min ago",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
user: "Alice Brown",
|
|
111
|
+
action: "Added comment on ticket #456",
|
|
112
|
+
time: "15 min ago",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
user: "Charlie Wilson",
|
|
116
|
+
action: "Assigned ticket to team",
|
|
117
|
+
time: "20 min ago",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
}),
|
|
121
|
+
}),
|
|
122
|
+
};
|
|
@@ -2,9 +2,10 @@ import { serve } from "@hono/node-server";
|
|
|
2
2
|
import { createAuthMiddleware, registerHandlers } from "@nubase/backend";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
4
|
import { cors } from "hono/cors";
|
|
5
|
-
import { ticketHandlers } from "./api/routes/ticket";
|
|
6
5
|
import { authHandlers } from "./api/routes/auth";
|
|
6
|
+
import { dashboardHandlers } from "./api/routes/dashboard";
|
|
7
7
|
import { testUtilsHandlers } from "./api/routes/test-utils";
|
|
8
|
+
import { ticketHandlers } from "./api/routes/ticket";
|
|
8
9
|
import {
|
|
9
10
|
createPostAuthWorkspaceMiddleware,
|
|
10
11
|
createWorkspaceMiddleware,
|
|
@@ -50,6 +51,7 @@ app.get("/", (c) => c.json({ message: "Welcome to __PROJECT_NAME_PASCAL__ API" }
|
|
|
50
51
|
// Register all handlers - path and method extracted from endpoint metadata
|
|
51
52
|
registerHandlers(app, authHandlers);
|
|
52
53
|
registerHandlers(app, ticketHandlers);
|
|
54
|
+
registerHandlers(app, dashboardHandlers);
|
|
53
55
|
|
|
54
56
|
// Register test utility handlers (only in test environment)
|
|
55
57
|
if (process.env.NODE_ENV === "test") {
|
|
@@ -3,6 +3,7 @@ import { defaultKeybindings, resourceLink } from "@nubase/frontend";
|
|
|
3
3
|
import { Home, TicketIcon } from "lucide-react";
|
|
4
4
|
import { apiEndpoints } from "schema";
|
|
5
5
|
import { __PROJECT_NAME_PASCAL__AuthController } from "./auth/__PROJECT_NAME_PASCAL__AuthController";
|
|
6
|
+
import { analyticsDashboard } from "./dashboards/analytics";
|
|
6
7
|
import { ticketResource } from "./resources/ticket";
|
|
7
8
|
|
|
8
9
|
const apiBaseUrl =
|
|
@@ -35,4 +36,7 @@ export const config: NubaseFrontendConfig<typeof apiEndpoints> = {
|
|
|
35
36
|
defaultThemeId: "dark",
|
|
36
37
|
authentication: authController,
|
|
37
38
|
publicRoutes: ["/signin"],
|
|
39
|
+
dashboards: {
|
|
40
|
+
[analyticsDashboard.id]: analyticsDashboard,
|
|
41
|
+
},
|
|
38
42
|
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createDashboard } from "@nubase/frontend";
|
|
2
|
+
import { apiEndpoints } from "schema";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Analytics dashboard configuration.
|
|
6
|
+
*
|
|
7
|
+
* This dashboard demonstrates the type-safe widget system:
|
|
8
|
+
* - Each widget references an endpoint that returns the correct data type
|
|
9
|
+
* - TypeScript will error if you try to use a non-matching endpoint
|
|
10
|
+
* - Layout is defined using react-grid-layout coordinates (x, y, w, h)
|
|
11
|
+
*/
|
|
12
|
+
export const analyticsDashboard = createDashboard("analytics")
|
|
13
|
+
.withApiEndpoints(apiEndpoints)
|
|
14
|
+
.withTitle("Analytics Dashboard")
|
|
15
|
+
.withWidgets([
|
|
16
|
+
// Revenue trend - area chart spanning most of the top row
|
|
17
|
+
{
|
|
18
|
+
type: "series",
|
|
19
|
+
id: "revenue-chart",
|
|
20
|
+
title: "Revenue Trend",
|
|
21
|
+
variant: "area1",
|
|
22
|
+
endpoint: "getRevenueChart",
|
|
23
|
+
defaultLayout: { x: 0, y: 0, w: 8, h: 3 },
|
|
24
|
+
},
|
|
25
|
+
// Browser stats - donut chart on the right
|
|
26
|
+
{
|
|
27
|
+
type: "proportional",
|
|
28
|
+
id: "browser-stats",
|
|
29
|
+
title: "Browser Usage",
|
|
30
|
+
variant: "donut",
|
|
31
|
+
endpoint: "getBrowserStats",
|
|
32
|
+
defaultLayout: { x: 8, y: 0, w: 4, h: 3 },
|
|
33
|
+
},
|
|
34
|
+
// KPI cards - second row
|
|
35
|
+
{
|
|
36
|
+
type: "kpi",
|
|
37
|
+
id: "total-revenue",
|
|
38
|
+
title: "Total Revenue",
|
|
39
|
+
endpoint: "getTotalRevenue",
|
|
40
|
+
defaultLayout: { x: 0, y: 3, w: 3, h: 2 },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "kpi",
|
|
44
|
+
id: "active-users",
|
|
45
|
+
title: "Active Users",
|
|
46
|
+
endpoint: "getActiveUsers",
|
|
47
|
+
defaultLayout: { x: 3, y: 3, w: 3, h: 2 },
|
|
48
|
+
},
|
|
49
|
+
// Sales chart - bar chart
|
|
50
|
+
{
|
|
51
|
+
type: "series",
|
|
52
|
+
id: "sales-chart",
|
|
53
|
+
title: "Weekly Sales",
|
|
54
|
+
variant: "bar",
|
|
55
|
+
endpoint: "getSalesChart",
|
|
56
|
+
defaultLayout: { x: 6, y: 3, w: 6, h: 2 },
|
|
57
|
+
},
|
|
58
|
+
// Recent activity table - bottom row
|
|
59
|
+
{
|
|
60
|
+
type: "table",
|
|
61
|
+
id: "recent-activity",
|
|
62
|
+
title: "Recent Activity",
|
|
63
|
+
endpoint: "getRecentActivity",
|
|
64
|
+
maxRows: 5,
|
|
65
|
+
defaultLayout: { x: 0, y: 5, w: 12, h: 3 },
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
@@ -5,23 +5,24 @@ import {
|
|
|
5
5
|
loginStartSchema,
|
|
6
6
|
logoutSchema,
|
|
7
7
|
signupSchema,
|
|
8
|
-
} from "./
|
|
8
|
+
} from "./endpoints/auth";
|
|
9
|
+
import {
|
|
10
|
+
getActiveUsersSchema,
|
|
11
|
+
getBrowserStatsSchema,
|
|
12
|
+
getRecentActivitySchema,
|
|
13
|
+
getRevenueChartSchema,
|
|
14
|
+
getSalesChartSchema,
|
|
15
|
+
getTotalRevenueSchema,
|
|
16
|
+
} from "./endpoints/dashboard";
|
|
9
17
|
import {
|
|
10
18
|
deleteTicketSchema,
|
|
11
19
|
getTicketSchema,
|
|
12
20
|
getTicketsSchema,
|
|
13
21
|
patchTicketSchema,
|
|
14
22
|
postTicketSchema,
|
|
15
|
-
} from "./
|
|
23
|
+
} from "./endpoints/ticket";
|
|
16
24
|
|
|
17
25
|
export const apiEndpoints = {
|
|
18
|
-
// Tickets
|
|
19
|
-
getTickets: getTicketsSchema,
|
|
20
|
-
getTicket: getTicketSchema,
|
|
21
|
-
postTicket: postTicketSchema,
|
|
22
|
-
patchTicket: patchTicketSchema,
|
|
23
|
-
deleteTicket: deleteTicketSchema,
|
|
24
|
-
|
|
25
26
|
// Auth
|
|
26
27
|
loginStart: loginStartSchema,
|
|
27
28
|
loginComplete: loginCompleteSchema,
|
|
@@ -29,6 +30,21 @@ export const apiEndpoints = {
|
|
|
29
30
|
logout: logoutSchema,
|
|
30
31
|
getMe: getMeSchema,
|
|
31
32
|
signup: signupSchema,
|
|
33
|
+
|
|
34
|
+
// Tickets
|
|
35
|
+
getTickets: getTicketsSchema,
|
|
36
|
+
getTicket: getTicketSchema,
|
|
37
|
+
postTicket: postTicketSchema,
|
|
38
|
+
patchTicket: patchTicketSchema,
|
|
39
|
+
deleteTicket: deleteTicketSchema,
|
|
40
|
+
|
|
41
|
+
// Dashboard widgets
|
|
42
|
+
getRevenueChart: getRevenueChartSchema,
|
|
43
|
+
getBrowserStats: getBrowserStatsSchema,
|
|
44
|
+
getTotalRevenue: getTotalRevenueSchema,
|
|
45
|
+
getActiveUsers: getActiveUsersSchema,
|
|
46
|
+
getSalesChart: getSalesChartSchema,
|
|
47
|
+
getRecentActivity: getRecentActivitySchema,
|
|
32
48
|
} as const;
|
|
33
49
|
|
|
34
50
|
export type ApiEndpoints = typeof apiEndpoints;
|
|
@@ -4,5 +4,3 @@ export { loginCompleteSchema } from "./login-complete";
|
|
|
4
4
|
export { loginStartSchema } from "./login-start";
|
|
5
5
|
export { logoutSchema } from "./logout";
|
|
6
6
|
export { signupSchema } from "./signup";
|
|
7
|
-
export { userSchema } from "./user";
|
|
8
|
-
export { workspaceInfoSchema } from "./workspace";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { emptySchema, nu, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import { userSchema } from "
|
|
3
|
-
import {
|
|
2
|
+
import { userSchema } from "../../resources/user";
|
|
3
|
+
import { workspaceSchema } from "../../resources/workspace";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Login complete request schema - Step 2 of two-step auth
|
|
@@ -20,6 +20,6 @@ export const loginCompleteSchema = {
|
|
|
20
20
|
}),
|
|
21
21
|
responseBody: nu.object({
|
|
22
22
|
user: userSchema,
|
|
23
|
-
workspace:
|
|
23
|
+
workspace: workspaceSchema,
|
|
24
24
|
}),
|
|
25
25
|
} satisfies RequestSchema;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { emptySchema, nu, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import {
|
|
2
|
+
import { workspaceSchema } from "../../resources/workspace";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Login start request schema - Step 1 of two-step auth
|
|
@@ -23,6 +23,6 @@ export const loginStartSchema = {
|
|
|
23
23
|
/** User's email (for display) */
|
|
24
24
|
email: nu.string(),
|
|
25
25
|
/** List of workspaces the user belongs to */
|
|
26
|
-
workspaces: nu.array(
|
|
26
|
+
workspaces: nu.array(workspaceSchema),
|
|
27
27
|
}),
|
|
28
28
|
} satisfies RequestSchema;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { emptySchema, nu, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import { userSchema } from "
|
|
3
|
-
import {
|
|
2
|
+
import { userSchema } from "../../resources/user";
|
|
3
|
+
import { workspaceSchema } from "../../resources/workspace";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Signup request schema
|
|
@@ -27,6 +27,6 @@ export const signupSchema = {
|
|
|
27
27
|
}),
|
|
28
28
|
responseBody: nu.object({
|
|
29
29
|
user: userSchema,
|
|
30
|
-
workspace:
|
|
30
|
+
workspace: workspaceSchema,
|
|
31
31
|
}),
|
|
32
32
|
} satisfies RequestSchema;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getActiveUsersSchema } from "./active-users";
|
|
2
|
+
export { getBrowserStatsSchema } from "./browser-stats";
|
|
3
|
+
export { getRecentActivitySchema } from "./recent-activity";
|
|
4
|
+
export { getRevenueChartSchema } from "./revenue-chart";
|
|
5
|
+
export { getSalesChartSchema } from "./sales-chart";
|
|
6
|
+
export { getTotalRevenueSchema } from "./total-revenue";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { idNumberSchema, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import {
|
|
2
|
+
import { ticketSchema } from "../../resources/ticket";
|
|
3
3
|
|
|
4
4
|
export const getTicketSchema = {
|
|
5
5
|
method: "GET" as const,
|
|
6
6
|
path: "/tickets/:id",
|
|
7
7
|
requestParams: idNumberSchema,
|
|
8
|
-
responseBody:
|
|
8
|
+
responseBody: ticketSchema,
|
|
9
9
|
} satisfies RequestSchema;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { nu, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import {
|
|
2
|
+
import { ticketSchema } from "../../resources/ticket";
|
|
3
3
|
|
|
4
4
|
export const getTicketsSchema = {
|
|
5
5
|
method: "GET" as const,
|
|
6
6
|
path: "/tickets",
|
|
7
|
-
requestParams:
|
|
8
|
-
responseBody: nu.array(
|
|
7
|
+
requestParams: ticketSchema.omit("id").partial(),
|
|
8
|
+
responseBody: nu.array(ticketSchema),
|
|
9
9
|
} satisfies RequestSchema;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { idNumberSchema, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import {
|
|
2
|
+
import { ticketSchema } from "../../resources/ticket";
|
|
3
3
|
|
|
4
4
|
export const patchTicketSchema = {
|
|
5
5
|
method: "PATCH" as const,
|
|
6
6
|
path: "/tickets/:id",
|
|
7
7
|
requestParams: idNumberSchema,
|
|
8
|
-
requestBody:
|
|
9
|
-
responseBody:
|
|
8
|
+
requestBody: ticketSchema.omit("id").partial(),
|
|
9
|
+
responseBody: ticketSchema,
|
|
10
10
|
} satisfies RequestSchema;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { emptySchema, type RequestSchema } from "@nubase/core";
|
|
2
|
-
import {
|
|
2
|
+
import { ticketSchema } from "../../resources/ticket";
|
|
3
3
|
|
|
4
4
|
export const postTicketSchema = {
|
|
5
5
|
method: "POST" as const,
|
|
6
6
|
path: "/tickets",
|
|
7
7
|
requestParams: emptySchema,
|
|
8
|
-
requestBody:
|
|
9
|
-
responseBody:
|
|
8
|
+
requestBody: ticketSchema.omit("id"),
|
|
9
|
+
responseBody: ticketSchema,
|
|
10
10
|
} satisfies RequestSchema;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|