From a23aee5d21586b7892491ec555406c9bc32d907f Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 21 Jan 2025 01:08:54 -0500 Subject: [PATCH] feat: wip previews for non-get routes --- db.js | 242 ++++++++++++++++++++++++-- index.js | 55 ++++-- migrations/002_add_scaffold_stuff.sql | 16 ++ views/workshop/cud_route.eta | 75 ++++++++ views/workshop/route.eta | 2 +- 5 files changed, 366 insertions(+), 24 deletions(-) create mode 100644 migrations/002_add_scaffold_stuff.sql create mode 100644 views/workshop/cud_route.eta diff --git a/db.js b/db.js index c7917d7..2d71107 100644 --- a/db.js +++ b/db.js @@ -126,22 +126,61 @@ function createStructure(db, name, userId) { function createRoute(db, verb, path, structureId, handler) { path = encodeURI(path); - // add default handler here + const stmt = db.prepare( - "INSERT INTO routes (verb, path, structure_id, handler) VALUES (?, ?, ?, ?)", + "INSERT INTO routes (verb, path, structure_id, handler) VALUES (?, ?, ?, ?)" ); const info = stmt.run(verb, path, structureId, handler); - return info.lastInsertRowid; // Returns the route_id of the newly created route + const routeId = info.lastInsertRowid; // Get the newly created route ID + + if (verb !== 'GET') { + createScaffoldPage(db, routeId); + } + + return routeId; // Returns the route_id of the newly created route } function getRoutes(db, structureId) { - return db - .prepare("SELECT * from routes where structure_id = ?") - .all(structureId); + const query = ` + SELECT + r.*, + sp.id AS scaffold_page_id, + sp.content AS scaffold_page_content, + sp2.id AS scaffold_params_id, + sp2.query_params, + sp2.url_params + FROM routes r + LEFT JOIN scaffold_pages sp ON r.id = sp.route_id + LEFT JOIN scaffold_params sp2 ON r.id = sp2.route_id + WHERE r.structure_id = ? + ORDER BY sp.created_at DESC, sp2.created_at DESC + `; + + return db.prepare(query).all(structureId); } function getRoute(db, routeId) { - return db.prepare("SELECT * from routes where id = ?").get(routeId); + const query = ` + SELECT + r.*, + sp.id AS scaffold_page_id, + sp.content AS scaffold_page_content, + sp2.id AS scaffold_params_id, + sp2.query_params, + sp2.url_params + FROM routes r + LEFT JOIN scaffold_pages sp ON r.id = sp.route_id + LEFT JOIN scaffold_params sp2 ON r.id = sp2.route_id + WHERE r.id = ? + ORDER BY sp.created_at DESC, sp2.created_at DESC + LIMIT 1 + `; + + return db.prepare(query).get(routeId); +} + +function defaultEndpointForRoute(db, routeId) { + } function updateRoute(db, route) { @@ -334,7 +373,7 @@ function cloneStructure( ).lastInsertRowid; const dbIds = db - .prepare(`select db_id from structure_dbs where structure_id = ?;`) + .prepare(`SELECT db_id FROM structure_dbs WHERE structure_id = ?;`) .all(structId); const toClone = new Set(cloneDbs); @@ -352,7 +391,7 @@ function cloneStructure( ` INSERT INTO dbs (name, structure_id, library) SELECT name, ?, library FROM dbs WHERE id = ?; - `, + `, ) .run(newStructId, db_id).lastInsertRowid; @@ -360,10 +399,10 @@ function cloneStructure( ` INSERT INTO structure_dbs (db_id, structure_id, alias) SELECT ?, ?, alias FROM structure_dbs WHERE db_id = ? AND structure_id = ?; - `, + `, ).run(newDb, newStructId, db_id, structId); - db.prepare(`select id from dbs where structure_id = ?`) + db.prepare(`SELECT id FROM dbs WHERE structure_id = ?`) .all(newStructId) .map((new_db) => { const srcPath = path.join(__dirname, "dbs", `${db_id}.sqlite`); @@ -373,6 +412,7 @@ function cloneStructure( fs.copyFileSync(srcPath + "-wal", destPath + "-wal"); }); } + for (let db_id of toAlias) { db.prepare( ` @@ -382,18 +422,42 @@ function cloneStructure( ).run(newStructId, structId, db_id); } + // Clone templates const cloneTemplates = db.prepare(` INSERT INTO templates (name, content, structure_id, test_object, engine) SELECT name, content, ?, test_object, engine FROM templates WHERE structure_id = ?; `); cloneTemplates.run(newStructId, structId); + // Clone routes const cloneRoutes = db.prepare(` INSERT INTO routes (verb, path, structure_id, handler) SELECT verb, path, ?, handler FROM routes WHERE structure_id = ?; `); cloneRoutes.run(newStructId, structId); + // Clone scaffold pages + const cloneScaffoldPages = db.prepare(` + INSERT INTO scaffold_pages (route_id, content, created_at) + SELECT newRoutes.id, sp.content, sp.created_at + FROM scaffold_pages sp + JOIN routes oldRoutes ON sp.route_id = oldRoutes.id + JOIN routes newRoutes ON oldRoutes.path = newRoutes.path AND oldRoutes.verb = newRoutes.verb + WHERE oldRoutes.structure_id = ? AND newRoutes.structure_id = ?; + `); + cloneScaffoldPages.run(structId, newStructId); + + // Clone scaffold params + const cloneScaffoldParams = db.prepare(` + INSERT INTO scaffold_params (route_id, query_params, url_params, created_at) + SELECT newRoutes.id, sp.query_params, sp.url_params, sp.created_at + FROM scaffold_params sp + JOIN routes oldRoutes ON sp.route_id = oldRoutes.id + JOIN routes newRoutes ON oldRoutes.path = newRoutes.path AND oldRoutes.verb = newRoutes.verb + WHERE oldRoutes.structure_id = ? AND newRoutes.structure_id = ?; + `); + cloneScaffoldParams.run(structId, newStructId); + return newStructId; }); @@ -432,6 +496,158 @@ function getMostRecentLogIdByRoute(db, routeId) { return result ? result.id : 0; } +function buildScaffoldUrl(endpoint, urlParams, queryString) { + let populatedUrl = endpoint.replace(/:([^/]+)/g, () => urlParams.shift() || ''); + return queryString ? `${populatedUrl}?${queryString}` : populatedUrl; +} + +function createScaffoldPage(db, routeId, content=null) { + if (!content) { + const route = getRoute(db, routeId) + const endpoint = buildScaffoldUrl(route.path, route.url_params, route.query_params); + content = getDefaultScaffoldContentByVerb(endpoint, route.verb); + console.log("gabga", content, route, endpoint) + } + console.log(content, "content") + const stmt = db.prepare( + "INSERT INTO scaffold_pages (route_id, content) VALUES (?, ?)" + ); + const info = stmt.run(routeId, content); + return info.lastInsertRowid; // Returns the scaffold_page id of the newly created scaffold page +} + +function getLatestScaffoldPage(db, routeId) { + const stmt = db.prepare( + "SELECT * FROM scaffold_pages WHERE route_id = ? ORDER BY created_at DESC LIMIT 1" + ); + return stmt.get(routeId); +} + +function updateScaffoldPage(db, scaffoldPage) { + const fields = ["content"]; + const values = fields.map((field) => scaffoldPage[field]); + const placeholders = fields.map((field) => `${field} = ?`).join(", "); + console.log(scaffoldPage, "gabababab") + + const sql = `UPDATE scaffold_pages SET ${placeholders} WHERE id = ?`; + values.push(scaffoldPage.id); // Add scaffoldPageId to the end for the WHERE clause + + const info = db.prepare(sql).run(...values); + console.log(info.changes) + return info.changes > 0; // Returns true if a row was updated, false otherwise +} + +function generatePostForm(endpoint) { + return ` + + + + + + Test POST Request + + + +

Test POST Request

+ +
" method="POST"> + + + + + +
+ + +
+ + + `; +} + +function generateModifyForm(endpoint, verb) { + return ` + + + + + + Test ${verb} Request + + + +

Test ${verb} Request

+ +
+ + + + + +
+ + +
+ + + `; +} + +function generateWSPage(endpoint) { + return ` + + + + + + Test WebSocket + + +

Test WebSocket Connection

+ + + + +
+ + + + + `; +} + +function getDefaultScaffoldContentByVerb(url, verb) { + if (verb == "POST") { + return generatePostForm(url); + } + else if (verb == "PUT" || verb == "DELETE") { + return generateModifyForm(url, verb); + } + else if (verb == "WS") { + return generateWSPage(url); + } +} + module.exports = { db, applyMigrations, @@ -445,6 +661,7 @@ module.exports = { createRoute, getRoutes, getRoute, + buildScaffoldUrl, updateRoute, updateDb, updateStruct, @@ -467,4 +684,7 @@ module.exports = { getLogsByRoute, getNewLogsByRoute, getMostRecentLogIdByRoute, + createScaffoldPage, + getLatestScaffoldPage, + updateScaffoldPage }; diff --git a/index.js b/index.js index c035ca2..608366a 100644 --- a/index.js +++ b/index.js @@ -464,6 +464,11 @@ app.post("/workshop/:structure_id/route", (req, res) => { app.put("/workshop/:structure_id/route/:route_id", (req, res) => { const route = model.getRoute(db, req.params.route_id); model.updateRoute(db, { ...route, ...req.body }); + if (req.body.scaffold_page) { + // TODO: make this send over scaffold page id too someday + const latestPage = model.getLatestScaffoldPage(db, req.params.route_id) + model.updateScaffoldPage(db, { ...latestPage, content: req.body.scaffold_page }) + } if (route.verb == "WS") { bootstrapWebsocketHandler({ ...route, ...req.body }) } @@ -575,11 +580,6 @@ app.put("/workshop/:structure_id/template/:template_id", (req, res) => { app.get("/workshop/:structure_id/template/:template_id", (req, res) => { const template = model.getTemplate(db, req.params.template_id); - console.log("wassup", { - template: template, - ...sidebarStuff(db, req.params.structure_id), - }); - return res.send( bootstrapTemplateWithHTMXetc( eta.render("workshop/template", { @@ -594,7 +594,6 @@ app.get("/workshop/:structure_id/template/:template_id/preview", (req, res) => { const template = model.getTemplate(db, req.params.template_id); const struct = model.getStructure(db, req.params.structure_id); const eta = model.getTemplater(req.params.structure_id); - console.log(template); const context = vm.createContext({ it: null }); vm.runInContext(template.test_object, context); @@ -621,22 +620,54 @@ app.get("/workshop/:structure_id/route/:id", (req, res) => { db, req.params.structure_id, ).route_prefix; - let previewUrl = routePrefix - ? path.join(routePrefix || "", route.path) - : route.path; + let previewUrl = null; + + if (route["verb"] == "GET" ) { + previewUrl = routePrefix + ? path.join(routePrefix || "", route.path) + : route.path; + } + else { + previewUrl = `/workshop/${req.params.structure_id}/route/${req.params.id}/preview`; + } + + template = route["verb"] == "GET" ? "workshop/route" : "workshop/cud_route"; return res.send( bootstrapTemplateWithHTMXetc( - eta.render("workshop/route", { + eta.render(template, { route: route, - previewUrl: - route["verb"] == "GET" ? previewUrl : "/workshop/do-something-here", + previewUrl: previewUrl, ...sidebarStuff(db, req.params.structure_id), }), ), ); }); +app.get("/workshop/:structure_id/route/:route_id/preview", (req, res) => { + const route = model.getRoute(db, req.params.route_id); + const struct = model.getStructure(db, req.params.structure_id); + + const it = { + route: function (url) { + return struct.route_prefix ? path.join(struct.route_prefix, url) : url; + } + } + + console.log(route) + + return res.send( + bootstrapTemplateWithHTMXetc( + eta.renderString(route.scaffold_page_content, it), + null, + null, + null, + struct.head_injection, + false, + ), + ); +}); + app.get("/workshop/:structure_id/route/:route_id/logs", (req, res) => { const since = req.query.since; let logs = []; diff --git a/migrations/002_add_scaffold_stuff.sql b/migrations/002_add_scaffold_stuff.sql new file mode 100644 index 0000000..15ee7ad --- /dev/null +++ b/migrations/002_add_scaffold_stuff.sql @@ -0,0 +1,16 @@ +CREATE TABLE scaffold_pages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + route_id INTEGER NOT NULL, + content TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(route_id) REFERENCES routes(id) ON DELETE CASCADE +); + +CREATE TABLE scaffold_params ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + route_id INTEGER NOT NULL, + query_params JSON, + url_params JSON, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(route_id) REFERENCES routes(id) ON DELETE CASCADE +); diff --git a/views/workshop/cud_route.eta b/views/workshop/cud_route.eta new file mode 100644 index 0000000..c84643c --- /dev/null +++ b/views/workshop/cud_route.eta @@ -0,0 +1,75 @@ + + + + + + + + +
+
+
Workshop - <%~ include('/workshop/structure_name', {structure: it.structure}) %> +
+
+
+
+ <%~ include('/workshop/sidebar', it) %> +
+
+
+ Route +
<%= it.route.handler %>
+ + + Test Page +
<%= it.route.scaffold_page_content %>
+ + +
+ + +
+
+
+ +
+ +
+
+
+ + + + + diff --git a/views/workshop/route.eta b/views/workshop/route.eta index 975cec7..54f614b 100644 --- a/views/workshop/route.eta +++ b/views/workshop/route.eta @@ -20,7 +20,7 @@
<%= it.route.handler %>
- +