Compare commits

...

5 commits

Author SHA1 Message Date
Anish Lakhwara 0344976747 test: working on deployments to fly 2025-02-20 12:40:36 -08:00
Anish Lakhwara 2d53428f56 filter parser updates? 2025-02-19 23:18:05 -08:00
Anish Lakhwara 20e50346f4 test: about to try and deploy to fly 2025-02-19 23:17:26 -08:00
Anish Lakhwara 5e996b27d3 feat: data table is a lil reactive 2025-02-19 23:17:05 -08:00
Anish Lakhwara 0480be5ded fix: make main a bit nicer 2025-02-19 23:16:53 -08:00
9 changed files with 208 additions and 64 deletions

View file

@ -94,7 +94,7 @@
};
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ go pigeon nodejs sqlite git-bug openssl ];
buildInputs = with pkgs; [ go pigeon nodejs sqlite git-bug openssl flyctl skopeo ];
# TODO:
# Shell Aliases don't work for direnv because they're not shell portable

23
fly.toml Normal file
View file

@ -0,0 +1,23 @@
# fly.toml app configuration file generated for mast-react-vite-cold-snowflake-8783 on 2025-02-19T23:28:02-08:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = 'mast-react-vite'
primary_region = 'sea'
[build]
image = 'react-server:latest'
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ['app']
[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1

View file

@ -54,56 +54,60 @@ export function DataTable<TData, TValue>({
}
})
return (
<div >
<Table >
<TableHeader className="bg-accent">
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}
className="relative text-foreground"
style={{
width: header.getSize(),
}}
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
return (
<div className="w-full overflow-x-auto">
<Table className="min-w-full table-fixed md:table-auto">
<TableHeader className="bg-accent flex flex-row md:table-header-group">
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="flex flex-row flex-wrap md:table-row">
{headerGroup.headers.map((header) => (
<TableHead
key={header.id}
className="relative text-foreground flex-1 min-w-[20px] flex items-center px-4 py-2 md:table-cell"
style={{
width: header.getSize(),
}}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody className="flex flex-col md:table-row-group">
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="flex flex-row flex-wrap md:table-row"
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className="flex-1 min-w-[20px] flex items-center px-4 py-2 md:table-cell"
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
)}
</TableBody>
</Table>
</div>
)
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
)
}

View file

@ -2,14 +2,15 @@ import { createRoot } from 'react-dom/client'
import './index.css'
import App from "./App.tsx";
import { DBAsync } from "@vlcn.io/xplat-api";
import initWasm from '@vlcn.io/crsqlite-wasm';
import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url';
import tblrx from '@vlcn.io/rx-tbl';
const sqlite = await initWasm(() => wasmUrl);
const db = await sqlite.open("todo.db");
await db.exec(`
const initDb = async () => {
const sqlite = await initWasm(() => wasmUrl);
const db: DBAsync = await sqlite.open("todo.db");
await db.exec(`
CREATE TABLE IF NOT EXISTS todos (
id BLOB PRIMARY KEY NOT NULL,
description TEXT,
@ -22,16 +23,19 @@ await db.exec(`
completed INTEGER NOT NULL DEFAULT 0
);
SELECT crsql_as_crr('todos');
`);
`);
const rx = tblrx(db);
return {db, rx};
}
const rx = tblrx(db);
const ctx = { db, rx };
const init = async () => {
const ctx = await initDb();
createRoot(document.getElementById("root") as HTMLElement).render(
<main className="min-h-screen flex flex-col py-12 bg-background text-gray-200">
<App ctx={ctx} />
</main>
);
}
document.getElementById("root")!.classList.add("dark");
createRoot(document.getElementById("root") as HTMLElement).render(
<main className="min-h-screen flex flex-col py-12 bg-background text-gray-200">
<App ctx={ctx} />
</main>
);
init();

View file

@ -4,6 +4,9 @@ import path from "path"
// https://vite.dev/config/
export default defineConfig({
server: {
host: true // This enables listening on all network interfaces
},
plugins: [react()],
resolve: {
alias: {

18
parser/command_parser.d.ts vendored Normal file
View file

@ -0,0 +1,18 @@
export interface Part {
type: 'text';
value: string;
reconstruct: () => string;
}
export interface Command {
type: 'add' | 'filter' | 'done';
description: string;
attributes: string[];
filters: string[];
project: string;
tags: string;
parts: Part[];
reconstruct: () => string;
}
export function parse(input: string): Command;

54
parser/filter_go.peg Normal file
View file

@ -0,0 +1,54 @@
{
package parser
type IdFilter struct {
Ids []int
}
}
Filter <- first:(IdRange / SingleId) rest:(',' (IdRange / SingleId))* {
var ids []int
first := toIntSlice(first)
ids = append(ids, first...)
if rest != nil {
for _, r := range rest.([]interface{}) {
restIds := toIntSlice(r.([]interface{})[1])
ids = append(ids, restIds...)
}
}
return &IdFilter{Ids: ids}, nil
}
IdRange <- start:Integer '-' end:Integer {
start := start.(int)
end := end.(int)
var ids []int
for i := start; i <= end; i++ {
ids = append(ids, i)
}
return ids, nil
}
SingleId <- id:Integer {
return []int{id.(int)}, nil
}
Integer <- [0-9]+ {
val := string(c.text)
n, _ := strconv.Atoi(val)
return n, nil
}
_ <- [ \t]*
{
func toIntSlice(v interface{}) []int {
if slice, ok := v.([]int); ok {
return slice
}
return nil
}
}

31
parser/filter_js.peg Normal file
View file

@ -0,0 +1,31 @@
{
function makeIdFilter(ids) {
return {
type: 'id_filter',
ids: ids.flat(),
reconstruct: function() {
return this.ids.join(',');
}
};
}
}
Filter = first:(IdRange / SingleId) rest:("," (IdRange / SingleId))* {
return makeIdFilter([first, ...rest.map(r => r[1])]);
}
IdRange = start:Integer "-" end:Integer {
const ids = [];
for (let i = start; i <= end; i++) {
ids.push(i);
}
return ids;
}
SingleId = id:Integer {
return [id];
}
Integer = digits:[0-9]+ {
return parseInt(digits.join(''), 10);
}

7
scripts/deploy.sh Normal file
View file

@ -0,0 +1,7 @@
#!/usr/bin/env bash
PROJECT_NAME=mast-react-vite
nix build .#react-server
skopeo --insecure-policy --debug copy docker-archive:"./result" "docker://registry.fly.io/$PROJECT_NAME:latest" --dest-creds x:"$(flyctl auth token)" --format v2s2
flyctl deploy -i "registry.fly.io/$PROJECT_NAME:latest" --remote-only