A basic but kind of scuffed Alpine version of the same functionality. Why is this so much more complicated?

main
Zed A. Shaw 3 months ago
parent f72fec3a5d
commit bafff1d25f
  1. 36
      commands/app.js
  2. 38
      controllers/todo_alpine.js
  3. 91
      package-lock.json
  4. 1
      package.json
  5. 3422
      static/axios.js
  6. 1
      static/axios.js.map
  7. 2
      templates/header.html
  8. 33
      templates/todo_alpine.html

@ -6,6 +6,7 @@ import path from "path";
import fs from "fs";
import chokidar from "chokidar";
import nunjucks from "nunjucks";
import fg from "fast-glob";
export const description = "Runs your app.";
@ -22,23 +23,24 @@ const configure = async (fastify, opts) => {
const app = fastify(opts);
// forces reload of the modules
const control_mod = await import(`../controllers/todo.js?update=${new Date()}`);
// TODO: mappings are very simple for now
for(let [url, controller] of Object.entries(control_mod.default)) {
const handler = new controller();
// this goes through all the allowed verbs
for(let verb of ["get", "post", "put", "delete"]) {
if(verb in handler) {
app[verb](`/${url}`, async (req, rep) => {
try {
await handler[verb](req, rep);
} catch(error) {
console.error(error);
console.error(error.stack);
console.error(error.source);
}
});
for(let mod of fg.sync("controllers/*.js")) {
const control_mod = await import(`../${mod}?update=${new Date()}`);
// TODO: mappings are very simple for now
for(let [url, controller] of Object.entries(control_mod.default)) {
const handler = new controller();
// this goes through all the allowed verbs
for(let verb of ["get", "post", "put", "delete"]) {
if(verb in handler) {
app[verb](`/${url}`, async (req, rep) => {
try {
await handler[verb](req, rep);
} catch(error) {
console.error(error);
console.error(error.stack);
console.error(error.source);
}
});
}
}
}
}

@ -0,0 +1,38 @@
import { ToDo } from "../lib/models.js";
import nunjucks from "nunjucks";
// this can go away when I learn how to detect the request type
export class TodoIndex {
async get(req, rep) {
const todo_list = await ToDo.all({});
const result = nunjucks.render("todo_alpine.html", {name: "Zed"});
rep.code(200).type("text/html").send(result);
}
}
export class Todo {
async get(req, rep) {
const todo_list = await ToDo.all({});
rep.code(200).send(todo_list);
}
async post(req, rep) {
if(req.query.todo_id !== undefined) {
await ToDo.delete({id: req.query.todo_id});
} else {
await ToDo.insert({task: req.body.task});
}
// this is how you can prevent the annoying double submit
rep.code(200).send({message: "OK"});
}
}
// you use the export default to set the route URL?
// I mean, it works not sure if I like it though
export default {
todo_alpine: Todo,
todo_index: TodoIndex
};

91
package-lock.json generated

@ -12,6 +12,7 @@
"@fastify/formbody": "^7.4.0",
"@fastify/helmet": "^11.1.1",
"@fastify/static": "^7.0.0",
"axios": "^1.6.7",
"commander": "^12.0.0",
"fast-glob": "^3.3.2",
"fastify": "^4.26.0",
@ -425,6 +426,11 @@
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
@ -443,6 +449,16 @@
"fastq": "^1.6.1"
}
},
"node_modules/axios": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
"dependencies": {
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -726,6 +742,17 @@
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
@ -816,6 +843,14 @@
"node": ">=4.0.0"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@ -1065,6 +1100,25 @@
"node": ">=14"
}
},
"node_modules/follow-redirects": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@ -1080,6 +1134,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -1708,6 +1775,25 @@
"node": ">=10.0.0"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
@ -2311,6 +2397,11 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",

@ -12,6 +12,7 @@
"@fastify/formbody": "^7.4.0",
"@fastify/helmet": "^11.1.1",
"@fastify/static": "^7.0.0",
"axios": "^1.6.7",
"commander": "^12.0.0",
"fast-glob": "^3.3.2",
"fastify": "^4.26.0",

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -2,7 +2,7 @@
<html>
<head>
<script src="/alpine.js"></script>
<script src="/axios.js"></script>
<title>Bandolier2</title>
<style>

@ -0,0 +1,33 @@
{% include "./header.html" %}
<h1>Your TODOs</h1>
<script src="/alpine.js"></script>
<script>
const new_task = async (todos, task) => {
// zero error handling but fine for now
await axios.post("/todo_alpine", {task});
return (await axios.get('/todo_alpine')).data;
}
</script>
<p>Welcome {{ name }}, here's your TODOs</p>
<div
x-data="{todos: []}"
x-init="todos = (await axios.get('/todo_alpine')).data">
<ol>
<template x-for="todo of todos">
<li x-text="todo.task"></li>
</template>
</ol>
<h4>Add a New TODO</h4>
<form action="/todo_index" @submit.prevent="todos = new_task(todos, task), task = ''" method="POST" x-data="{task: ''}">
<label for="task">Task</label>
<input name="task" x-model="task"></input>
<button type="button" @click="todos = new_task(todos, task), task = ''">Submit</button>
</form>
</div>
{% include "./footer.html" %}
Loading…
Cancel
Save