From 7816b51957e8fb65ce0a06e05db1328c19a74b6c Mon Sep 17 00:00:00 2001 From: Daniel Covington Date: Fri, 24 Apr 2026 08:56:23 -0400 Subject: [PATCH] version 1 is done --- app/controllers/BoardsController.asp | 47 ++++- app/controllers/CardsController.asp | 82 ++++++-- app/controllers/ColumnsController.asp | 29 ++- app/controllers/SwimLanesController.asp | 29 ++- app/models/POBO_boards.asp | 26 ++- app/models/POBO_cards.asp | 51 +++-- app/repositories/boards_Repository.asp | 14 +- app/repositories/cards_Repository.asp | 28 ++- app/views/Boards/Create.asp | 26 ++- app/views/Boards/Edit.asp | 25 +++ app/views/Boards/Show.asp | 24 ++- app/views/Cards/_modal.asp | 22 +++ ...260423100000_add_printstream_to_boards.asp | 15 ++ ...100000_add_printstream_fields_to_cards.asp | 19 ++ .../20260424200000_add_full_note_to_cards.asp | 13 ++ db/webdata.accdb | Bin 704512 -> 1024000 bytes public/css/kanban.css | 178 +++++++++++++++-- public/js/kanban-board.js | 180 ++++++++++++++++-- public/js/kanban-modal.js | 44 ++++- scripts/importPrintStreamJobs.vbs | Bin 0 -> 36468 bytes scripts/migrate_isbusiness_to_households.vbs | 90 --------- 21 files changed, 745 insertions(+), 197 deletions(-) create mode 100644 db/migrations/20260423100000_add_printstream_to_boards.asp create mode 100644 db/migrations/20260424100000_add_printstream_fields_to_cards.asp create mode 100644 db/migrations/20260424200000_add_full_note_to_cards.asp create mode 100644 scripts/importPrintStreamJobs.vbs delete mode 100644 scripts/migrate_isbusiness_to_households.vbs diff --git a/app/controllers/BoardsController.asp b/app/controllers/BoardsController.asp index 83a4454..99076bb 100644 --- a/app/controllers/BoardsController.asp +++ b/app/controllers/BoardsController.asp @@ -50,12 +50,14 @@ Class BoardsController_Class slug = boards_Repository().UniqueSlug(GenerateSlug(boardName), 0) Dim board : Set board = New POBO_boards - board.name = boardName - board.slug = slug - board.created_at = Now() - board.created_by = currentUsername - board.updated_at = Now() - board.updated_by = currentUsername + board.name = boardName + board.slug = slug + board.import_from_printstream = (Request.Form("import_from_printstream") = "on") + board.printstream_job_name = Trim(CStr(Request.Form("printstream_job_name"))) + board.created_at = Now() + board.created_by = currentUsername + board.updated_at = Now() + board.updated_by = currentUsername boards_Repository().AddNew board @@ -117,6 +119,11 @@ Class BoardsController_Class """swim_lane_id"":" & cardItem.swim_lane_id & "," & _ """job_number"":" & JsonStr(cardItem.job_number) & "," & _ """job_name"":" & JsonStr(cardItem.job_name) & "," & _ + """customer_name"":" & JsonStr(cardItem.customer_name) & "," & _ + """delivery_date"":" & JsonDateStr(cardItem.delivery_date) & "," & _ + """quantity"":" & JsonStr(cardItem.quantity) & "," & _ + """notes"":" & JsonStr(cardItem.notes) & "," & _ + """full_note"":" & JsonStr(cardItem.full_note) & "," & _ """position"":" & cardItem.position & "}" firstCard = False Loop @@ -168,10 +175,12 @@ Class BoardsController_Class Dim newSlug : newSlug = boards_Repository().UniqueSlug(GenerateSlug(newName), CLng(board.id)) - board.name = newName - board.slug = newSlug - board.updated_at = Now() - board.updated_by = GetCurrentUsername() + board.name = newName + board.slug = newSlug + board.import_from_printstream = (Request.Form("import_from_printstream") = "on") + board.printstream_job_name = Trim(CStr(Request.Form("printstream_job_name"))) + board.updated_at = Now() + board.updated_by = GetCurrentUsername() boards_Repository().Update board @@ -226,6 +235,24 @@ Class BoardsController_Class JsonStr = """" & v & """" End Function + Private Function JsonDateStr(d) + If IsNull(d) Or IsEmpty(d) Then + JsonDateStr = "null" + Exit Function + End If + On Error Resume Next + Dim dt, s + dt = CDate(d) + s = Year(dt) & "-" & Right("0" & Month(dt), 2) & "-" & Right("0" & Day(dt), 2) + If Err.Number <> 0 Then + Err.Clear + JsonDateStr = "null" + Else + JsonDateStr = """" & s & """" + End If + On Error GoTo 0 + End Function + End Class Dim BoardsController_Class__Singleton diff --git a/app/controllers/CardsController.asp b/app/controllers/CardsController.asp index 0d03abc..ead4d08 100644 --- a/app/controllers/CardsController.asp +++ b/app/controllers/CardsController.asp @@ -37,22 +37,39 @@ Class CardsController_Class Dim username : username = GetCurrentUsername() Dim card : Set card = New POBO_cards - card.board_id = boardId - card.column_id = columnId - card.swim_lane_id = swimLaneId - card.job_number = jobNum - card.job_name = jobName - card.position = nextPos - card.created_at = Now() - card.created_by = username - card.updated_at = Now() - card.updated_by = username + card.board_id = boardId + card.column_id = columnId + card.swim_lane_id = swimLaneId + card.job_number = jobNum + card.job_name = jobName + card.customer_name = Trim(CStr(Request.Form("customer_name") & "")) + card.delivery_date = Trim(CStr(Request.Form("delivery_date") & "")) + card.quantity = Trim(CStr(Request.Form("quantity") & "")) + card.notes = Trim(CStr(Request.Form("notes") & "")) + card.full_note = CStr(Request.Form("full_note") & "") + card.position = nextPos + card.created_at = Now() + card.created_by = username + card.updated_at = Now() + card.updated_by = username + On Error Resume Next cards_Repository().AddNew card + If Err.Number <> 0 Then + Response.Write "{""ok"":false,""error"":" & JsonString(Err.Description) & "}" + Err.Clear + Exit Sub + End If + On Error GoTo 0 Response.Write "{""ok"":true,""id"":" & card.id & "," & _ """job_number"":" & JsonString(card.job_number) & "," & _ """job_name"":" & JsonString(card.job_name) & "," & _ + """customer_name"":" & JsonString(card.customer_name) & "," & _ + """delivery_date"":" & JsonDateStr(card.delivery_date) & "," & _ + """quantity"":" & JsonString(card.quantity) & "," & _ + """notes"":" & JsonString(card.notes) & "," & _ + """full_note"":" & JsonString(card.full_note) & "," & _ """column_id"":" & card.column_id & "," & _ """swim_lane_id"":" & card.swim_lane_id & "," & _ """position"":" & card.position & "}" @@ -77,14 +94,31 @@ Class CardsController_Class card.job_number = Trim(CStr(Request.Form("job_number"))) card.job_name = Trim(CStr(Request.Form("job_name"))) + card.customer_name = Trim(CStr(Request.Form("customer_name") & "")) + card.delivery_date = Trim(CStr(Request.Form("delivery_date") & "")) + card.quantity = Trim(CStr(Request.Form("quantity") & "")) + card.notes = Trim(CStr(Request.Form("notes") & "")) + card.full_note = CStr(Request.Form("full_note") & "") card.updated_at = Now() card.updated_by = GetCurrentUsername() + On Error Resume Next cards_Repository().Update card + If Err.Number <> 0 Then + Response.Write "{""ok"":false,""error"":" & JsonString(Err.Description) & "}" + Err.Clear + Exit Sub + End If + On Error GoTo 0 Response.Write "{""ok"":true," & _ """job_number"":" & JsonString(card.job_number) & "," & _ - """job_name"":" & JsonString(card.job_name) & "}" + """job_name"":" & JsonString(card.job_name) & "," & _ + """customer_name"":" & JsonString(card.customer_name) & "," & _ + """delivery_date"":" & JsonDateStr(card.delivery_date) & "," & _ + """quantity"":" & JsonString(card.quantity) & "," & _ + """notes"":" & JsonString(card.notes) & "," & _ + """full_note"":" & JsonString(card.full_note) & "}" End Sub ' POST /cards/:id/move — form: column_id, swim_lane_id, position, [sibling_ids CSV for reorder] @@ -147,7 +181,31 @@ Class CardsController_Class End Function Private Function JsonString(s) - JsonString = """" & Replace(Replace(CStr(s), "\", "\\"), """", "\""") & """" + Dim v : v = CStr(s & "") + v = Replace(v, "\", "\\") + v = Replace(v, """", "\""") + v = Replace(v, vbCrLf, "\n") + v = Replace(v, vbLf, "\n") + v = Replace(v, vbCr, "\n") + JsonString = """" & v & """" + End Function + + Private Function JsonDateStr(d) + If IsNull(d) Or IsEmpty(d) Then + JsonDateStr = "null" + Exit Function + End If + On Error Resume Next + Dim dt, s + dt = CDate(d) + s = Year(dt) & "-" & Right("0" & Month(dt), 2) & "-" & Right("0" & Day(dt), 2) + If Err.Number <> 0 Then + Err.Clear + JsonDateStr = "null" + Else + JsonDateStr = """" & s & """" + End If + On Error GoTo 0 End Function End Class diff --git a/app/controllers/ColumnsController.asp b/app/controllers/ColumnsController.asp index 697080f..01a2305 100644 --- a/app/controllers/ColumnsController.asp +++ b/app/controllers/ColumnsController.asp @@ -102,19 +102,42 @@ Class ColumnsController_Class End If Dim rawJson : rawJson = GetRawJsonFromRequest() - Dim parsed : Set parsed = JSON.parse(rawJson) + Dim parser : Set parser = New aspJSON + Dim parsed - If IsNull(parsed) Or IsEmpty(parsed) Then - Response.Write "{""ok"":false,""error"":""Invalid JSON""}" + On Error Resume Next + parser.loadJSON rawJson + If Err.Number <> 0 Then + Err.Clear + Set parser = Nothing + Response.Write "{""ok"":false,""error"":""Invalid JSON payload""}" + Exit Sub + End If + Set parsed = parser.data + On Error GoTo 0 + + If parsed Is Nothing Or parsed.Count = 0 Then + Set parser = Nothing + Response.Write "{""ok"":false,""error"":""Invalid JSON payload""}" Exit Sub End If Dim username : username = GetCurrentUsername() Dim i, item + On Error Resume Next For i = 0 To parsed.Count - 1 Set item = parsed.Item(i) board_columns_Repository().UpdatePosition CLng(item.Item("id")), CLng(item.Item("position")), Now(), username + If Err.Number <> 0 Then + Err.Clear + On Error GoTo 0 + Set parser = Nothing + Response.Write "{""ok"":false,""error"":""Invalid reorder item at index " & i & """}" + Exit Sub + End If Next + On Error GoTo 0 + Set parser = Nothing Response.Write "{""ok"":true}" End Sub diff --git a/app/controllers/SwimLanesController.asp b/app/controllers/SwimLanesController.asp index 0b0a4ed..fd6dbe4 100644 --- a/app/controllers/SwimLanesController.asp +++ b/app/controllers/SwimLanesController.asp @@ -102,19 +102,42 @@ Class SwimLanesController_Class End If Dim rawJson : rawJson = GetRawJsonFromRequest() - Dim parsed : Set parsed = JSON.parse(rawJson) + Dim parser : Set parser = New aspJSON + Dim parsed - If IsNull(parsed) Or IsEmpty(parsed) Then - Response.Write "{""ok"":false,""error"":""Invalid JSON""}" + On Error Resume Next + parser.loadJSON rawJson + If Err.Number <> 0 Then + Err.Clear + Set parser = Nothing + Response.Write "{""ok"":false,""error"":""Invalid JSON payload""}" + Exit Sub + End If + Set parsed = parser.data + On Error GoTo 0 + + If parsed Is Nothing Or parsed.Count = 0 Then + Set parser = Nothing + Response.Write "{""ok"":false,""error"":""Invalid JSON payload""}" Exit Sub End If Dim username : username = GetCurrentUsername() Dim i, item + On Error Resume Next For i = 0 To parsed.Count - 1 Set item = parsed.Item(i) swim_lanes_Repository().UpdatePosition CLng(item.Item("id")), CLng(item.Item("position")), Now(), username + If Err.Number <> 0 Then + Err.Clear + On Error GoTo 0 + Set parser = Nothing + Response.Write "{""ok"":false,""error"":""Invalid reorder item at index " & i & """}" + Exit Sub + End If Next + On Error GoTo 0 + Set parser = Nothing Response.Write "{""ok"":true}" End Sub diff --git a/app/models/POBO_boards.asp b/app/models/POBO_boards.asp index 6e2ba45..b50446d 100644 --- a/app/models/POBO_boards.asp +++ b/app/models/POBO_boards.asp @@ -5,20 +5,24 @@ Class POBO_boards Private p_id Private p_name Private p_slug + Private p_import_from_printstream + Private p_printstream_job_name Private p_created_at Private p_created_by Private p_updated_at Private p_updated_by Private Sub Class_Initialize() - p_id = 0 - p_name = "" - p_slug = "" - p_created_at = #1/1/1970# - p_created_by = "" - p_updated_at = #1/1/1970# - p_updated_by = "" - Properties = Array("id","name","slug","created_at","created_by","updated_at","updated_by") + p_id = 0 + p_name = "" + p_slug = "" + p_import_from_printstream = False + p_printstream_job_name = "" + p_created_at = #1/1/1970# + p_created_by = "" + p_updated_at = #1/1/1970# + p_updated_by = "" + Properties = Array("id","name","slug","import_from_printstream","printstream_job_name","created_at","created_by","updated_at","updated_by") End Sub Public Property Get PrimaryKey() : PrimaryKey = "id" : End Property @@ -33,6 +37,12 @@ Class POBO_boards Public Property Get slug() : slug = p_slug : End Property Public Property Let slug(v) : p_slug = CStr(v) : End Property + Public Property Get import_from_printstream() : import_from_printstream = p_import_from_printstream : End Property + Public Property Let import_from_printstream(v) : p_import_from_printstream = CBool(v) : End Property + + Public Property Get printstream_job_name() : printstream_job_name = p_printstream_job_name : End Property + Public Property Let printstream_job_name(v) : p_printstream_job_name = CStr(v) : End Property + Public Property Get created_at() : created_at = p_created_at : End Property Public Property Let created_at(v) : p_created_at = CDate(v) : End Property diff --git a/app/models/POBO_cards.asp b/app/models/POBO_cards.asp index 619388c..dd26dc9 100644 --- a/app/models/POBO_cards.asp +++ b/app/models/POBO_cards.asp @@ -8,6 +8,11 @@ Class POBO_cards Private p_swim_lane_id Private p_job_number Private p_job_name + Private p_customer_name + Private p_delivery_date + Private p_quantity + Private p_notes + Private p_full_note Private p_position Private p_created_at Private p_created_by @@ -15,18 +20,23 @@ Class POBO_cards Private p_updated_by Private Sub Class_Initialize() - p_id = 0 - p_board_id = 0 - p_column_id = 0 - p_swim_lane_id = 0 - p_job_number = "" - p_job_name = "" - p_position = 0 - p_created_at = #1/1/1970# - p_created_by = "" - p_updated_at = #1/1/1970# - p_updated_by = "" - Properties = Array("id","board_id","column_id","swim_lane_id","job_number","job_name","position","created_at","created_by","updated_at","updated_by") + p_id = 0 + p_board_id = 0 + p_column_id = 0 + p_swim_lane_id = 0 + p_job_number = "" + p_job_name = "" + p_customer_name = "" + p_delivery_date = Null + p_quantity = "" + p_notes = "" + p_full_note = "" + p_position = 0 + p_created_at = #1/1/1970# + p_created_by = "" + p_updated_at = #1/1/1970# + p_updated_by = "" + Properties = Array("id","board_id","column_id","swim_lane_id","job_number","job_name","customer_name","delivery_date","quantity","notes","full_note","position","created_at","created_by","updated_at","updated_by") End Sub Public Property Get PrimaryKey() : PrimaryKey = "id" : End Property @@ -50,6 +60,23 @@ Class POBO_cards Public Property Get job_name() : job_name = p_job_name : End Property Public Property Let job_name(v) : p_job_name = CStr(v) : End Property + Public Property Get customer_name() : customer_name = p_customer_name : End Property + Public Property Let customer_name(v) : p_customer_name = CStr(v & "") : End Property + + Public Property Get delivery_date() : delivery_date = p_delivery_date : End Property + Public Property Let delivery_date(v) + If IsDate(v) Then p_delivery_date = CDate(v) Else p_delivery_date = Null + End Property + + Public Property Get quantity() : quantity = p_quantity : End Property + Public Property Let quantity(v) : p_quantity = CStr(v & "") : End Property + + Public Property Get notes() : notes = p_notes : End Property + Public Property Let notes(v) : p_notes = CStr(v & "") : End Property + + Public Property Get full_note() : full_note = p_full_note : End Property + Public Property Let full_note(v) : p_full_note = CStr(v & "") : End Property + Public Property Get position() : position = p_position : End Property Public Property Let position(v) : p_position = CDbl(v) : End Property diff --git a/app/repositories/boards_Repository.asp b/app/repositories/boards_Repository.asp index 3465774..14e7d59 100644 --- a/app/repositories/boards_Repository.asp +++ b/app/repositories/boards_Repository.asp @@ -2,7 +2,7 @@ Class boards_Repository_Class Public Function FindByID(id) - Dim sql : sql = "SELECT [id],[name],[slug],[created_at],[created_by],[updated_at],[updated_by] FROM [boards] WHERE [id] = ?" + Dim sql : sql = "SELECT [id],[name],[slug],[import_from_printstream],[printstream_job_name],[created_at],[created_by],[updated_at],[updated_by] FROM [boards] WHERE [id] = ?" Dim rs : Set rs = DAL.Query(sql, Array(id)) If rs.EOF Then Err.Raise 1, "boards_Repository_Class", "Board not found with id = " & id @@ -13,7 +13,7 @@ Class boards_Repository_Class End Function Public Function FindBySlug(slug) - Dim sql : sql = "SELECT [id],[name],[slug],[created_at],[created_by],[updated_at],[updated_by] FROM [boards] WHERE [slug] = ?" + Dim sql : sql = "SELECT [id],[name],[slug],[import_from_printstream],[printstream_job_name],[created_at],[created_by],[updated_at],[updated_by] FROM [boards] WHERE [slug] = ?" Dim rs : Set rs = DAL.Query(sql, Array(slug)) If rs.EOF Then Set FindBySlug = Nothing @@ -24,7 +24,7 @@ Class boards_Repository_Class End Function Public Function GetAll() - Dim sql : sql = "SELECT [id],[name],[slug],[created_at],[created_by],[updated_at],[updated_by] FROM [boards] ORDER BY [name] ASC" + Dim sql : sql = "SELECT [id],[name],[slug],[import_from_printstream],[printstream_job_name],[created_at],[created_by],[updated_at],[updated_by] FROM [boards] ORDER BY [name] ASC" Dim rs : Set rs = DAL.Query(sql, Empty) Dim list : Set list = New LinkedList_Class Do Until rs.EOF @@ -60,8 +60,8 @@ Class boards_Repository_Class End Function Public Sub AddNew(ByRef model) - Dim sql : sql = "INSERT INTO [boards] ([name],[slug],[created_at],[created_by],[updated_at],[updated_by]) VALUES (?,?,?,?,?,?)" - DAL.Execute sql, Array(model.name, model.slug, model.created_at, model.created_by, model.updated_at, model.updated_by) + Dim sql : sql = "INSERT INTO [boards] ([name],[slug],[import_from_printstream],[printstream_job_name],[created_at],[created_by],[updated_at],[updated_by]) VALUES (?,?,?,?,?,?,?,?)" + DAL.Execute sql, Array(model.name, model.slug, model.import_from_printstream, model.printstream_job_name, model.created_at, model.created_by, model.updated_at, model.updated_by) Dim rsId : Set rsId = DAL.Query("SELECT @@IDENTITY AS NewID", Empty) If Not rsId.EOF Then If Not IsNull(rsId(0)) Then model.id = rsId(0) @@ -70,8 +70,8 @@ Class boards_Repository_Class End Sub Public Sub Update(model) - Dim sql : sql = "UPDATE [boards] SET [name]=?,[slug]=?,[updated_at]=?,[updated_by]=? WHERE [id]=?" - DAL.Execute sql, Array(model.name, model.slug, model.updated_at, model.updated_by, model.id) + Dim sql : sql = "UPDATE [boards] SET [name]=?,[slug]=?,[import_from_printstream]=?,[printstream_job_name]=?,[updated_at]=?,[updated_by]=? WHERE [id]=?" + DAL.Execute sql, Array(model.name, model.slug, model.import_from_printstream, model.printstream_job_name, model.updated_at, model.updated_by, model.id) End Sub Public Sub Delete(id) diff --git a/app/repositories/cards_Repository.asp b/app/repositories/cards_Repository.asp index 05026f2..90a322a 100644 --- a/app/repositories/cards_Repository.asp +++ b/app/repositories/cards_Repository.asp @@ -2,7 +2,7 @@ Class cards_Repository_Class Private Function SelectBase() - SelectBase = "SELECT [id],[board_id],[column_id],[swim_lane_id],[job_number],[job_name],[position],[created_at],[created_by],[updated_at],[updated_by] FROM [cards]" + SelectBase = "SELECT [id],[board_id],[column_id],[swim_lane_id],[job_number],[job_name],[customer_name],[delivery_date],[quantity],[notes],[full_note],[position],[created_at],[created_by],[updated_at],[updated_by] FROM [cards]" End Function Public Function FindByID(id) @@ -52,8 +52,15 @@ Class cards_Repository_Class End Function Public Sub AddNew(ByRef model) - Dim sql : sql = "INSERT INTO [cards] ([board_id],[column_id],[swim_lane_id],[job_number],[job_name],[position],[created_at],[created_by],[updated_at],[updated_by]) VALUES (?,?,?,?,?,?,?,?,?,?)" - DAL.Execute sql, Array(model.board_id, model.column_id, model.swim_lane_id, model.job_number, model.job_name, model.position, model.created_at, model.created_by, model.updated_at, model.updated_by) + Dim sql, params + If QuantityIsBlank(model.quantity) Then + sql = "INSERT INTO [cards] ([board_id],[column_id],[swim_lane_id],[job_number],[job_name],[customer_name],[delivery_date],[quantity],[notes],[full_note],[position],[created_at],[created_by],[updated_at],[updated_by]) VALUES (?,?,?,?,?,?,?,NULL,?,?,?,?,?,?,?)" + params = Array(model.board_id, model.column_id, model.swim_lane_id, model.job_number, model.job_name, model.customer_name, model.delivery_date, model.notes, model.full_note, model.position, model.created_at, model.created_by, model.updated_at, model.updated_by) + Else + sql = "INSERT INTO [cards] ([board_id],[column_id],[swim_lane_id],[job_number],[job_name],[customer_name],[delivery_date],[quantity],[notes],[full_note],[position],[created_at],[created_by],[updated_at],[updated_by]) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" + params = Array(model.board_id, model.column_id, model.swim_lane_id, model.job_number, model.job_name, model.customer_name, model.delivery_date, model.quantity, model.notes, model.full_note, model.position, model.created_at, model.created_by, model.updated_at, model.updated_by) + End If + DAL.Execute sql, params Dim rsId : Set rsId = DAL.Query("SELECT @@IDENTITY AS NewID", Empty) If Not rsId.EOF Then If Not IsNull(rsId(0)) Then model.id = rsId(0) @@ -62,10 +69,21 @@ Class cards_Repository_Class End Sub Public Sub Update(model) - Dim sql : sql = "UPDATE [cards] SET [job_number]=?,[job_name]=?,[updated_at]=?,[updated_by]=? WHERE [id]=?" - DAL.Execute sql, Array(model.job_number, model.job_name, model.updated_at, model.updated_by, model.id) + Dim sql, params + If QuantityIsBlank(model.quantity) Then + sql = "UPDATE [cards] SET [job_number]=?,[job_name]=?,[customer_name]=?,[delivery_date]=?,[quantity]=NULL,[notes]=?,[full_note]=?,[updated_at]=?,[updated_by]=? WHERE [id]=?" + params = Array(model.job_number, model.job_name, model.customer_name, model.delivery_date, model.notes, model.full_note, model.updated_at, model.updated_by, model.id) + Else + sql = "UPDATE [cards] SET [job_number]=?,[job_name]=?,[customer_name]=?,[delivery_date]=?,[quantity]=?,[notes]=?,[full_note]=?,[updated_at]=?,[updated_by]=? WHERE [id]=?" + params = Array(model.job_number, model.job_name, model.customer_name, model.delivery_date, model.quantity, model.notes, model.full_note, model.updated_at, model.updated_by, model.id) + End If + DAL.Execute sql, params End Sub + Private Function QuantityIsBlank(v) + QuantityIsBlank = (Len(Trim(CStr(v & ""))) = 0) + End Function + Public Sub Move(id, columnId, swimLaneId, position, updatedAt, updatedBy) Dim sql : sql = "UPDATE [cards] SET [column_id]=?,[swim_lane_id]=?,[position]=?,[updated_at]=?,[updated_by]=? WHERE [id]=?" DAL.Execute sql, Array(columnId, swimLaneId, position, updatedAt, updatedBy, id) diff --git a/app/views/Boards/Create.asp b/app/views/Boards/Create.asp index 735ec4a..9e941d1 100644 --- a/app/views/Boards/Create.asp +++ b/app/views/Boards/Create.asp @@ -19,6 +19,18 @@
 
+
+
+ + +
+
+
Cancel @@ -31,11 +43,19 @@ diff --git a/app/views/Boards/Show.asp b/app/views/Boards/Show.asp index dfab647..4e0b162 100644 --- a/app/views/Boards/Show.asp +++ b/app/views/Boards/Show.asp @@ -10,8 +10,11 @@ Response.CodePage = 65001 - - + + + + + @@ -23,6 +26,20 @@ Response.CodePage = 65001 <%= H(board.name) %>
+
<%= H(vLaneItem.name) %>
diff --git a/app/views/Cards/_modal.asp b/app/views/Cards/_modal.asp index f2a8a05..609bbc2 100644 --- a/app/views/Cards/_modal.asp +++ b/app/views/Cards/_modal.asp @@ -19,6 +19,28 @@ +
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
diff --git a/db/migrations/20260423100000_add_printstream_to_boards.asp b/db/migrations/20260423100000_add_printstream_to_boards.asp new file mode 100644 index 0000000..1f21cb3 --- /dev/null +++ b/db/migrations/20260423100000_add_printstream_to_boards.asp @@ -0,0 +1,15 @@ +<% +'======================================================================================================================= +' MIGRATION: add_printstream_to_boards +'======================================================================================================================= + +Sub Migration_Up(migration) + migration.ExecuteSQL "ALTER TABLE [boards] ADD COLUMN [import_from_printstream] YESNO" + migration.ExecuteSQL "ALTER TABLE [boards] ADD COLUMN [printstream_job_name] MEMO" +End Sub + +Sub Migration_Down(migration) + migration.ExecuteSQL "ALTER TABLE [boards] DROP COLUMN [printstream_job_name]" + migration.ExecuteSQL "ALTER TABLE [boards] DROP COLUMN [import_from_printstream]" +End Sub +%> diff --git a/db/migrations/20260424100000_add_printstream_fields_to_cards.asp b/db/migrations/20260424100000_add_printstream_fields_to_cards.asp new file mode 100644 index 0000000..907596d --- /dev/null +++ b/db/migrations/20260424100000_add_printstream_fields_to_cards.asp @@ -0,0 +1,19 @@ +<% +'======================================================================================================================= +' MIGRATION: add_printstream_fields_to_cards +'======================================================================================================================= + +Sub Migration_Up(migration) + migration.ExecuteSQL "ALTER TABLE [cards] ADD COLUMN [customer_name] VARCHAR(255)" + migration.ExecuteSQL "ALTER TABLE [cards] ADD COLUMN [delivery_date] DATETIME" + migration.ExecuteSQL "ALTER TABLE [cards] ADD COLUMN [quantity] VARCHAR(50)" + migration.ExecuteSQL "ALTER TABLE [cards] ADD COLUMN [notes] MEMO" +End Sub + +Sub Migration_Down(migration) + migration.ExecuteSQL "ALTER TABLE [cards] DROP COLUMN [notes]" + migration.ExecuteSQL "ALTER TABLE [cards] DROP COLUMN [quantity]" + migration.ExecuteSQL "ALTER TABLE [cards] DROP COLUMN [delivery_date]" + migration.ExecuteSQL "ALTER TABLE [cards] DROP COLUMN [customer_name]" +End Sub +%> diff --git a/db/migrations/20260424200000_add_full_note_to_cards.asp b/db/migrations/20260424200000_add_full_note_to_cards.asp new file mode 100644 index 0000000..e360855 --- /dev/null +++ b/db/migrations/20260424200000_add_full_note_to_cards.asp @@ -0,0 +1,13 @@ +<% +'======================================================================================================================= +' MIGRATION: add_full_note_to_cards +'======================================================================================================================= + +Sub Migration_Up(migration) + migration.ExecuteSQL "ALTER TABLE [cards] ADD COLUMN [full_note] MEMO" +End Sub + +Sub Migration_Down(migration) + migration.ExecuteSQL "ALTER TABLE [cards] DROP COLUMN [full_note]" +End Sub +%> diff --git a/db/webdata.accdb b/db/webdata.accdb index e2948072da6f99f5aebd5e976a4766c9d5bb0d1f..d843e93dfcfdc4f3a96e257edb83ca63b13787d1 100644 GIT binary patch literal 1024000 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 wV3)B>(0Qr+bV}f0~ zf&w}pRYR%@R+D4t`lo z^CjnDhqy&uED)vP)xTIW|YMM}wUtzj*a`vphq zSDRV|R1N`;pWQ1zWc*8h??UP9J2W0UAi=&`_PFD6ClGk2mK|sh)&=YR{$PXO?{D(g zX4W!Y-4tqGUxs7B;KTl4pw8crtT?mzOY6&m4+l5-n;Pn|HUwK5nnbM+STEGETke%L zgjD;7BZSnV5D-Eg3e`ebi$aYM>QShTN89y8h)qbcy#yv7XH8X$DxO6>A$Y}S5zy}0 zsPX7$?nDPGV$=`C-E3EGb*<3!4Da6C^K|={_YHPXB8>d2-gt+%Y};#(R>z}t z?qmHdkJ87Clc*<(OvntG88ELK-G(*LPe0TdCo;q*couvm?C5bHBHPJ2QbATM8TKp= z69*aQ#9^;EHta|Y%brr|1n-z!?R42DV0}o+f4*x>wz|fgV{`1ZzI`N`2SqP&5BzCD zYL3SSD9n!Vu&{qxM~+-kUb9yck_Gx0FK~a;J+BRF|5lHxk{XX*QJ4#7=sBJXQxjZ; zAN_>)(xeMec#ikN!Z^={${+KciYFN(k&+=9kvF zliNEic3J!kmt{QVTHxaQ4}Mmf;vTKQeL5Ac2Ko%ojYkXIu<=uVw}{RGJ3r;!a9|vF z%kKUfyEN&7_1N#YC6%vmok^|N$u4u!a2VV5i|#ykpZ2zztqv(emwxNokh=VT0N{^F1(wc#$BANrMAdP4x=)BGg;FD{- zr|4z!4YC7))0TzPLdS_!7M4rkslW4QwI7lrWOq^z*bN@nG=kfogoT06@X-6Ob2nVR z$@}wPCtw|Xmil@k#tZK-ZGkWE z%MR)@Hd{1g-ZEdFa?q5R@Vg{W;UQx?f{WrJznVTX{VlWAEHM|14~&y`k~n1G%i*L` z5ZU6&wGwTvR%%R`>AX(KTi>@zr|5)Pz{w{=n8}a*xzWz(*kT$Z?^Duv7yNA%t9ZjT zVdgJa!MsOWT%<7zs#ddg36Cpo7N(b{Tg;n8A|!$hf%a7_8#dg}-0=1)mX+|iEHgi? zm~JrzlUlT!4Kr1)YD6wN1s!y4=(Wsoy)h`DxWbZwLBqn-uyqm{waFO3`z93xV5AYquz#870eNA z6l};WZJ3LZ^QdK4@+zue6-B70iwvQNl7Nz{iW4>*Rr=uERplPI|J%y6HCaa6^pV&j ziCM*ALgc*EB3|&oNKC=M3@uoL$Q{`@ITFpa3dh)o6#f`h3LJ>OIraE%a2pDpH-!(P zP-1z;+y`Cp*mWly@zCu1+V))?5Tp>ZU6@5X@p|`=L9*lZhSZsg8Mqvl8{|P89|WJ5 z=AqeX9nI#u8u7_P1t}iAh%d)4lsc$-S1Gg}dRKWLJ=admC>~iP>nzBbQ7Uzj=F-Js zg=Um+soCw>Nbih zccoQM_*9Q95|aiwKDAQU(k8J*t3GwIgiY(Glcw+$6RtO@?E-&Vw_{s6*Pfo+B+;MR zV2|RJ7iTZ>t{}tzoV|u;FKRN8k+Z0RRTLeD=ak$fJ}H1Z(E!m7^>e|4Jjm@*r)(Zr zJ>BX@R1o23S|TDHF<|2<$M^8cw~RjU%tojvW-a0qI5E#0^o-4eS@scyzZ_McG|;)Q zCjOM5hhevf?hSp3q9DwOx>HMPA#J`;3*qKR)bd6mpfKhzPYW&~;3E;1(}FWCC_=!~ vPC^UeiyTOLYGxrn!%VEeyA+me0hCF#PRBzGyG0*&J$xb1aZ8QIE=vCe!9Vgr diff --git a/public/css/kanban.css b/public/css/kanban.css index 64c4f80..1603cc5 100644 --- a/public/css/kanban.css +++ b/public/css/kanban.css @@ -27,7 +27,6 @@ body.kanban-page .navbar { body.kanban-page .navbar-brand { color: #f4f8ff !important; - font-family: "Fraunces", Georgia, serif; letter-spacing: -0.01em; } @@ -39,6 +38,33 @@ body.kanban-page .navbar-brand { flex-shrink: 0; } +.board-header-search { + width: min(440px, 36vw); + margin: 0 0.75rem; +} + +.board-header-search .input-group-text { + border-color: rgba(214, 229, 250, 0.7); + background: rgba(255, 255, 255, 0.15); + color: #eff6ff; +} + +.board-header-search .form-control { + border-color: rgba(214, 229, 250, 0.7); + background: rgba(255, 255, 255, 0.17); + color: #f5f9ff; +} + +.board-header-search .form-control::placeholder { + color: rgba(235, 243, 255, 0.72); +} + +.board-header-search .form-control:focus { + border-color: rgba(235, 245, 255, 0.95); + box-shadow: 0 0 0 0.2rem rgba(157, 194, 245, 0.25); + background: rgba(255, 255, 255, 0.23); +} + .kanban-board-title { display: block; min-width: 0; @@ -67,21 +93,27 @@ body.kanban-page .navbar .btn-outline-secondary:hover { width: 100%; margin: 0 auto; height: calc(100vh - 65px); - overflow: auto; + overflow-x: auto; + overflow-y: auto; padding: 0.9rem 1rem 1.1rem; -webkit-overflow-scrolling: touch; scroll-behavior: smooth; touch-action: pan-x pan-y; + overscroll-behavior: contain; + scrollbar-width: thin; + scrollbar-color: #8fb0e0 #dce8f8; + scrollbar-gutter: stable; } .kanban-grid { display: grid; - min-width: max(75vw, max-content); + width: max-content; + min-width: 100%; border: 1px solid var(--line, #d9e3f5); border-radius: 14px; background: rgba(255, 255, 255, 0.72); box-shadow: 0 12px 34px rgba(22, 48, 92, 0.12); - overflow: hidden; + overflow: clip; } /* Sticky corner and headers */ @@ -121,6 +153,9 @@ body.kanban-page .navbar .btn-outline-secondary:hover { left: 0; z-index: 20; min-width: 240px; + display: flex; + align-items: center; + gap: 0.42rem; padding: 0.85rem 0.82rem; font-size: clamp(0.7rem, 0.14vw + 0.66rem, 0.78rem); font-weight: 700; @@ -139,6 +174,33 @@ body.kanban-page .navbar .btn-outline-secondary:hover { overflow-wrap: anywhere; } +.kanban-lane-header .lane-toggle { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.34rem; + height: 1.34rem; + padding: 0; + border: 0; + border-radius: 999px; + background: rgba(26, 74, 145, 0.12); + color: #1f4f96; + cursor: pointer; + flex: 0 0 auto; +} + +.kanban-lane-header .lane-toggle:hover { + background: rgba(26, 74, 145, 0.22); +} + +.kanban-lane-header .lane-toggle i { + transition: transform 140ms ease; +} + +.kanban-lane-header.lane-collapsed .lane-toggle i { + transform: rotate(-90deg); +} + /* Cells */ .kanban-cell { min-width: 230px; @@ -154,6 +216,20 @@ body.kanban-page .navbar .btn-outline-secondary:hover { linear-gradient(180deg, rgba(255, 255, 255, 0.88) 0%, rgba(244, 248, 255, 0.93) 100%); } +.kanban-cell.lane-collapsed { + min-height: 0; + max-height: 0; + padding-top: 0; + padding-bottom: 0; + border-top-color: transparent; + overflow: hidden; + pointer-events: none; +} + +.kanban-cell.lane-collapsed .kanban-card { + display: none !important; +} + .kanban-cell.drag-over { background: linear-gradient(180deg, #e9f2ff 0%, #deecff 100%); box-shadow: inset 0 0 0 2px rgba(19, 99, 223, 0.24); @@ -187,9 +263,19 @@ body.kanban-page .navbar .btn-outline-secondary:hover { box-shadow: 0 14px 30px rgba(17, 46, 94, 0.22); } +.kanban-card-hidden { + display: none !important; +} + +.card-headline { + display: flex; + align-items: center; + gap: 0.38rem; + min-width: 0; +} + .card-job-number { display: inline-block; - margin-bottom: 0.36rem; padding: 0.08rem 0.42rem; border-radius: 999px; font-size: 0.66rem; @@ -198,12 +284,45 @@ body.kanban-page .navbar .btn-outline-secondary:hover { text-transform: uppercase; color: #0e4fae; background: #e7f0ff; + flex: 0 0 auto; +} + +.card-customer { + font-size: 0.78rem; + font-weight: 600; + color: #2b4a80; + min-width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } -.card-job-name { - color: #1f2b43; - font-size: 0.86rem; - line-height: 1.32; +.card-meta { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.25rem; +} + +.card-meta-label { + font-size: 0.63rem; + font-weight: 700; + color: #7a90b2; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.card-delivery, +.card-qty { + font-size: 0.73rem; + color: #3a5080; +} + +.card-notes { + margin-top: 0.22rem; + font-size: 0.71rem; + color: #647899; + line-height: 1.3; } /* Settings panel */ @@ -294,25 +413,30 @@ body.kanban-page .navbar .btn-outline-secondary:hover { /* Scrollbars */ .kanban-wrapper::-webkit-scrollbar, .settings-body::-webkit-scrollbar { - width: 10px; - height: 10px; + width: 12px; + height: 12px; } .kanban-wrapper::-webkit-scrollbar-track, .settings-body::-webkit-scrollbar-track { - background: #eaf0fb; + background: #dce8f8; + border-radius: 999px; } .kanban-wrapper::-webkit-scrollbar-thumb, .settings-body::-webkit-scrollbar-thumb { - background: #b8c9e6; + background: #8fb0e0; border-radius: 999px; - border: 2px solid #eaf0fb; + border: 2px solid #dce8f8; } .kanban-wrapper::-webkit-scrollbar-thumb:hover, .settings-body::-webkit-scrollbar-thumb:hover { - background: #97afd8; + background: #5e8ecb; +} + +.kanban-wrapper::-webkit-scrollbar-corner { + background: #dce8f8; } /* Small screens */ @@ -340,6 +464,11 @@ body.kanban-page .navbar .btn-outline-secondary:hover { gap: 0.35rem !important; } + .board-header-search { + width: min(270px, 44vw); + margin: 0 0.35rem; + } + .board-header-actions .btn { padding-left: 0.48rem; padding-right: 0.48rem; @@ -347,6 +476,25 @@ body.kanban-page .navbar .btn-outline-secondary:hover { } @media (max-width: 640px) { + .board-header-search { + width: 100%; + margin: 0.5rem 0 0; + order: 3; + } + + body.kanban-page .navbar { + flex-wrap: wrap; + align-items: flex-start !important; + } + + .board-header-main { + flex: 1 1 auto; + } + + .board-header-actions { + flex: 0 0 auto; + } + .kanban-settings-panel { width: 100vw; border-left: 0; diff --git a/public/js/kanban-board.js b/public/js/kanban-board.js index 24b2f73..64f4a67 100644 --- a/public/js/kanban-board.js +++ b/public/js/kanban-board.js @@ -3,6 +3,11 @@ 'use strict'; var boardId = KANBAN.boardId; + var laneCollapseStorageKey = 'kanban_lane_collapsed_' + String(boardId); + var collapsedLaneIds = loadCollapsedLaneIds(); + var searchState = { + query: '' + }; var dragState = { active: false, x: 0, @@ -35,27 +40,123 @@ var grid = document.getElementById('kanban-grid'); var colHs = grid.querySelectorAll('.kanban-col-header'); var cols = '240px'; - colHs.forEach(function () { cols += ' 220px'; }); + colHs.forEach(function () { cols += ' 230px'; }); grid.style.gridTemplateColumns = cols; } + function loadCollapsedLaneIds() { + var laneMap = {}; + try { + var raw = window.localStorage.getItem(laneCollapseStorageKey); + if (!raw) return laneMap; + var arr = JSON.parse(raw); + if (!Array.isArray(arr)) return laneMap; + arr.forEach(function (laneId) { + laneMap[String(laneId)] = true; + }); + } catch (e) { + console.warn('Failed to load lane collapse state', e); + } + return laneMap; + } + + function saveCollapsedLaneIds() { + try { + window.localStorage.setItem(laneCollapseStorageKey, JSON.stringify(Object.keys(collapsedLaneIds))); + } catch (e) { + console.warn('Failed to save lane collapse state', e); + } + } + + function setLaneCollapsed(laneId, isCollapsed) { + var laneKey = String(laneId); + var header = document.querySelector('.kanban-lane-header[data-lane-id="' + laneKey + '"]'); + if (!header) return; + + var laneCells = document.querySelectorAll('.kanban-cell[data-lane-id="' + laneKey + '"]'); + header.classList.toggle('lane-collapsed', isCollapsed); + laneCells.forEach(function (cell) { + cell.classList.toggle('lane-collapsed', isCollapsed); + }); + + var toggleBtn = header.querySelector('.lane-toggle'); + if (toggleBtn) { + toggleBtn.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true'); + toggleBtn.title = isCollapsed ? 'Expand swim lane' : 'Collapse swim lane'; + toggleBtn.setAttribute('aria-label', toggleBtn.title); + } + + if (isCollapsed) { + collapsedLaneIds[laneKey] = true; + } else { + delete collapsedLaneIds[laneKey]; + } + saveCollapsedLaneIds(); + } + + function toggleLaneCollapsed(laneId) { + var laneKey = String(laneId); + setLaneCollapsed(laneKey, !collapsedLaneIds[laneKey]); + } + + function bindLaneHeaderToggle(headerEl) { + if (!headerEl) return; + var toggleBtn = headerEl.querySelector('.lane-toggle'); + if (!toggleBtn) return; + + if (!toggleBtn.dataset.boundToggle) { + toggleBtn.addEventListener('click', function (evt) { + evt.preventDefault(); + evt.stopPropagation(); + toggleLaneCollapsed(headerEl.dataset.laneId); + }); + toggleBtn.dataset.boundToggle = '1'; + } + } + + function initLaneHeaderToggles() { + document.querySelectorAll('.kanban-lane-header').forEach(function (headerEl) { + bindLaneHeaderToggle(headerEl); + if (collapsedLaneIds[String(headerEl.dataset.laneId)]) { + setLaneCollapsed(headerEl.dataset.laneId, true); + } + }); + } + + function cardBodyHtml(card) { + var html = '
' + + '' + esc(card.job_number || '') + ''; + + if (card.customer_name) { + html += '' + esc(card.customer_name) + ''; + } + + html += '
'; + + return html; + } + + function buildCardSearchText(card) { + return [ + card.job_number || '', + card.job_name || '', + card.customer_name || '', + card.notes || '' + ].join(' ').toLowerCase(); + } + function buildCardEl(card) { var div = document.createElement('div'); div.className = 'kanban-card'; div.dataset.id = card.id; div.dataset.columnId = card.column_id; div.dataset.laneId = card.swim_lane_id; - div.innerHTML = - '
' + esc(card.job_number || '') + '
' + - '
' + esc(card.job_name || '') + '
'; + div.dataset.searchText = buildCardSearchText(card); + div.innerHTML = cardBodyHtml(card); div.addEventListener('click', function () { - window.KanbanModal.openEdit( - card.id, - card.column_id, - card.swim_lane_id, - card.job_number, - card.job_name - ); + var c = KANBAN.cards.find(function (x) { return String(x.id) === String(div.dataset.id); }); + if (!c) return; + window.KanbanModal.openEdit(c.id, c.column_id, c.swim_lane_id, c.job_number, c.job_name, c.customer_name, c.delivery_date, c.quantity, c.notes, c.full_note); }); return div; } @@ -69,6 +170,26 @@ cell.appendChild(buildCardEl(card)); } }); + applyCardFilter(); + } + + function applyCardFilter() { + var activeQuery = searchState.query; + document.querySelectorAll('.kanban-card').forEach(function (el) { + var searchableText = (el.dataset.searchText || '').toLowerCase(); + var isMatch = activeQuery === '' || searchableText.indexOf(activeQuery) > -1; + el.classList.toggle('kanban-card-hidden', !isMatch); + }); + } + + function initJobSearch() { + var searchInput = document.getElementById('job-search-input'); + if (!searchInput) return; + + searchInput.addEventListener('input', function () { + searchState.query = String(searchInput.value || '').toLowerCase().trim(); + applyCardFilter(); + }); } function handleDragEnd(evt) { @@ -206,23 +327,31 @@ if (cell) { cell.appendChild(buildCardEl(card)); } + applyCardFilter(); }, - onCardUpdated: function (id, jobNumber, jobName) { + onCardUpdated: function (id, data) { var card = KANBAN.cards.find(function (c) { return String(c.id) === String(id); }); if (card) { - card.job_number = jobNumber; - card.job_name = jobName; + card.job_number = data.job_number || ''; + card.job_name = data.job_name || ''; + card.customer_name = data.customer_name || ''; + card.delivery_date = data.delivery_date || null; + card.quantity = data.quantity || ''; + card.notes = data.notes || ''; + card.full_note = data.full_note !== undefined ? data.full_note : (card.full_note || ''); } var el = document.querySelector('.kanban-card[data-id="' + id + '"]'); - if (el) { - el.querySelector('.card-job-number').textContent = jobNumber; - el.querySelector('.card-job-name').textContent = jobName; + if (el && card) { + el.innerHTML = cardBodyHtml(card); + el.dataset.searchText = buildCardSearchText(card); } + applyCardFilter(); }, onCardDeleted: function (id) { KANBAN.cards = KANBAN.cards.filter(function (c) { return String(c.id) !== String(id); }); var el = document.querySelector('.kanban-card[data-id="' + id + '"]'); if (el) el.remove(); + applyCardFilter(); }, addColumn: function (col) { var grid = document.getElementById('kanban-grid'); @@ -263,8 +392,13 @@ var lh = document.createElement('div'); lh.className = 'kanban-lane-header'; lh.dataset.laneId = lane.id; - lh.innerHTML = '' + esc(lane.name) + ''; + lh.innerHTML = + '' + + '' + esc(lane.name) + ''; grid.appendChild(lh); + bindLaneHeaderToggle(lh); colHeaders.forEach(function (ch) { var cell = document.createElement('div'); @@ -275,12 +409,20 @@ createCellSortable(cell); }); + if (collapsedLaneIds[String(lane.id)]) { + setLaneCollapsed(lane.id, true); + } + applyGridTemplate(); }, removeLane: function (laneId) { document.querySelector('.kanban-lane-header[data-lane-id="' + laneId + '"]').remove(); document.querySelectorAll('.kanban-cell[data-lane-id="' + laneId + '"]').forEach(function (el) { el.remove(); }); KANBAN.cards = KANBAN.cards.filter(function (c) { return String(c.swim_lane_id) !== String(laneId); }); + if (collapsedLaneIds[String(laneId)]) { + delete collapsedLaneIds[String(laneId)]; + saveCollapsedLaneIds(); + } }, renameColumn: function (colId, name) { var hdr = document.querySelector('.kanban-col-header[data-col-id="' + colId + '"] .col-label'); @@ -295,4 +437,6 @@ applyGridTemplate(); renderCards(); initSortables(); + initJobSearch(); + initLaneHeaderToggles(); })(); diff --git a/public/js/kanban-modal.js b/public/js/kanban-modal.js index 46a8e5e..07300e7 100644 --- a/public/js/kanban-modal.js +++ b/public/js/kanban-modal.js @@ -14,6 +14,12 @@ var btnSave = document.getElementById('btn-save-card'); var btnDelete = document.getElementById('btn-delete-card'); + var custNameEl = document.getElementById('card-customer-name'); + var delivDateEl = document.getElementById('card-delivery-date'); + var qtyEl = document.getElementById('card-quantity'); + var notesEl = document.getElementById('card-notes'); + var fullNoteEl = document.getElementById('card-full-note'); + var boardId = KANBAN.boardId; /* ── Helpers ─────────────────────────────────────────────── */ @@ -44,6 +50,11 @@ laneIdEl.value = laneId || ''; jobNumEl.value = ''; jobNameEl.value = ''; + custNameEl.value = ''; + delivDateEl.value = ''; + qtyEl.value = ''; + notesEl.value = ''; + fullNoteEl.value = ''; btnDelete.classList.add('d-none'); clearError(); bsModal.show(); @@ -51,13 +62,18 @@ } /* ── Open for edit ───────────────────────────────────────── */ - function openEdit(id, colId, laneId, jobNum, jobName) { + function openEdit(id, colId, laneId, jobNum, jobName, custName, delivDate, qty, notes, fullNote) { titleEl.textContent = 'Edit Card'; cardIdEl.value = id; colIdEl.value = colId; laneIdEl.value = laneId; - jobNumEl.value = jobNum || ''; - jobNameEl.value = jobName || ''; + jobNumEl.value = jobNum || ''; + jobNameEl.value = jobName || ''; + custNameEl.value = custName || ''; + delivDateEl.value = delivDate || ''; + qtyEl.value = qty || ''; + notesEl.value = notes || ''; + fullNoteEl.value = fullNote || ''; btnDelete.classList.remove('d-none'); clearError(); bsModal.show(); @@ -72,6 +88,11 @@ var laneId = laneIdEl.value; var jNum = jobNumEl.value.trim(); var jName = jobNameEl.value.trim(); + var cust = custNameEl.value.trim(); + var dDate = delivDateEl.value; + var qty = qtyEl.value.trim(); + var notes = notesEl.value.trim(); + var fullNote = fullNoteEl.value; if (!jNum && !jName) { showError('Enter at least a job number or job name.'); @@ -80,10 +101,10 @@ if (id) { // Update existing - post('/cards/' + id, { job_number: jNum, job_name: jName }, function (res) { + post('/cards/' + id, { job_number: jNum, job_name: jName, customer_name: cust, delivery_date: dDate, quantity: qty, notes: notes, full_note: fullNote }, function (res) { if (res.ok) { bsModal.hide(); - window.KanbanBoard.onCardUpdated(id, res.job_number, res.job_name); + window.KanbanBoard.onCardUpdated(id, res); } else { showError(res.error || 'Save failed.'); } @@ -95,11 +116,16 @@ return; } post('/cards', { - board_id: boardId, - column_id: colId, + board_id: boardId, + column_id: colId, swim_lane_id: laneId, - job_number: jNum, - job_name: jName + job_number: jNum, + job_name: jName, + customer_name: cust, + delivery_date: dDate, + quantity: qty, + notes: notes, + full_note: fullNote }, function (res) { if (res.ok) { bsModal.hide(); diff --git a/scripts/importPrintStreamJobs.vbs b/scripts/importPrintStreamJobs.vbs new file mode 100644 index 0000000000000000000000000000000000000000..69f682ab5bcaf3257a9815253fae6d8ec490e0b0 GIT binary patch literal 36468 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 literal 0 HcmV?d00001 diff --git a/scripts/migrate_isbusiness_to_households.vbs b/scripts/migrate_isbusiness_to_households.vbs deleted file mode 100644 index 5f0a8b9..0000000 --- a/scripts/migrate_isbusiness_to_households.vbs +++ /dev/null @@ -1,90 +0,0 @@ -' migrate_isbusiness_to_households.vbs -' Moves IsBusiness from HouseholderNames to Households. -' -' Usage: -' cscript //nologo scripts\migrate_isbusiness_to_households.vbs "C:\path\to\myAccessFile.accdb" -' -' What it does: -' 1) Adds Households.IsBusiness (SMALLINT) if missing -' 2) Copies data: sets Households.IsBusiness=1 if any related HouseholderNames.IsBusiness<>0 -' 3) Sets NULLs to 0 -' 4) Drops HouseholderNames.IsBusiness if present -' -Option Explicit - -Dim dbPath -If WScript.Arguments.Count < 1 Then - WScript.Echo "ERROR: missing db path." - WScript.Echo "Usage: cscript //nologo scripts\migrate_isbusiness_to_households.vbs ""C:\path\to\db.accdb""" - WScript.Quit 1 -End If - -dbPath = WScript.Arguments(0) - -Dim conn -Set conn = CreateObject("ADODB.Connection") -conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath & ";Persist Security Info=False;" - -On Error Resume Next - -If Not ColumnExists(conn, "Households", "IsBusiness") Then - Exec conn, "ALTER TABLE [Households] ADD COLUMN [IsBusiness] SMALLINT" - If Err.Number <> 0 Then - WScript.Echo "ERROR adding Households.IsBusiness: " & Err.Description - WScript.Quit 1 - End If - WScript.Echo "Added Households.IsBusiness" -Else - WScript.Echo "Households.IsBusiness already exists" -End If - -' Copy data (only if the old column exists) -If ColumnExists(conn, "HouseholderNames", "IsBusiness") Then - ' Normalize all existing households first so the column is never left NULL. - Exec conn, "UPDATE [Households] SET [IsBusiness]=0" - If Err.Number <> 0 Then - WScript.Echo "ERROR initializing Households.IsBusiness: " & Err.Description - WScript.Quit 1 - End If - - ' Promote households to business when any related name was previously marked as a business. - Exec conn, "UPDATE [Households] SET [IsBusiness]=1 WHERE [Id] IN (SELECT [HouseholdId] FROM [HouseholderNames] WHERE [IsBusiness]<>0)" - If Err.Number <> 0 Then - WScript.Echo "ERROR copying IsBusiness to Households: " & Err.Description - WScript.Quit 1 - End If - WScript.Echo "Copied IsBusiness values to Households" - - Exec conn, "ALTER TABLE [HouseholderNames] DROP COLUMN [IsBusiness]" - If Err.Number <> 0 Then - WScript.Echo "ERROR dropping HouseholderNames.IsBusiness: " & Err.Description - WScript.Quit 1 - End If - WScript.Echo "Dropped HouseholderNames.IsBusiness" -Else - WScript.Echo "HouseholderNames.IsBusiness does not exist; nothing to drop" -End If - -conn.Close -Set conn = Nothing -WScript.Echo "Done." - -' --- helpers --- -Sub Exec(c, sql) - Err.Clear - c.Execute sql -End Sub - -Function ColumnExists(c, tableName, colName) - Dim rs - ColumnExists = False - Err.Clear - Set rs = c.OpenSchema(4, Array(Empty, Empty, tableName, colName)) ' adSchemaColumns=4 - If Err.Number <> 0 Then - Err.Clear - Exit Function - End If - If Not rs.EOF Then ColumnExists = True - rs.Close - Set rs = Nothing -End Function