diff --git a/backend/internal/server/server.go b/backend/internal/server/server.go index 4af9a752..866e1157 100644 --- a/backend/internal/server/server.go +++ b/backend/internal/server/server.go @@ -132,7 +132,7 @@ func (server *Server) Run() error { // TODO: Move the compiler routes to a separate file/into compiler // Apps - server.router.GET("/api/app-resources/:id/base.html", func(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + server.router.GET("/api/app-resources/:id/base/*filepath", func(res http.ResponseWriter, req *http.Request, params httprouter.Params) { id := params.ByName("id") res.Header().Set("Content-Type", "text/html; charset=utf-8") diff --git a/backend/internal/server/web_prod.go b/backend/internal/server/web_prod.go index ebcbe54f..2b1ac90d 100644 --- a/backend/internal/server/web_prod.go +++ b/backend/internal/server/web_prod.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/julienschmidt/httprouter" + "robinplatform.dev/internal/log" ) //go:generate rm -rf web @@ -32,13 +33,27 @@ func (server *Server) loadRoutes() { return err } if !entry.IsDir() { - route := strings.TrimPrefix(assetPath, "web") + routes := []string{strings.TrimPrefix(assetPath, "web")} + if strings.HasSuffix(assetPath, ".html") { - route = regexp.MustCompile(`\[([^\]]+)\]`).ReplaceAllString(route, ":$1") - route = strings.TrimSuffix(route, ".html") + wildcardStartIndex := strings.Index(routes[0], "[[...") + if wildcardStartIndex != -1 { + wildcardName := routes[0][wildcardStartIndex+5:] + wildcardName = wildcardName[:len(wildcardName)-7] + + routes = []string{ + routes[0][:wildcardStartIndex-1], + routes[0][:wildcardStartIndex] + "*" + wildcardName, + } + } + + for idx := range routes { + routes[idx] = regexp.MustCompile(`\[([^\]]+)\]`).ReplaceAllString(routes[idx], ":$1") + routes[idx] = strings.TrimSuffix(routes[idx], ".html") - if strings.HasSuffix(route, "/index") { - route = strings.TrimSuffix(route, "index") + if strings.HasSuffix(routes[0], "/index") { + routes[idx] = strings.TrimSuffix(routes[idx], "index") + } } } @@ -47,20 +62,27 @@ func (server *Server) loadRoutes() { mimetype = "text/html" } - router.GET(route, func(res http.ResponseWriter, req *http.Request, _ httprouter.Params) { - file, err := nextBuild.Open(assetPath) - if os.IsNotExist(err) { - // TODO: serve 404 page - res.WriteHeader(404) - res.Write([]byte("404 - Not Found")) - } else if err != nil { - res.WriteHeader(500) - res.Write([]byte(err.Error())) - } else { - res.Header().Set("Content-Type", mimetype) - io.Copy(res, file) - } - }) + for _, route := range routes { + logger.Debug("Registering route", log.Ctx{ + "route": route, + "path": assetPath, + }) + + router.GET(route, func(res http.ResponseWriter, req *http.Request, _ httprouter.Params) { + file, err := nextBuild.Open(assetPath) + if os.IsNotExist(err) { + // TODO: serve 404 page + res.WriteHeader(404) + res.Write([]byte("404 - Not Found")) + } else if err != nil { + res.WriteHeader(500) + res.Write([]byte(err.Error())) + } else { + res.Header().Set("Content-Type", mimetype) + io.Copy(res, file) + } + }) + } } return nil }) diff --git a/backend/robin.servers.json b/backend/robin.servers.json index e3c0b535..61fe240d 100644 --- a/backend/robin.servers.json +++ b/backend/robin.servers.json @@ -1,5 +1,13 @@ { "devServers": { - "cli": "go run github.com/mitranim/gow -e 'go,tsx,html' run ./cmd/cli start" + "cli": { + "healthChecks": [ + { + "type": "tcp", + "port": 9010 + } + ], + "command": "go run github.com/mitranim/gow -e 'go,tsx,html' run ./cmd/cli start" + } } } diff --git a/frontend/components/AppWindow.tsx b/frontend/components/AppWindow.tsx index be540fe2..0a593c26 100644 --- a/frontend/components/AppWindow.tsx +++ b/frontend/components/AppWindow.tsx @@ -59,6 +59,13 @@ function AppWindowContent({ id, setTitle }: AppWindowProps) { const iframeRef = React.useRef(null); const [error, setError] = React.useState(null); + const subRoute = React.useMemo( + () => + router.isReady + ? router.asPath.substring('/app/'.length + id.length) + : null, + [router.isReady, router.asPath, id], + ); React.useEffect(() => { const onMessage = (message: MessageEvent) => { @@ -128,7 +135,7 @@ function AppWindowContent({ id, setTitle }: AppWindowProps) { diff --git a/frontend/pages/app/[id]/settings.tsx b/frontend/pages/app-settings/[id].tsx similarity index 87% rename from frontend/pages/app/[id]/settings.tsx rename to frontend/pages/app-settings/[id].tsx index 65f53a11..f20d06e5 100644 --- a/frontend/pages/app/[id]/settings.tsx +++ b/frontend/pages/app-settings/[id].tsx @@ -1,13 +1,13 @@ import { useRouter } from 'next/router'; -import { AppToolbar } from '../../../components/AppToolbar'; -import { Settings } from '../../../components/Settings'; +import { AppToolbar } from '../../components/AppToolbar'; +import { Settings } from '../../components/Settings'; import { z } from 'zod'; -import { useRpcMutation, useRpcQuery } from '../../../hooks/useRpcQuery'; -import { Button } from '../../../components/Button'; +import { useRpcMutation, useRpcQuery } from '../../hooks/useRpcQuery'; +import { Button } from '../../components/Button'; import { ArrowLeftIcon } from '@primer/octicons-react'; import { toast } from 'react-hot-toast'; -import { Alert } from '../../../components/Alert'; -import { Spinner } from '../../../components/Spinner'; +import { Alert } from '../../components/Alert'; +import { Spinner } from '../../components/Spinner'; import { useQueryClient } from '@tanstack/react-query'; import Head from 'next/head'; diff --git a/frontend/pages/app/[id]/index.tsx b/frontend/pages/app/[id]/[[...appRoute]].tsx similarity index 100% rename from frontend/pages/app/[id]/index.tsx rename to frontend/pages/app/[id]/[[...appRoute]].tsx