From: Taran Nathan Date: Sat, 26 Sep 2026 15:42:05 +0000 (-0700) Subject: defcon first X-Git-Url: https://git.taranathan.com/?a=commitdiff_plain;h=fe03e52f3b28cdd6ea5804fe37e80763dad8f72a;p=robotics-task-manager.git defcon first --- diff --git a/client/src/client.gleam b/client/src/client.gleam index 53923e8..64184da 100644 --- a/client/src/client.gleam +++ b/client/src/client.gleam @@ -1,3 +1,5 @@ +import gleam/dynamic +import gleam/dynamic/decode import gleam/int import gleam/json import gleam/list @@ -209,6 +211,11 @@ fn update(model: Model, message: Message) -> #(Model, Effect(Message)) { field(fields, "assignees"), model.task_subteams, field(fields, "due_date"), + list.key_find(fields, "defcon") + |> result.unwrap("") + |> dynamic.string + |> decode.run(decode.int) + |> result.unwrap(0), ) |> shared.new_task_json #( @@ -701,6 +708,7 @@ fn project_view(model: Model, project: shared.Project) -> Element(Message) { text_input("assignee", "Owner"), text_input("assignees", "Assignees"), text_input("due_date", "Due (MM/DD/YY)"), + text_input("defcon", "DEFCON"), subteam_checkboxes(model.task_subteams), html.textarea( [ @@ -850,6 +858,10 @@ fn task_view(task: shared.Task) -> Element(Message) { html.small([], [html.text("Subteams")]), html.text(if_blank(join_subteams(task.subteams), "No subteam")), ]), + html.div([attribute.class("task-person")], [ + html.small([], [html.text("DEFCON")]), + html.text(if_blank(int.to_string(task.defcon), "0")), + ]), html.div([attribute.class("task-due")], [ html.small([], [html.text("Due")]), html.text(case task.due_date { diff --git a/server/db/init.sql b/server/db/init.sql index 92900bb..015299d 100644 --- a/server/db/init.sql +++ b/server/db/init.sql @@ -25,7 +25,8 @@ create table if not exists task ( assignees text not null default '', subteams subteam[] not null default '{}'::subteam[], due_date date, - created_at timestamptz not null default now() + created_at timestamptz not null default now(), + defcon int not null default 0 ); alter table task add column if not exists assignees text not null default ''; diff --git a/server/src/server.gleam b/server/src/server.gleam index 95b76b5..4014b49 100644 --- a/server/src/server.gleam +++ b/server/src/server.gleam @@ -303,6 +303,7 @@ fn add_task( task.assignees, list.map(task.subteams, to_sql_subteam), task.due_date, + task.defcon, ) wisp.json_response("{\"ok\":true}", 201) } @@ -362,6 +363,7 @@ fn to_shared_task(task: sql.ListTasksRow) -> shared.Task { assignees: task.assignees, subteams: string.split(task.subteams, ","), due_date: task.due_date, + defcon: task.defcon, ) } diff --git a/server/src/sql.gleam b/server/src/sql.gleam index 2d5ee9a..ba967e2 100644 --- a/server/src/sql.gleam +++ b/server/src/sql.gleam @@ -118,6 +118,7 @@ pub fn create_task( arg_5: String, arg_6: List(Subteam), arg_7: String, + arg_8: Int, ) -> Result(pog.Returned(CreateTaskRow), pog.QueryError) { let decoder = { use id <- decode.field(0, decode.int) @@ -131,9 +132,10 @@ pub fn create_task( assignee, assignees, subteams, - due_date + due_date, + defcon ) -values ($1, $2, $3, $4, $5, $6::subteam[], nullif($7, '')::date) +values ($1, $2, $3, $4, $5, $6::subteam[], nullif($7, '')::date, $8) returning id " |> pog.query @@ -144,6 +146,7 @@ returning id |> pog.parameter(pog.text(arg_5)) |> pog.parameter(pog.array(fn(value) { subteam_encoder(value) }, arg_6)) |> pog.parameter(pog.text(arg_7)) + |> pog.parameter(pog.int(arg_8)) |> pog.returning(decoder) |> pog.execute(db) } @@ -386,6 +389,7 @@ pub type ListTasksRow { status: String, assignee: String, assignees: String, + defcon: Int, subteams: String, due_date: String, ) @@ -409,8 +413,9 @@ pub fn list_tasks( use status <- decode.field(4, decode.string) use assignee <- decode.field(5, decode.string) use assignees <- decode.field(6, decode.string) - use subteams <- decode.field(7, decode.string) - use due_date <- decode.field(8, decode.string) + use defcon <- decode.field(7, decode.int) + use subteams <- decode.field(8, decode.string) + use due_date <- decode.field(9, decode.string) decode.success(ListTasksRow( id:, project_id:, @@ -419,6 +424,7 @@ pub fn list_tasks( status:, assignee:, assignees:, + defcon:, subteams:, due_date:, )) @@ -432,6 +438,7 @@ pub fn list_tasks( status, assignee, assignees, + defcon, coalesce(array_to_string(subteams, ','), '') as subteams, coalesce(due_date::text, '') as due_date from task diff --git a/server/src/sql/create_task.sql b/server/src/sql/create_task.sql index 12c089a..a4a9c6a 100644 --- a/server/src/sql/create_task.sql +++ b/server/src/sql/create_task.sql @@ -5,7 +5,8 @@ insert into task ( assignee, assignees, subteams, - due_date + due_date, + defcon ) -values ($1, $2, $3, $4, $5, $6::subteam[], nullif($7, '')::date) +values ($1, $2, $3, $4, $5, $6::subteam[], nullif($7, '')::date, $8) returning id diff --git a/server/src/sql/list_tasks.sql b/server/src/sql/list_tasks.sql index 27b0807..6fd52e2 100644 --- a/server/src/sql/list_tasks.sql +++ b/server/src/sql/list_tasks.sql @@ -6,6 +6,7 @@ select status, assignee, assignees, + defcon, coalesce(array_to_string(subteams, ','), '') as subteams, coalesce(due_date::text, '') as due_date from task diff --git a/server/static/client.js b/server/static/client.js index 84839b5..f92bb97 100644 --- a/server/static/client.js +++ b/server/static/client.js @@ -2170,6 +2170,9 @@ function string4(input) { function bool2(input) { return identity2(input); } +function int3(input) { + return identity2(input); +} function object2(entries) { return object(entries); } @@ -7127,7 +7130,7 @@ class Project extends CustomType { } } class Task extends CustomType { - constructor(id, project_id, title2, description, status, assignee, assignees, subteams, due_date) { + constructor(id, project_id, title2, description, status, assignee, assignees, subteams, due_date, defcon) { super(); this.id = id; this.project_id = project_id; @@ -7138,6 +7141,7 @@ class Task extends CustomType { this.assignees = assignees; this.subteams = subteams; this.due_date = due_date; + this.defcon = defcon; } } class Dashboard extends CustomType { @@ -7163,7 +7167,7 @@ class NewProject extends CustomType { } } class NewTask extends CustomType { - constructor(title2, description, assignee, assignees, subteams, due_date) { + constructor(title2, description, assignee, assignees, subteams, due_date, defcon) { super(); this.title = title2; this.description = description; @@ -7171,6 +7175,7 @@ class NewTask extends CustomType { this.assignees = assignees; this.subteams = subteams; this.due_date = due_date; + this.defcon = defcon; } } class StatusChange extends CustomType { @@ -7189,7 +7194,9 @@ function task_decoder() { return field("assignees", string3, (assignees) => { return field("subteams", list2(string3), (subteams) => { return field("due_date", string3, (due_date) => { - return success(new Task(id, project_id, title2, description, status, assignee, assignees, subteams, due_date)); + return field("defcon", int2, (defcon) => { + return success(new Task(id, project_id, title2, description, status, assignee, assignees, subteams, due_date, defcon)); + }); }); }); }); @@ -7240,7 +7247,8 @@ function new_task_json(value3) { ["assignee", string4(value3.assignee)], ["assignees", string4(value3.assignees)], ["subteams", array2(value3.subteams, string4)], - ["due_date", string4(value3.due_date)] + ["due_date", string4(value3.due_date)], + ["defcon", int3(value3.defcon)] ])); } function status_change_json(value3) { @@ -7515,9 +7523,6 @@ function left_status_button(task) { return none2(); } } -function join_subteams(subteams) { - return join(subteams, ", "); -} function if_blank(value3, fallback) { let $ = value3 === ""; if ($) { @@ -7526,6 +7531,9 @@ function if_blank(value3, fallback) { return value3; } } +function join_subteams(subteams) { + return join(subteams, ", "); +} function task_view(task) { return div(toList([class$("task")]), toList([ div(toList([class$("task-header")]), toList([ @@ -7552,6 +7560,10 @@ function task_view(task) { small(List$Empty$const, toList([text3("Subteams")])), text3(if_blank(join_subteams(task.subteams), "No subteam")) ])), + div(toList([class$("task-person")]), toList([ + small(List$Empty$const, toList([text3("DEFCON")])), + text3(if_blank(to_string(task.defcon), "0")) + ])), div(toList([class$("task-due")]), toList([ small(List$Empty$const, toList([text3("Due")])), text3((() => { @@ -7639,6 +7651,7 @@ function project_view(model, project) { text_input("assignee", "Owner"), text_input("assignees", "Assignees"), text_input("due_date", "Due (MM/DD/YY)"), + text_input("defcon", "DEFCON"), subteam_checkboxes(model.task_subteams), textarea(toList([ class$("task-description-input"), @@ -7926,7 +7939,7 @@ function update_task_status(model, task_id, status) { let tasks = map2(project.tasks, (task) => { let $1 = task.id === task_id; if ($1) { - return new Task(task.id, task.project_id, task.title, task.description, status, task.assignee, task.assignees, task.subteams, task.due_date); + return new Task(task.id, task.project_id, task.title, task.description, status, task.assignee, task.assignees, task.subteams, task.due_date, task.defcon); } else { return task; } @@ -8026,7 +8039,13 @@ function update2(model, message2) { let project_id = message2[0]; let fields = message2[1]; let _block; - let _pipe = new NewTask(field2(fields, "title"), field2(fields, "description"), field2(fields, "assignee"), field2(fields, "assignees"), model.task_subteams, field2(fields, "due_date")); + let _pipe = new NewTask(field2(fields, "title"), field2(fields, "description"), field2(fields, "assignee"), field2(fields, "assignees"), model.task_subteams, field2(fields, "due_date"), (() => { + let _pipe2 = key_find(fields, "defcon"); + let _pipe$1 = unwrap2(_pipe2, ""); + let _pipe$2 = identity(_pipe$1); + let _pipe$3 = run(_pipe$2, int2); + return unwrap2(_pipe$3, 0); + })()); _block = new_task_json(_pipe); let body2 = _block; return [ @@ -8270,7 +8289,7 @@ function main2() { let app = application(init, update2, view); let $ = start4(app, "#app", Option$None$const); if (!($ instanceof Ok)) { - throw makeError("let_assert", FILEPATH, "client", 20, "main", "Pattern match failed, no pattern matched the value.", { value: $, start: 459, end: 509, pattern_start: 470, pattern_end: 475 }); + throw makeError("let_assert", FILEPATH, "client", 22, "main", "Pattern match failed, no pattern matched the value.", { value: $, start: 508, end: 558, pattern_start: 519, pattern_end: 524 }); } return; } diff --git a/shared/src/shared.gleam b/shared/src/shared.gleam index ec8f0de..378cc21 100644 --- a/shared/src/shared.gleam +++ b/shared/src/shared.gleam @@ -22,6 +22,7 @@ pub type Task { assignees: String, subteams: List(String), due_date: String, + defcon: Int, ) } @@ -45,6 +46,7 @@ pub type NewTask { assignees: String, subteams: List(String), due_date: String, + defcon: Int, ) } @@ -77,7 +79,19 @@ fn task_decoder() -> decode.Decoder(Task) { use assignees <- decode.field("assignees", decode.string) use subteams <- decode.field("subteams", decode.list(decode.string)) use due_date <- decode.field("due_date", decode.string) - decode.success(Task(id:, project_id:, title:, description:, status:, assignee:, assignees:, subteams:, due_date:)) + use defcon <- decode.field("defcon", decode.int) + decode.success(Task( + id:, + project_id:, + title:, + description:, + status:, + assignee:, + assignees:, + subteams:, + due_date:, + defcon:, + )) } pub fn credentials_decoder() -> decode.Decoder(Credentials) { @@ -100,7 +114,16 @@ pub fn new_task_decoder() -> decode.Decoder(NewTask) { use assignees <- decode.field("assignees", decode.string) use subteams <- decode.field("subteams", decode.list(decode.string)) use due_date <- decode.field("due_date", decode.string) - decode.success(NewTask(title:, description:, assignee:, assignees:, subteams:, due_date:)) + use defcon <- decode.field("defcon", decode.int) + decode.success(NewTask( + title:, + description:, + assignee:, + assignees:, + subteams:, + due_date:, + defcon:, + )) } pub fn status_change_decoder() -> decode.Decoder(StatusChange) { @@ -137,6 +160,7 @@ fn task_json(value: Task) -> json.Json { #("assignees", json.string(value.assignees)), #("subteams", json.array(value.subteams, json.string)), #("due_date", json.string(value.due_date)), + #("defcon", json.int(value.defcon)), ]) } @@ -163,6 +187,7 @@ pub fn new_task_json(value: NewTask) -> json.Json { #("assignees", json.string(value.assignees)), #("subteams", json.array(value.subteams, json.string)), #("due_date", json.string(value.due_date)), + #("defcon", json.int(value.defcon)), ]) }