update
This commit is contained in:
+4
-2
@@ -5,6 +5,7 @@ local M = {}
|
||||
---@class eta.clickup.Session: eta.Session
|
||||
---@field user string
|
||||
---@field workspace string
|
||||
---@field default_reviewer string
|
||||
|
||||
---@class eta.clickup.Ref
|
||||
---@field name string
|
||||
@@ -27,7 +28,8 @@ local M = {}
|
||||
---@param self eta.clickup.Session
|
||||
---@return eta.clickup.Task[]
|
||||
M.latest_tasks = function(self)
|
||||
local ret = helpers.request("get", self, "/team/" .. self.workspace .. "/task",{subtasks="true", include_markdown_description="true", ['assignees[]']= self.user})
|
||||
local ret = helpers.request("get", self, "/team/" .. self.workspace .. "/task",
|
||||
{ subtasks = "true", include_markdown_description = "true", ['assignees[]'] = self.user })
|
||||
if ret then
|
||||
return ret.tasks
|
||||
end
|
||||
@@ -38,7 +40,7 @@ end
|
||||
---@param id string
|
||||
---@return eta.clickup.Task
|
||||
M.task = function(self, id)
|
||||
local ret = helpers.request("get", self, "/task/" .. id,{include_markdown_description="true"}) or {}
|
||||
local ret = helpers.request("get", self, "/task/" .. id, { include_markdown_description = "true" }) or {}
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
+30
-13
@@ -11,27 +11,32 @@ local M = {}
|
||||
---@param params {[string]: string}
|
||||
---@returns table | nil
|
||||
M.request = function(method, session, endpoint, params)
|
||||
local param_list = {}
|
||||
for param_name, param_value in pairs(params) do
|
||||
table.insert(param_list, param_name .. "=" .. param_value)
|
||||
end
|
||||
local url = session.base_url .. endpoint
|
||||
if #param_list then
|
||||
url = url .. "?" .. table.concat(param_list, "&")
|
||||
end
|
||||
local resp = nil
|
||||
if method == "get" then
|
||||
resp = curl.get(url, {headers = {
|
||||
local param_list = {}
|
||||
for param_name, param_value in pairs(params) do
|
||||
table.insert(param_list, param_name .. "=" .. param_value)
|
||||
end
|
||||
if #param_list then
|
||||
url = url .. "?" .. table.concat(param_list, "&")
|
||||
end
|
||||
resp = curl.get(url, {
|
||||
headers = {
|
||||
-- ['PRIVATE-TOKEN'] = session.auth,
|
||||
['Authorization'] = session.auth,
|
||||
["content-type"] = "application/json",
|
||||
}})
|
||||
}
|
||||
})
|
||||
elseif method == "post" then
|
||||
resp = curl.post(url, {headers = {
|
||||
resp = curl.post(url, {
|
||||
headers = {
|
||||
-- ['PRIVATE-TOKEN'] = session.auth,
|
||||
['Authorization'] = session.auth,
|
||||
["content-type"] = "application/json",
|
||||
}})
|
||||
},
|
||||
body = vim.json.encode(params)
|
||||
})
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@@ -56,8 +61,20 @@ M.request = function(method, session, endpoint, params)
|
||||
return prjs
|
||||
end
|
||||
|
||||
print("failed http request: " .. tostring(resp.status) .. " (" .. resp.body .. ", " .. url .. ")")
|
||||
return nil
|
||||
error("failed http request: " .. tostring(resp.status) .. " (" .. resp.body .. ", " .. url .. ")")
|
||||
end
|
||||
|
||||
--- @param str string
|
||||
--- @param char? string defaults to " "
|
||||
--- @return string[]
|
||||
M.split = function(str, char)
|
||||
char = char or " "
|
||||
--- @type string[]
|
||||
local ret = {}
|
||||
for part in str:gmatch("[^" .. char .. "]+") do
|
||||
table.insert(ret, part)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
+45
-14
@@ -1,12 +1,15 @@
|
||||
local curl = require("plenary.curl")
|
||||
local notify = require("snacks.notifier").notify
|
||||
local gitlab = require("eta.gitlab")
|
||||
local clickup = require("eta.clickup")
|
||||
local M = {}
|
||||
local curl = require("plenary.curl")
|
||||
local notifier = require("snacks.notifier")
|
||||
local notify = require("snacks.notifier").notify
|
||||
local gitlab = require("eta.gitlab")
|
||||
local clickup = require("eta.clickup")
|
||||
local helpers = require("eta.helpers")
|
||||
local nio = require("nio")
|
||||
local M = {}
|
||||
|
||||
---@param data table
|
||||
---@return string | nil
|
||||
M.table_to_yaml = function(data)
|
||||
M.table_to_yaml = function(data)
|
||||
local json = vim.json.encode(data)
|
||||
|
||||
-- Nutzt 'yq' um JSON zu YAML zu konvertieren
|
||||
@@ -23,7 +26,7 @@ end
|
||||
|
||||
---@param yaml_string string
|
||||
---@return table | nil
|
||||
M.yaml_to_table = function(yaml_string)
|
||||
M.yaml_to_table = function(yaml_string)
|
||||
-- 1. YAML String in yq einspeisen und JSON ausgeben lassen
|
||||
-- Das Flag -o=json sorgt für die Konvertierung
|
||||
local temp_file = os.tmpname()
|
||||
@@ -68,7 +71,7 @@ end
|
||||
M.clickup_session = nil
|
||||
|
||||
---@type eta.gitlab.Session
|
||||
M.gitlab_session = nil
|
||||
M.gitlab_session = nil
|
||||
|
||||
|
||||
---@param task eta.clickup.Task
|
||||
@@ -82,6 +85,27 @@ M._update_task = function(task)
|
||||
end
|
||||
end
|
||||
|
||||
local last_task = clickup.task(M.clickup_session, task.id)
|
||||
|
||||
if task.status == "in review" and last_task.status.status == "in progress" then
|
||||
local resp = curl.post(M.clickup_session.base_url .. "/task/" .. task.id .. "/comment", {
|
||||
headers = {
|
||||
['Authorization'] = M.clickup_session.auth,
|
||||
["accept"] = "application/json",
|
||||
["content-type"] = "application/json",
|
||||
},
|
||||
body = vim.json.encode({
|
||||
comment_text = "pls review",
|
||||
assignee = M.clickup_session.default_reviewer,
|
||||
notify_all = "false",
|
||||
})
|
||||
})
|
||||
|
||||
if resp.status ~= 200 then
|
||||
error("failed to comment " .. task.id .. "\n(" .. resp.body .. ")")
|
||||
end
|
||||
end
|
||||
|
||||
local resp = curl.put(M.clickup_session.base_url .. "/task/" .. task.id, {
|
||||
headers = {
|
||||
['Authorization'] = M.clickup_session.auth,
|
||||
@@ -149,7 +173,7 @@ M._on_select_task = function(picker, item)
|
||||
-- vim.api.nvim_set_option_value("buftype", "nofile", { buf = new_buf_no })
|
||||
vim.api.nvim_set_option_value("filetype", "markdown", { buf = new_buf_no })
|
||||
vim.api.nvim_create_autocmd({ "BufWriteCmd" }, { buffer = new_buf_no, callback = M._on_tempbuf_write })
|
||||
local content = { "---"}
|
||||
local content = { "---" }
|
||||
local to_dump = {}
|
||||
for _, k in ipairs({ "id", "name", "status", "tags", "list", "parent", "dependencies" }) do
|
||||
to_dump[k] = item[k]
|
||||
@@ -228,7 +252,7 @@ end
|
||||
---@param id string
|
||||
M.open_task = function(id)
|
||||
if id:match("[a-z0-9]+") then
|
||||
local notif_id = notify("opening #".. id, "info", { timeout = 1000, title = "ETA", style = 'fancy' })
|
||||
local notif_id = notify("opening #" .. id, "info", { timeout = 1000, title = "ETA", style = 'fancy' })
|
||||
local t = clickup.task(M.clickup_session, id)
|
||||
---@type SelectionItem
|
||||
local item = {
|
||||
@@ -246,7 +270,7 @@ M.open_task = function(id)
|
||||
},
|
||||
action = nil
|
||||
}
|
||||
pcall(M._on_select_task,nil, item)
|
||||
pcall(M._on_select_task, nil, item)
|
||||
else
|
||||
error("invalid id format")
|
||||
end
|
||||
@@ -255,12 +279,19 @@ end
|
||||
---@param data vim.api.keyset.create_user_command.command_args
|
||||
M.select_task = function(data)
|
||||
local notif_id = notify("fetching tasks", "warn", { timeout = 10000, title = "ETA", style = 'fancy' })
|
||||
if not pcall(M.open_task,vim.fn.expand("<cword>")) then
|
||||
local tasks = clickup.latest_tasks(M.clickup_session)
|
||||
|
||||
local args = data.fargs
|
||||
|
||||
if args[1] == "start" then
|
||||
return
|
||||
end
|
||||
|
||||
if not pcall(M.open_task, vim.fn.expand("<cword>")) then
|
||||
---@type SelectionItem[]
|
||||
local items = {}
|
||||
|
||||
local tasks = clickup.latest_tasks(M.clickup_session)
|
||||
|
||||
for tix, t in ipairs(tasks) do
|
||||
if string.sub(t.name, -7, -1) ~= "Absence" then
|
||||
local preview_frontmatter = ""
|
||||
@@ -288,7 +319,7 @@ M.select_task = function(data)
|
||||
action = M._on_select_task
|
||||
}
|
||||
|
||||
for _, k in ipairs({ "id", "name", "status", "tags", "parent"}) do
|
||||
for _, k in ipairs({ "id", "name", "status", "tags", "parent" }) do
|
||||
preview_frontmatter = preview_frontmatter .. "\n" .. k .. ": " .. vim.json.encode(prepared[k])
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
local notify = require("snacks.notifier").notify
|
||||
local helpers = require("eta.helpers")
|
||||
local M = {}
|
||||
|
||||
---@class eta.solidtime.Session: eta.Session
|
||||
---@field auth string personal access token in the form of `Bearer <TOKEN>`
|
||||
---@field org string organization id
|
||||
|
||||
---@class eta.solidtime.User
|
||||
---@field name string
|
||||
---@field id string
|
||||
|
||||
---@param session eta.solidtime.Session
|
||||
---@return eta.solidtime.User
|
||||
M.get_user = function(session)
|
||||
return helpers.request(
|
||||
"get",
|
||||
session,
|
||||
"/users/me",
|
||||
{}
|
||||
).data
|
||||
end
|
||||
|
||||
---@param session eta.solidtime.Session
|
||||
---@param task eta.clickup.Task
|
||||
---@param project? string
|
||||
M.start_new = function(session, task, project)
|
||||
local req = helpers.request(
|
||||
"post",
|
||||
session,
|
||||
"/organizations/" .. session.org .. "/time-entries",
|
||||
{
|
||||
billable = false,
|
||||
member_id = M.get_user(session).id,
|
||||
start = os.date("%Y-%m-%dT%H:%M:%SZ")
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,79 @@
|
||||
-- 1. Map each status to a distinct color, Nerd Font icon, and styling
|
||||
local status_configs = {
|
||||
["backlog"] = { fg = "#7f8c8d", icon = " ", bold = false }, -- Clipboard List
|
||||
["selected for development"] = { fg = "#3498db", icon = " ", bold = false }, -- Target / Bullseye
|
||||
["in progress"] = { fg = "#f1c40f", icon = " ", bold = true }, -- Lightning Bolt
|
||||
["in review"] = { fg = "#9b59b6", icon = " ", bold = true }, -- Eye / Review
|
||||
["on hold"] = { fg = "#e67e22", icon = " ", bold = false }, -- Pause Circle
|
||||
["done"] = { fg = "#2ecc71", icon = " ", bold = true }, -- Checkmark
|
||||
["closed"] = { fg = "#555555", icon = " ", strikethrough = true }, -- Blocked / Minus Circle
|
||||
}
|
||||
|
||||
-- 2. Dynamically build the Neovim Highlight Groups
|
||||
for status, config in pairs(status_configs) do
|
||||
local hl_name = "TaskStatus_" .. status:gsub(" ", "_")
|
||||
vim.api.nvim_set_hl(0, hl_name, {
|
||||
fg = config.fg,
|
||||
bold = config.bold,
|
||||
strikethrough = config.strikethrough
|
||||
})
|
||||
config.hl_group = hl_name
|
||||
end
|
||||
|
||||
-- Subtle gray style for the task title
|
||||
vim.api.nvim_set_hl(0, "TaskTitle", { fg = "#abb2bf", italic = true })
|
||||
|
||||
-- 3. Create a unique namespace
|
||||
local task_hint_ns = vim.api.nvim_create_namespace("custom_task_inlay_hints")
|
||||
|
||||
-- 4. Hijack the native LSP Inlay Hint Renderer
|
||||
local native_inlay_handler = vim.lsp.handlers["textDocument/inlayHint"]
|
||||
|
||||
vim.lsp.handlers["textDocument/inlayHint"] = function(err, result, ctx, config)
|
||||
if err or not result then
|
||||
return native_inlay_handler(err, result, ctx, config)
|
||||
end
|
||||
|
||||
local standard_hints = {}
|
||||
local bufnr = ctx.bufnr or 0
|
||||
|
||||
if vim.api.nvim_buf_is_loaded(bufnr) then
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, task_hint_ns, 0, -1)
|
||||
end
|
||||
|
||||
for _, hint in ipairs(result) do
|
||||
local raw_label = ""
|
||||
if type(hint.label) == "string" then
|
||||
raw_label = hint.label
|
||||
elseif type(hint.label) == "table" then
|
||||
for _, part in ipairs(hint.label) do
|
||||
raw_label = raw_label .. part.value
|
||||
end
|
||||
end
|
||||
|
||||
-- Match format: [<status>] <title>
|
||||
local status, title = raw_label:match("^%[(.-)%]%s*(.*)$")
|
||||
local norm_status = status and status:lower() or ""
|
||||
|
||||
if status_configs[norm_status] then
|
||||
local cfg = status_configs[norm_status]
|
||||
|
||||
-- Multi-colored array using the clean Nerd Font icons
|
||||
local virtual_text_chunks = {
|
||||
{ " ── ", "Comment" },
|
||||
{ cfg.icon, cfg.hl_group }, -- Nerd Font Symbol
|
||||
{ "[" .. status:upper() .. "] ", cfg.hl_group }, -- Colored Status text
|
||||
{ title, "TaskTitle" } -- Muted task name
|
||||
}
|
||||
|
||||
vim.api.nvim_buf_set_extmark(bufnr, task_hint_ns, hint.position.line, hint.position.character, {
|
||||
virt_text = virtual_text_chunks,
|
||||
virt_text_pos = "inline", -- Swap to "eol" if it disrupts typing alignment
|
||||
})
|
||||
else
|
||||
table.insert(standard_hints, hint)
|
||||
end
|
||||
end
|
||||
|
||||
return native_inlay_handler(err, standard_hints, ctx, config)
|
||||
end
|
||||
Reference in New Issue
Block a user