+
{children}
diff --git a/packages/dashboard/src/app/(layout)/services/[id]/components/ServiceOnboardingModal.tsx b/packages/dashboard/src/app/(layout)/services/[id]/components/ServiceOnboardingModal.tsx
new file mode 100644
index 0000000..ace670f
--- /dev/null
+++ b/packages/dashboard/src/app/(layout)/services/[id]/components/ServiceOnboardingModal.tsx
@@ -0,0 +1,106 @@
+"use client"
+
+import { useEffect, useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { ArrowRight, Server, Code } from "lucide-react"
+import { useRouter } from "next/navigation"
+
+export default function ServiceOnboardingModal() {
+ const router = useRouter()
+ const [isOpen, setIsOpen] = useState(false)
+
+ useEffect(() => {
+ const hasSeenServiceCreatedModal = localStorage.getItem("service_created_modal_shown") === "true"
+
+ if (!hasSeenServiceCreatedModal) {
+ setIsOpen(true)
+ }
+ }, [])
+
+ const completeModal = () => {
+ localStorage.setItem("service_created_modal_shown", "true")
+ setIsOpen(false)
+ }
+
+ const onUseMcpServer = () => {
+ completeModal()
+ router.push("/credentials")
+ }
+
+ const onUseWithApi = () => {
+ completeModal()
+ router.push("/credentials")
+ }
+
+ return (
+
+ )
+}
diff --git a/packages/dashboard/src/app/(layout)/services/[id]/page.tsx b/packages/dashboard/src/app/(layout)/services/[id]/page.tsx
index dee6942..d07986e 100644
--- a/packages/dashboard/src/app/(layout)/services/[id]/page.tsx
+++ b/packages/dashboard/src/app/(layout)/services/[id]/page.tsx
@@ -14,6 +14,7 @@ import {EndpointsTab} from "./components/EndpointsTab";
import {APIServiceForm} from "@/components/forms/APIServiceForm";
import DeleteServiceForm from "@/components/forms/DeleteServiceForm";
import ServiceMonitoring from "@/app/(layout)/services/[id]/components/monitoring/ServiceMonitoring";
+import ServiceOnboardingModal from "@/app/(layout)/services/[id]/components/ServiceOnboardingModal";
type Args = {
params: Promise<{ id: string }>
@@ -44,6 +45,7 @@ export default async function PrivatePage({params}: Args) {
return (
+
diff --git a/packages/dashboard/src/utils/data/demoSwagger.ts b/packages/dashboard/src/utils/data/demoSwagger.ts
new file mode 100644
index 0000000..de97eef
--- /dev/null
+++ b/packages/dashboard/src/utils/data/demoSwagger.ts
@@ -0,0 +1,699 @@
+export const demoSwagger = {
+ "swagger":"2.0",
+ "info":{
+ "description":"Fake Online REST API for Testing and Prototyping",
+ "version":"1.0.0",
+ "title":"JSON Placeholder"
+ },
+ "host":"jsonplaceholder.typicode.com",
+ "tags":[
+ {
+ "name":"posts"
+ },
+ {
+ "name":"comments"
+ },
+ {
+ "name":"albums"
+ },
+ {
+ "name":"photos"
+ },
+ {
+ "name":"todos"
+ },
+ {
+ "name":"users"
+ }
+ ],
+ "schemes":[
+ "https"
+ ],
+ "paths":{
+ "/posts":{
+ "get":{
+ "tags":[
+ "posts"
+ ],
+ "operationId":"getPosts",
+ "summary":"Get all available posts",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by post ID",
+ "required":false
+ },
+ {
+ "name":"userId",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by user ID",
+ "required":false
+ }
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Post"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/posts/{id}":{
+ "get":{
+ "tags":[
+ "posts"
+ ],
+ "summary":"Get specific post",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"The ID of the post to retrieve",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/Post"
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/posts/{id}/comments":{
+ "get":{
+ "tags":[
+ "posts"
+ ],
+ "summary":"Get comments for a specific post",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"post id",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Comment"
+ }
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/comments":{
+ "get":{
+ "tags":[
+ "comments"
+ ],
+ "operationId":"getComments",
+ "summary":"Get all available comments",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by comment ID",
+ "required":false
+ },
+ {
+ "name":"postId",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by post ID",
+ "required":false
+ }
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Comment"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/comments/{id}":{
+ "get":{
+ "tags":[
+ "comments"
+ ],
+ "operationId":"getComment",
+ "summary":"Get specific comment",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"The ID of the comment to retrieve",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/Comment"
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/albums":{
+ "get":{
+ "tags":[
+ "albums"
+ ],
+ "operationId":"getAlbums",
+ "summary":"Get all available albums",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by album ID",
+ "required":false
+ },
+ {
+ "name":"userId",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by user ID",
+ "required":false
+ }
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Album"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/albums/{id}":{
+ "get":{
+ "tags":[
+ "albums"
+ ],
+ "summary":"Get specific album",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"The ID of the album to retrieve",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/Album"
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/albums/{id}/photos":{
+ "get":{
+ "tags":[
+ "albums"
+ ],
+ "summary":"Get photos for a specific album",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"post id",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Photo"
+ }
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/photos":{
+ "get":{
+ "tags":[
+ "photos"
+ ],
+ "operationId":"getPhotos",
+ "summary":"Get all available photos",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by photo ID",
+ "required":false
+ },
+ {
+ "name":"albumId",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by album ID",
+ "required":false
+ }
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Photo"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/photos/{id}":{
+ "get":{
+ "tags":[
+ "photos"
+ ],
+ "operationId":"getPhoto",
+ "summary":"Get specific photo",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"The ID of the photo to retrieve",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/Photo"
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/todos":{
+ "get":{
+ "tags":[
+ "todos"
+ ],
+ "operationId":"getTodos",
+ "summary":"Get all available todos",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by todo ID",
+ "required":false
+ },
+ {
+ "name":"userId",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by user ID",
+ "required":false
+ }
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/Todo"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/todos/{id}":{
+ "get":{
+ "tags":[
+ "todos"
+ ],
+ "operationId":"getTodo",
+ "summary":"Get specific todo",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"The ID of the todo to retrieve",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/Todo"
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ },
+ "/users":{
+ "get":{
+ "tags":[
+ "users"
+ ],
+ "operationId":"getUsers",
+ "summary":"Get all available users",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by user ID",
+ "required":false
+ },
+ {
+ "name":"email",
+ "in":"query",
+ "type":"integer",
+ "description":"Filter by user email address",
+ "required":false
+ }
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/User"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/users/{id}":{
+ "get":{
+ "tags":[
+ "users"
+ ],
+ "operationId":"getUser",
+ "summary":"Get specific user",
+ "parameters":[
+ {
+ "name":"id",
+ "in":"path",
+ "description":"The ID of the user to retrieve",
+ "required":true,
+ "type":"integer"
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/User"
+ }
+ },
+ "404":{
+ "description":"not found",
+ "schema":{
+ "$ref":"#/definitions/NotFoundError"
+ }
+ }
+ }
+ }
+ }
+ },
+ "definitions":{
+ "Post":{
+ "type":"object",
+ "properties":{
+ "id":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "userId":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "title":{
+ "type":"string"
+ },
+ "body":{
+ "type":"string"
+ }
+ }
+ },
+ "Comment":{
+ "type":"object",
+ "properties":{
+ "id":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "postId":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "name":{
+ "type":"string"
+ },
+ "email":{
+ "type":"string",
+ "format":"email"
+ },
+ "body":{
+ "type":"string"
+ }
+ }
+ },
+ "Album":{
+ "type":"object",
+ "properties":{
+ "id":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "userId":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "title":{
+ "type":"string"
+ }
+ }
+ },
+ "Photo":{
+ "type":"object",
+ "properties":{
+ "id":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "albumId":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "title":{
+ "type":"string"
+ },
+ "url":{
+ "type":"string",
+ "format":"uri"
+ },
+ "thumbnailUrl":{
+ "type":"string",
+ "format":"uri"
+ }
+ }
+ },
+ "Todo":{
+ "type":"object",
+ "properties":{
+ "id":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "userId":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "title":{
+ "type":"string"
+ },
+ "completed":{
+ "type":"boolean"
+ }
+ }
+ },
+ "User":{
+ "type":"object",
+ "properties":{
+ "id":{
+ "type":"integer",
+ "format":"int64"
+ },
+ "name":{
+ "type":"string"
+ },
+ "username":{
+ "type":"string"
+ },
+ "email":{
+ "type":"string",
+ "format":"email"
+ },
+ "phone":{
+ "type":"string"
+ },
+ "website":{
+ "type":"string"
+ },
+ "company":{
+ "type":"object",
+ "properties":{
+ "name":{
+ "type":"string"
+ },
+ "catchPhrase":{
+ "type":"string"
+ },
+ "bs":{
+ "type":"string"
+ }
+ }
+ },
+ "address":{
+ "type":"object",
+ "properties":{
+ "street":{
+ "type":"string"
+ },
+ "suite":{
+ "type":"string"
+ },
+ "city":{
+ "type":"string"
+ },
+ "zipcode":{
+ "type":"string"
+ },
+ "geo":{
+ "type":"object",
+ "properties":{
+ "lat":{
+ "type":"string"
+ },
+ "lng":{
+ "type":"string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "NotFoundError":{
+ "type":"object"
+ }
+ }
+}
diff --git a/packages/dashboard/src/utils/supabase/database.types.ts b/packages/dashboard/src/utils/supabase/database.types.ts
index e615b45..c3386fd 100644
--- a/packages/dashboard/src/utils/supabase/database.types.ts
+++ b/packages/dashboard/src/utils/supabase/database.types.ts
@@ -135,13 +135,13 @@ export type Database = {
Insert: {
created_at?: string | null
endpoint_id: number
- id?: never
+ id?: number
schema?: Json | null
}
Update: {
created_at?: string | null
endpoint_id?: number
- id?: never
+ id?: number
schema?: Json | null
}
Relationships: [
@@ -316,18 +316,21 @@ export type Database = {
billing_started_at: string
calls_count: number
id: number
+ mcp_calls_count: number
user_id: string
}
Insert: {
billing_started_at?: string
calls_count?: number
id?: number
+ mcp_calls_count?: number
user_id: string
}
Update: {
billing_started_at?: string
calls_count?: number
id?: number
+ mcp_calls_count?: number
user_id?: string
}
Relationships: []
@@ -346,6 +349,13 @@ export type Database = {
}
Returns: Json
}
+ increment_mcp_usage: {
+ Args: { p_user_id: string; p_max_requests: number }
+ Returns: {
+ allowed: boolean
+ c_count: number
+ }[]
+ }
increment_usage: {
Args: { p_user_id: string; p_max_requests: number }
Returns: {