Repository navigation
Expand file tree
/
Copy pathinit.lua
More file actions
executable file
·198 lines (179 loc) · 7.14 KB
/
Copy pathinit.lua
File metadata and controls
executable file
·198 lines (179 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
-- This module is responsible for CRUD operations for the draft notes in the discussion tree.
-- That includes things like editing existing draft notes in the tree, and
-- and deleting them. Normal notes and comments are managed separately,
-- under lua/gitlab/actions/discussions/init.lua
local common = require("gitlab.actions.common")
local discussion_tree = require("gitlab.actions.discussions.tree")
local git = require("gitlab.git")
local client = require("gitlab.client")
local NuiTree = require("nui.tree")
local List = require("gitlab.utils.list")
local u = require("gitlab.utils")
local state = require("gitlab.state")
local branch_not_in_sync_comment = " (even if local branch not in sync with remote)"
local M = {}
---Re-fetch all draft notes (and non-draft notes) and re-render the relevant views.
---@param unlinked boolean
---@param all? boolean
M.rebuild_view = function(unlinked, all)
M.load_draft_notes(function()
local discussions = require("gitlab.actions.discussions")
discussions.rebuild_view(unlinked, all)
end)
end
---Make API call to get the discussion data, store it in the state, and call the callback.
---@param on_success fun()
M.load_draft_notes = function(on_success)
state.discussion_tree.updating = state.discussion_tree.updating + 1
state.load_new_state("draft_notes", function()
state.discussion_tree.last_updated = os.time()
state.discussion_tree.updating = state.discussion_tree.updating - 1
on_success()
end, function(data)
client.notify_error(data)
state.discussion_tree.updating = state.discussion_tree.updating - 1
end)
end
---Send the edits to Gitlab and refresh the draft_notes tree.
---@param note_id integer
---@param unlinked boolean
---@return fun(text: string)
M.confirm_edit_draft_note = function(note_id, unlinked)
return function(text)
local all_notes = List.new(state.DRAFT_NOTES)
local the_note = all_notes:find(function(note)
return note.id == note_id
end)
local body = { note = text, position = the_note.position }
client.send_request(string.format("/mr/draft_notes/%d", note_id), "PATCH", body, function(data)
u.notify(data.message, vim.log.levels.INFO)
M.rebuild_view(unlinked)
end)
end
end
---Send the deletion to Gitlab when the user makes a selection, and re-render the tree.
---@param note_id integer
---@param unlinked boolean
M.confirm_delete_draft_note = function(note_id, unlinked)
client.send_request(string.format("/mr/draft_notes/%d", note_id), "DELETE", nil, function(data)
u.notify(data.message, vim.log.levels.INFO)
M.rebuild_view(unlinked)
end)
end
---Trigger a popup prompting the user to publish the current draft comment.
---@param tree NuiTree
M.publish_draft = function(tree)
local branch_in_sync = git.check_current_branch_up_to_date_on_remote(vim.log.levels.ERROR)
local sync_comment = branch_in_sync and "" or branch_not_in_sync_comment
vim.ui.select({ "Confirm", "Cancel" }, {
prompt = string.format("Publish current draft comment%s?", sync_comment),
}, function(choice)
if choice == "Confirm" then
M.confirm_publish_draft(tree)
end
end)
end
---Trigger a popup prompting the user to publish all draft notes.
M.publish_all_drafts = function()
local branch_in_sync = git.check_current_branch_up_to_date_on_remote(vim.log.levels.ERROR)
local sync_comment = branch_in_sync and "" or branch_not_in_sync_comment
vim.ui.select({ "Confirm", "Cancel" }, {
prompt = string.format("Publish all drafts%s?", sync_comment),
}, function(choice)
if choice == "Confirm" then
M.confirm_publish_all_drafts()
end
end)
end
---Publish all draft notes and comments and re-render all discussion views.
M.confirm_publish_all_drafts = function()
local body = { publish_all = true }
client.send_request("/mr/draft_notes/publish", "POST", body, function(data)
u.notify(data.message, vim.log.levels.INFO)
state.DRAFT_NOTES = {}
require("gitlab.actions.discussions").rebuild_view(false, true)
end, function(data)
client.notify_error(data)
u.notify(
"Draft(s) may have been published despite the error. Check the discussion tree. Try publishing drafts individually.",
vim.log.levels.WARN
)
require("gitlab.actions.discussions").rebuild_view(false, true)
end)
end
---Publish the current draft note that is being hovered over in the tree, and make an
---API call to refresh the relevant data for that tree and re-render it.
---@param tree NuiTree
M.confirm_publish_draft = function(tree)
local current_node = tree:get_node()
local note_node = common.get_note_node(tree, current_node)
local root_node = common.get_root_node(tree, current_node)
if note_node == nil or root_node == nil then
u.notify("Could not get note or root node", vim.log.levels.ERROR)
return
end
---@type integer
local note_id = note_node.is_root and root_node.id or note_node.id
local body = { note = note_id }
local unlinked = tree.bufnr == require("gitlab.actions.discussions").unlinked_bufnr
client.send_request("/mr/draft_notes/publish", "POST", body, function(data)
u.notify(data.message, vim.log.levels.INFO)
M.rebuild_view(unlinked)
end, function(data)
client.notify_error(data)
u.notify("Draft may have been published despite the error. Check the discussion tree.", vim.log.levels.WARN)
M.rebuild_view(unlinked)
end)
end
--
-- Helper functions
--
---Return true if a draft note was left on a particular diff, false if it is an unlinked note.
---@param note DraftNote
---@return boolean
M.has_position = function(note)
return note.position.new_path ~= nil or note.position.old_path ~= nil
end
---Build a note for the discussion tree for draft notes that are roots of their own
---discussions, e.g. not replies.
---@param note DraftNote
---@return NuiTree.Node
M.build_root_draft_note = function(note)
local _, root_text, root_text_nodes = discussion_tree.build_note(note)
return NuiTree.Node({
range = (type(note.position) == "table" and note.position.line_range or nil),
text = root_text,
type = "note",
is_root = true,
is_draft = true,
id = note.id,
root_note_id = note.id,
file_name = (type(note.position) == "table" and note.position.new_path or nil),
old_file_name = (type(note.position) == "table" and note.position.old_path or nil),
new_line = (type(note.position) == "table" and note.position.new_line or nil),
old_line = (type(note.position) == "table" and note.position.old_line or nil),
resolvable = false,
resolved = false,
url = state.INFO.web_url .. "#note_" .. note.id,
}, root_text_nodes)
end
---Return a list of nodes to add to the discussion tree.
---@param unlinked boolean If true, return only unlinked (note) nodes
---@return NuiTree.Node[]
M.add_draft_notes_to_table = function(unlinked)
local draft_notes = List.new(state.DRAFT_NOTES)
local draft_note_nodes = draft_notes
---@param note DraftNote
:filter(function(note)
if unlinked then
return not M.has_position(note)
end
return M.has_position(note)
end)
:filter(function(note)
return note.discussion_id == "" -- Do not include draft replies
end)
:map(M.build_root_draft_note)
return draft_note_nodes
end
return M