Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Adds More Information to Summary Panel #100

Merged
merged 19 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@ require("gitlab").setup({
resolved = '✓', -- Symbol to show next to resolved discussions
unresolved = '✖', -- Symbol to show next to unresolved discussions
},
info = { -- Show additional fields in the summary pane
enabled = true,
horizontal = false, -- Display metadata to the left of the summary rather than underneath
fields = { -- The fields listed here will be displayed, in whatever order you choose
"author",
"created_at",
"updated_at",
"merge_status",
"draft",
"conflicts",
"assignees",
"branch",
"pipeline",
},
},
discussion_sign_and_diagnostic = {
skip_resolved_discussion = false,
skip_old_revision_discussion = true,
Expand Down Expand Up @@ -206,6 +221,8 @@ require("gitlab").summary()

After editing the description or title, you may save your changes via the `settings.popup.perform_action` keybinding.

By default this plugin will also show additional metadata about the MR in a separate pane underneath the description. This can be disabled, and these fields can be reordered or removed. Please see the `settings.info` section of the configuration.

### Reviewing Diffs

The `review` action will open a diff of the changes. You can leave comments using the `create_comment` action. In visual mode, add multiline comments with the `create_multiline_comment` command, and add suggested changes with the `create_comment_suggestion` command.
Expand Down
36 changes: 36 additions & 0 deletions example.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
local Layout = require("nui.layout")
local Popup = require("nui.popup")

local opts = {
buf_options = {
filetype = "markdown",
},
focusable = true,
border = {
style = "rounded",
},
}

local title_popup = Popup(opts)
local description_popup = Popup(opts)
local info_popup = Popup(opts)

local layout = Layout(
{
position = "50%",
relative = "editor",
size = {
width = "95%",
height = "95%",
},
},
Layout.Box({
Layout.Box(title_popup, { size = { height = 3 } }),
Layout.Box({
Layout.Box(description_popup, { grow = 1 }),
Layout.Box(info_popup, { size = { height = 15 } }),
}, { dir = "col", size = "100%" }),
}, { dir = "col" })
)

layout:mount()
10 changes: 9 additions & 1 deletion lua/gitlab/actions/pipeline.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ local function get_pipeline()
return pipeline
end

M.get_pipeline_status = function()
local pipeline = get_pipeline()
if pipeline == nil then
return nil
end
return string.format("%s (%s)", state.settings.pipeline[pipeline.status], pipeline.status)
end

-- The function will render the Pipeline state in a popup
M.open = function()
local pipeline = get_pipeline()
Expand All @@ -44,7 +52,7 @@ M.open = function()
local lines = {}

u.switch_can_edit_buf(bufnr, true)
table.insert(lines, string.format("Status: %s (%s)", state.settings.pipeline[pipeline.status], pipeline.status))
table.insert(lines, "Status: " .. M.get_pipeline_status())
table.insert(lines, "")
table.insert(lines, string.format("Last Run: %s", u.time_since(pipeline.created_at)))
table.insert(lines, string.format("Url: %s", pipeline.web_url))
Expand Down
215 changes: 161 additions & 54 deletions lua/gitlab/actions/summary.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ local job = require("gitlab.job")
local u = require("gitlab.utils")
local state = require("gitlab.state")
local miscellaneous = require("gitlab.actions.miscellaneous")
local pipeline = require("gitlab.actions.pipeline")

local M = {
layout_visible = false,
layout = nil,
Expand All @@ -15,15 +17,58 @@ local M = {
description_bufnr = nil,
}

-- The function will render the MR description in a popup
local title_popup_settings = {
buf_options = {
filetype = "markdown",
},
focusable = true,
border = {
style = "rounded",
},
}

local details_popup_settings = {
buf_options = {
filetype = "markdown",
},
focusable = true,
border = {
style = "rounded",
text = {
top = "Details",
},
},
}

local description_popup_settings = {
buf_options = {
filetype = "markdown",
},
enter = true,
focusable = true,
border = {
style = "rounded",
text = {
top = "Description",
},
},
}

-- The function will render a popup containing the MR title and MR description, and optionally,
-- any additional metadata that the user wants. The title and description are editable and
-- can be changed via the local action keybinding, which also closes the popup
M.summary = function()
if M.layout_visible then
M.layout:unmount()
M.layout_visible = false
return
end

local layout, title_popup, description_popup = M.create_layout()
local title = state.INFO.title
local description_lines = M.build_description_lines()
local info_lines = state.settings.info.enabled and M.build_info_lines() or nil

local layout, title_popup, description_popup, info_popup = M.create_layout(info_lines)

M.layout = layout
M.layout_buf = layout.bufnr
Expand All @@ -34,29 +79,93 @@ M.summary = function()
M.layout_visible = false
end

local currentBuffer = vim.api.nvim_get_current_buf()
local title = state.INFO.title
local description = state.INFO.description
local lines = {}

for line in description:gmatch("[^\n]+") do
table.insert(lines, line)
table.insert(lines, "")
end

vim.schedule(function()
vim.api.nvim_buf_set_lines(currentBuffer, 0, -1, false, lines)
vim.api.nvim_buf_set_lines(description_popup.bufnr, 0, -1, false, description_lines)
vim.api.nvim_buf_set_lines(title_popup.bufnr, 0, -1, false, { title })

if info_popup then
vim.api.nvim_buf_set_lines(info_popup.bufnr, 0, -1, false, info_lines)
vim.api.nvim_set_option_value("modifiable", false, { buf = info_popup.bufnr })
vim.api.nvim_set_option_value("readonly", false, { buf = info_popup.bufnr })
end

state.set_popup_keymaps(
description_popup,
M.edit_summary,
miscellaneous.attach_file,
{ cb = exit, action_before_close = true }
)
state.set_popup_keymaps(title_popup, M.edit_summary, nil, { cb = exit, action_before_close = true })

vim.api.nvim_set_current_buf(description_popup.bufnr)
end)
end

-- Builds a lua list of strings that contain the MR description
M.build_description_lines = function()
local description_lines = {}

local description = state.INFO.description
for line in description:gmatch("[^\n]+") do
table.insert(description_lines, line)
table.insert(description_lines, "")
end

return description_lines
end

-- Builds a lua list of strings that contain metadata about the current MR. Only builds the
-- lines that users include in their state.settings.info.fields list.
M.build_info_lines = function()
local info = state.INFO
local options = {
author = { title = "Author", content = "@" .. info.author.username .. " (" .. info.author.name .. ")" },
created_at = { title = "Created", content = u.format_to_local(info.created_at, vim.fn.strftime("%z")) },
updated_at = { title = "Updated", content = u.format_to_local(info.updated_at, vim.fn.strftime("%z")) },
merge_status = { title = "Status", content = info.detailed_merge_status },
draft = { title = "Draft", content = (info.draft and "Yes" or "No") },
conflicts = { title = "Merge Conflicts", content = (info.has_conflicts and "Yes" or "No") },
assignees = { title = "Assignees", content = u.make_readable_list(info.assignees, "name") },
branch = { title = "Branch", content = info.source_branch },
pipeline = {
title = "Pipeline Status:",
content = function()
return pipeline.get_pipeline_status()
end,
},
}

local longest_used = ""
for _, v in ipairs(state.settings.info.fields) do
local title = options[v].title
if string.len(title) > string.len(longest_used) then
longest_used = title
end
end

local function row_offset(row)
local offset = string.len(longest_used) - string.len(row)
return string.rep(" ", offset + 3)
end

local lines = {}
for _, v in ipairs(state.settings.info.fields) do
local row = options[v]
local line = "* " .. row.title .. row_offset(row.title)
if type(row.content) == "function" then
local content = row.content()
if content ~= nil then
line = line .. row.content()
end
else
line = line .. row.content
end
table.insert(lines, line)
end

return lines
end

-- This function will PUT the new description to the Go server
M.edit_summary = function()
local description = u.get_buffer_text(M.description_bufnr)
Expand All @@ -71,54 +180,52 @@ M.edit_summary = function()
end)
end

local top_popup = {
buf_options = {
filetype = "markdown",
},
focusable = true,
border = {
style = "rounded",
text = {
top = "Merge Request",
},
},
}

local bottom_popup = {
buf_options = {
filetype = "markdown",
},
enter = true,
focusable = true,
border = {
style = "rounded",
},
}

M.create_layout = function()
local title_popup = Popup(top_popup)
M.create_layout = function(info_lines)
local title_popup = Popup(title_popup_settings)
M.title_bufnr = title_popup.bufnr
local description_popup = Popup(bottom_popup)
local description_popup = Popup(description_popup_settings)
M.description_bufnr = description_popup.bufnr
local details_popup

local layout = Layout(
{
position = "50%",
relative = "editor",
size = {
width = "90%",
height = "70%",
},
},
Layout.Box({
Layout.Box(title_popup, { size = { height = 3 } }),
Layout.Box(description_popup, { size = "100%" }),
local internal_layout
if state.settings.info.enabled then
details_popup = Popup(details_popup_settings)
if state.settings.info.horizontal then
local longest_line = u.get_longest_string(info_lines)
print(longest_line)
internal_layout = Layout.Box({
Layout.Box(title_popup, { size = 3 }),
Layout.Box({
Layout.Box(details_popup, { size = longest_line + 3 }),
Layout.Box(description_popup, { grow = 1 }),
}, { dir = "row", size = "100%" }),
}, { dir = "col" })
else
internal_layout = Layout.Box({
Layout.Box(title_popup, { size = 3 }),
Layout.Box(description_popup, { grow = 1 }),
Layout.Box(details_popup, { size = #info_lines + 3 }),
}, { dir = "col" })
end
else
internal_layout = Layout.Box({
Layout.Box(title_popup, { size = 3 }),
Layout.Box(description_popup, { grow = 1 }),
}, { dir = "col" })
)
end

local layout = Layout({
position = "50%",
relative = "editor",
size = {
width = "95%",
height = "95%",
},
}, internal_layout)

layout:mount()

return layout, title_popup, description_popup
return layout, title_popup, description_popup, details_popup
end

return M
34 changes: 34 additions & 0 deletions lua/gitlab/spec/util_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,38 @@ describe("utils/init.lua", function()
assert.are.same(got, want)
end)
end)

describe("offset_to_seconds", function()
local tests = {
est = { "-0500", -18000 },
pst = { "-0800", -28800 },
gmt = { "+0000", 0 },
cet = { "+0100", 360 },
jst = { "+0900", 32400 },
ist = { "+0530", 19800 },
art = { "-0300", -10800 },
aest = { "+1100", 39600 },
mmt = { "+0630", 23400 },
}

for _, val in ipairs(tests) do
local got = u.offset_to_seconds(val[1])
local want = val[2]
assert.are.same(got, want)
end
end)

describe("format_to_local", function()
local tests = {
{ "2023-10-28T16:25:09.482Z", "-0500", "10/28/2023 at 11:25" },
{ "2016-11-22T1:25:09.482Z", "-0500", "11/21/2016 at 20:25" },
{ "2016-11-22T1:25:09.482Z", "-0000", "11/22/2016 at 01:25" },
{ "2017-3-22T13:25:09.482Z", "+0700", "03/22/2017 at 20:25" },
}
for _, val in ipairs(tests) do
local got = u.format_to_local(val[1], val[2])
local want = val[3]
assert.are.same(got, want)
end
end)
end)
Loading