diff --git a/lua/gmod_integration/client/cl_context_menu.lua b/lua/gmod_integration/client/cl_context_menu.lua index f08fce5..434a8c5 100644 --- a/lua/gmod_integration/client/cl_context_menu.lua +++ b/lua/gmod_integration/client/cl_context_menu.lua @@ -8,4 +8,16 @@ list.Set("DesktopWindows", "GmodIntegration:DesktopWindows", { window:Close() gmInte.openAdminConfig() end +}) + +list.Set("DesktopWindows", "GmodIntegration:DesktopWindows:ReportBug", { + icon = "gmod_integration/logo_context_report.png", + title = "Report Bug", + width = 960, + height = 700, + onewindow = true, + init = function(icon, window) + window:Close() + gmInte.openReportBug() + end }) \ No newline at end of file diff --git a/lua/gmod_integration/client/cl_report_bug.lua b/lua/gmod_integration/client/cl_report_bug.lua new file mode 100644 index 0000000..74dfd89 --- /dev/null +++ b/lua/gmod_integration/client/cl_report_bug.lua @@ -0,0 +1,147 @@ +// format: multiline +local Fields = { + { + ["title"] = "Screenshot", + ["type"] = "image", + }, + { + ["title"] = "Description", + ["type"] = "text", + ["tall"] = 80, + }, + { + ["title"] = "Importance Level", + ["type"] = "dropdown", + ["options"] = { + "Critical - Crash or made the game unplayable.", + "High - Critical functionality is unusable.", + "Medium - Important functionality is unusable.", + "Low - Cosmetic issue.", + "Trivial - Very minor issue.", + }, + }, + { + ["title"] = "Steps to Reproduce", + ["type"] = "text", + ["tall"] = 80, + }, + { + ["title"] = "Expected result", + ["type"] = "text", + ["tall"] = 50, + }, + { + ["title"] = "Actual result", + ["type"] = "text", + ["tall"] = 50, + }, +} + +function gmInte.openReportBug() + local captureData = { + format = "jpeg", + x = 0, + y = 0, + w = ScrW(), + h = ScrH(), + quality = 95, + } + + local screenCapture = render.Capture(captureData) + if screenCapture then file.Write("gmod_integration/report_bug_screenshot.jpeg", screenCapture) end + local frame = vgui.Create("DFrame") + frame:SetSize(500, (700 / 1080) * ScrH()) + frame:Center() + frame:SetTitle("Report Bug") + frame:MakePopup() + gmInte.applyPaint(frame) + // bug report = screenshot, description, steps to reproduce, expected result, actual result + local dPanel = vgui.Create("DScrollPanel", frame) + dPanel:Dock(FILL) + gmInte.applyPaint(dPanel) + local elements = {} + for _ = 1, #Fields do + local field = Fields[_] + if field.type == "image" && !screenCapture then continue end + local label = vgui.Create("DLabel", dPanel) + label:Dock(TOP) + label:DockMargin(5, 5, 5, 5) + label:SetText(field.title) + if field.type == "image" then + local image = vgui.Create("DImage", dPanel) + image:Dock(TOP) + image:DockMargin(5, 5, 5, 5) + image:SetImage("data/gmod_integration/report_bug_screenshot.jpeg") + image:SetSize(frame:GetWide() - 10, (frame:GetWide() - 10) * (9 / 16)) + elseif field.type == "text" then + local text = vgui.Create("DTextEntry", dPanel) + text:Dock(TOP) + text:DockMargin(5, 5, 5, 5) + text:SetMultiline(true) + text:SetTall(field.tall || 40) + text:SetPlaceholderText("Explain the bug you encountered, be as precise as possible.") + gmInte.applyPaint(text) + table.insert(elements, text) + elseif field.type == "dropdown" then + local dropdown = vgui.Create("DComboBox", dPanel) + dropdown:Dock(TOP) + dropdown:DockMargin(5, 5, 5, 5) + dropdown:SetValue("Select Importance Level") + for i = 1, #field.options do + dropdown:AddChoice(field.options[i]) + end + + dropdown:SetSortItems(false) + gmInte.applyPaint(dropdown) + table.insert(elements, dropdown) + end + end + + local buttonGrid = vgui.Create("DGrid", frame) + buttonGrid:Dock(BOTTOM) + buttonGrid:DockMargin(5, 10, 5, 5) + buttonGrid:SetCols(2) + buttonGrid:SetColWide(frame:GetWide() - 10) + buttonGrid:SetRowHeight(35) + local button = vgui.Create("DButton") + button:SetText("Send Report") + button:SetSize(buttonGrid:GetColWide() - 10, buttonGrid:GetRowHeight()) + gmInte.applyPaint(button) + buttonGrid:AddItem(button) + button.DoClick = function() + // all fields are required and > 60 characters + for _, element in ipairs(elements) do + if element:GetText() == "" then + notification.AddLegacy("All fields are required", NOTIFY_ERROR, 5) + return + end + end + + local screenData = {} + if screenCapture then + local base64Capture = util.Base64Encode(screenCapture) + local size = math.Round(string.len(base64Capture) / 1024) + screenData = { + ["screenshot"] = base64Capture, + ["captureData"] = captureData, + ["size"] = size .. "KB" + } + end + + gmInte.http.post("/clients/:steamID64/servers/:serverID/bugs", { + ["player"] = gmInte.getPlayerFormat(LocalPlayer()), + ["screenshot"] = screenData, + ["description"] = elements[1]:GetText(), + ["importance"] = elements[2]:GetValue(), + ["steps"] = elements[3]:GetText(), + ["expected"] = elements[4]:GetText(), + ["actual"] = elements[5]:GetText(), + }, function() + notification.AddLegacy("Bug report sent to Discord", NOTIFY_GENERIC, 5) + frame:Close() + end, function() notification.AddLegacy("Failed to send bug report retry later", NOTIFY_ERROR, 5) end) + end +end + +concommand.Add("gmi_report_bug", gmInte.openReportBug) +concommand.Add("gmod_integration_report_bug", gmInte.openReportBug) \ No newline at end of file diff --git a/materials/gmod_integration/logo_context_report.png b/materials/gmod_integration/logo_context_report.png new file mode 100644 index 0000000..c4cdfba Binary files /dev/null and b/materials/gmod_integration/logo_context_report.png differ