This commit changes the filter on the API response so that we are only filtering out system level notes. This means we get notes that are not linked to specific locations in the code. Subsequent work will have to separate these types of notes from the other code-linked notes and probably display them in some sort of separate tree.
222 lines
6.7 KiB
Lua
222 lines
6.7 KiB
Lua
local u = require("gitlab.utils")
|
|
local NuiTree = require("nui.tree")
|
|
local job = require("gitlab.job")
|
|
local state = require("gitlab.state")
|
|
local Job = require("plenary.job")
|
|
local Popup = require("nui.popup")
|
|
local keymaps = require("gitlab.keymaps")
|
|
|
|
local M = {}
|
|
|
|
local replyPopup = Popup(u.create_popup_state("Reply", "80%", "80%"))
|
|
|
|
M.reply = function()
|
|
if u.base_invalid() then return end
|
|
replyPopup:mount()
|
|
keymaps.set_popup_keymaps(replyPopup, M.send_reply)
|
|
end
|
|
|
|
M.send_reply = function(text)
|
|
local escapedText = string.gsub(text, "\n", "\\n")
|
|
local json = string.format('{"discussion_id": "%s", "reply": "%s"}', state.ACTIVE_DISCUSSION, escapedText)
|
|
job.run_job("reply", "POST", json, function(data)
|
|
local note_node = M.build_note(data.note)
|
|
note_node:expand()
|
|
|
|
state.tree:add_node(note_node, "-" .. state.ACTIVE_DISCUSSION)
|
|
vim.schedule(function()
|
|
state.tree:render()
|
|
local buf = vim.api.nvim_get_current_buf()
|
|
u.darken_metadata(buf, '')
|
|
vim.notify("Sent reply!", vim.log.levels.INFO)
|
|
end)
|
|
end)
|
|
end
|
|
|
|
-- Adds node to discussion tree
|
|
local function addToDiscussionTree(i, note, discussionChildren)
|
|
local note_node = M.build_note(note)
|
|
if i == 1 then
|
|
note_node:expand()
|
|
end
|
|
table.insert(discussionChildren, note_node)
|
|
end
|
|
|
|
-- Places all of the discussions into a readable list
|
|
M.list_discussions = function()
|
|
if u.base_invalid() then return end
|
|
Job:new({
|
|
command = "curl",
|
|
args = { "-s", string.format("localhost:%s/discussions", state.PORT) },
|
|
on_stdout = function(_, output)
|
|
local data_ok, data = pcall(vim.json.decode, output)
|
|
if data_ok and data ~= nil then
|
|
local status = (data.status >= 200 and data.status < 300) and "success" or "error"
|
|
if status == "error" then
|
|
vim.notify("Could not fetch discussions!", vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
M.discussions = data.discussions
|
|
vim.schedule(function()
|
|
if type(data.discussions) ~= "table" then
|
|
vim.notify("No discussions for this MR")
|
|
return
|
|
end
|
|
|
|
vim.cmd.tabnew()
|
|
local buf = vim.api.nvim_create_buf(false, true)
|
|
vim.api.nvim_command("aboveleft vsplit")
|
|
vim.api.nvim_buf_set_option(buf, 'filetype', 'markdown')
|
|
vim.api.nvim_set_current_buf(buf)
|
|
local allDiscussions = {}
|
|
for i, discussion in ipairs(data.discussions) do
|
|
local discussionChildren = {}
|
|
for _, note in ipairs(discussion.notes) do
|
|
if note.position then
|
|
addToDiscussionTree(i, note, discussionChildren)
|
|
else
|
|
end
|
|
end
|
|
local discussionNode = NuiTree.Node({
|
|
text = discussion.id,
|
|
id = discussion.id,
|
|
is_discussion = true
|
|
},
|
|
discussionChildren)
|
|
if i == 1 then
|
|
discussionNode:expand()
|
|
end
|
|
table.insert(allDiscussions, discussionNode)
|
|
end
|
|
state.tree = NuiTree({ nodes = allDiscussions, bufnr = buf })
|
|
|
|
M.set_tree_keymaps(buf)
|
|
|
|
state.tree:render()
|
|
vim.api.nvim_buf_set_option(buf, 'filetype', 'markdown')
|
|
u.darken_metadata(buf, '')
|
|
end)
|
|
end
|
|
end,
|
|
on_stderr = function(_, output)
|
|
vim.notify("Could not run approve command!", vim.log.levels.ERROR)
|
|
error(output)
|
|
end,
|
|
}):start()
|
|
end
|
|
|
|
|
|
M.jump_to_file = function()
|
|
local node = state.tree:get_node()
|
|
if node == nil then return end
|
|
|
|
local childrenIds = node:get_child_ids()
|
|
-- We have selected a note node
|
|
if node.file_name ~= nil then
|
|
u.jump_to_file(node.file_name, node.line_number)
|
|
elseif node.is_body then
|
|
local parentId = node:get_parent_id()
|
|
local parent = state.tree:get_node(parentId)
|
|
if parent == nil then return end
|
|
u.jump_to_file(parent.file_name, parent.line_number)
|
|
else
|
|
local firstChild = state.tree:get_node(childrenIds[1])
|
|
if firstChild == nil then return end
|
|
u.jump_to_file(firstChild.file_name, firstChild.line_number)
|
|
end
|
|
end
|
|
|
|
M.set_tree_keymaps = function(buf)
|
|
-- Jump to file location where comment was left
|
|
vim.keymap.set('n', state.keymaps.discussion_tree.jump_to_location, function()
|
|
M.jump_to_file()
|
|
end, { buffer = true })
|
|
|
|
vim.keymap.set('n', state.keymaps.discussion_tree.edit_comment, function()
|
|
require("gitlab.comment").edit_comment()
|
|
end, { buffer = true })
|
|
|
|
vim.keymap.set('n', state.keymaps.discussion_tree.delete_comment, function()
|
|
require("gitlab.comment").delete_comment()
|
|
end)
|
|
|
|
-- Expand/collapse the current node
|
|
vim.keymap.set('n', state.keymaps.discussion_tree.toggle_node, function()
|
|
local node = state.tree:get_node()
|
|
if node == nil then return end
|
|
local children = node:get_child_ids()
|
|
if node == nil then return end
|
|
if node:is_expanded() then
|
|
node:collapse()
|
|
for _, child in ipairs(children) do
|
|
state.tree:get_node(child):collapse()
|
|
end
|
|
else
|
|
for _, child in ipairs(children) do
|
|
state.tree:get_node(child):expand()
|
|
end
|
|
node:expand()
|
|
end
|
|
|
|
|
|
state.tree:render()
|
|
u.darken_metadata(buf, '')
|
|
end,
|
|
{ buffer = true })
|
|
|
|
vim.keymap.set('n', 'r', function()
|
|
local node = state.tree:get_node()
|
|
if node == nil then return end
|
|
|
|
-- Get closest discussion parent
|
|
if node.is_body then
|
|
local parentId = node:get_parent_id()
|
|
local parent = state.tree:get_node(parentId)
|
|
if parent == nil then return end
|
|
parentId = parent:get_parent_id()
|
|
parent = state.tree:get_node(parentId)
|
|
if parent == nil then return end
|
|
node = parent
|
|
elseif node.is_note then
|
|
local parentId = node:get_parent_id()
|
|
local parent = state.tree:get_node(parentId)
|
|
if parent == nil then return end
|
|
node = parent
|
|
end
|
|
|
|
state.ACTIVE_DISCUSSION = node.id
|
|
M.reply()
|
|
end, { buffer = true })
|
|
end
|
|
|
|
M.build_note = function(note)
|
|
local noteTextNodes = {}
|
|
for bodyLine in note.body:gmatch("[^\n]+") do
|
|
table.insert(noteTextNodes, NuiTree.Node({ text = bodyLine, is_body = true }, {}))
|
|
end
|
|
local noteHeader = "@" ..
|
|
note.author.username .. " on " .. u.format_date(note.created_at)
|
|
|
|
local file_name
|
|
local line_number
|
|
if (type(note.position) == 'table') then
|
|
line_number = note.position.new_line or note.position.old_line
|
|
file_name = note.position.new_path
|
|
end
|
|
|
|
|
|
local note_node = NuiTree.Node(
|
|
{
|
|
text = noteHeader,
|
|
id = note.id,
|
|
file_name = file_name,
|
|
line_number = line_number,
|
|
is_note = true,
|
|
is_code_comment = type(note.position) == 'table'
|
|
}, noteTextNodes)
|
|
|
|
return note_node
|
|
end
|
|
|
|
return M
|