rename
This commit is contained in:
parent
518f2df5c8
commit
7c6c3d7223
|
|
@ -0,0 +1,68 @@
|
|||
from dataclasses import dataclass, field
|
||||
from json import loads
|
||||
from pydantic import BaseModel
|
||||
from requests import HTTPError, get
|
||||
|
||||
from .common import EnvVar, JSONDataMap, JSONData, JSONDataList, JSONDataScalar
|
||||
|
||||
|
||||
class ClickupTask(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClickupSession:
|
||||
auth_key: str = field(
|
||||
default_factory=EnvVar(
|
||||
"CLICKUP_AUTH",
|
||||
"clickup auth token is required to be set",
|
||||
)
|
||||
)
|
||||
workspace_id: str = field(
|
||||
default_factory=EnvVar(
|
||||
"CLICKUP_WORKSPACE_ID",
|
||||
"clickup workspace id is required to be set",
|
||||
)
|
||||
)
|
||||
user_id: str = field(
|
||||
default_factory=EnvVar(
|
||||
"CLICKUP_USER_ID",
|
||||
"clickup user id is required to be set",
|
||||
)
|
||||
)
|
||||
base_url: str = "https://api.clickup.com/api/v2"
|
||||
|
||||
def _get(self, endpoint: str, **query_params: str) -> JSONDataMap:
|
||||
with get(
|
||||
self.base_url + endpoint,
|
||||
query_params,
|
||||
headers={
|
||||
"accept": "application/json",
|
||||
"Authorization": self.auth_key,
|
||||
},
|
||||
) as resp:
|
||||
return resp.json()
|
||||
|
||||
def get_tasks(self, **filters: str) -> list[ClickupTask]:
|
||||
data = self._get(
|
||||
f"/team/{self.workspace_id}/task",
|
||||
**{
|
||||
"subtasks": "true",
|
||||
"include_markdown_description": "true",
|
||||
"assignees[]": self.user_id,
|
||||
}
|
||||
| filters,
|
||||
).get("tasks", [])
|
||||
if isinstance(data, list):
|
||||
return [ClickupTask.model_validate(t) for t in data if isinstance(t, dict)]
|
||||
|
||||
return []
|
||||
|
||||
def get_task(self, task_id: str) -> ClickupTask:
|
||||
return ClickupTask.model_validate(
|
||||
self._get(
|
||||
f"/task/{task_id}",
|
||||
include_markdown_description="true",
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from os import environ
|
||||
from typing import TypeAlias
|
||||
|
||||
|
||||
JSONDataScalar: TypeAlias = str | None | float | bool
|
||||
JSONDataList: TypeAlias = list["JSONDataScalar | JSONDataMap | JSONDataList"]
|
||||
JSONDataMap: TypeAlias = dict[str, "JSONDataScalar | JSONDataList | JSONDataMap"]
|
||||
JSONData: TypeAlias = "JSONDataMap | JSONDataList"
|
||||
|
||||
|
||||
@dataclass
|
||||
class EnvVar:
|
||||
"""
|
||||
Environment Variable fetcher for use in dataclass ``field(default_factory=...)``
|
||||
|
||||
>>> @dataclass
|
||||
>>> class SomeDataclass:
|
||||
... field_name: str = field(default_factory=EnvVar("SOME_VAR_NAME", "err msg"))
|
||||
|
||||
"""
|
||||
|
||||
var_name: str
|
||||
err_msg: str = ""
|
||||
|
||||
def __call__(self) -> str:
|
||||
try:
|
||||
return environ[self.var_name]
|
||||
except KeyError as e:
|
||||
e.add_note(self.err_msg)
|
||||
raise
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
from lsprotocol.types import (
|
||||
TEXT_DOCUMENT_COMPLETION,
|
||||
TEXT_DOCUMENT_DOCUMENT_SYMBOL,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
CompletionItemLabelDetails,
|
||||
CompletionOptions,
|
||||
CompletionParams,
|
||||
DocumentSymbol,
|
||||
DocumentSymbolParams,
|
||||
NotebookDocumentSyncOptions,
|
||||
Position,
|
||||
Range,
|
||||
SymbolKind,
|
||||
TextDocumentSyncKind,
|
||||
WorkDoneProgressBegin,
|
||||
WorkDoneProgressEnd,
|
||||
WorkDoneProgressReport,
|
||||
)
|
||||
from pygls.lsp.server import LanguageServer
|
||||
|
||||
from .clickup import ClickupSession, ClickupTask
|
||||
|
||||
|
||||
class CustomServer(LanguageServer):
|
||||
cache: dict[str, ClickupTask]
|
||||
cu_session: ClickupSession
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
version: str,
|
||||
text_document_sync_kind: TextDocumentSyncKind = TextDocumentSyncKind.Incremental,
|
||||
notebook_document_sync: NotebookDocumentSyncOptions | None = None,
|
||||
) -> None:
|
||||
super().__init__(name, version, text_document_sync_kind, notebook_document_sync)
|
||||
self.cache = {}
|
||||
self.cu_session = ClickupSession()
|
||||
self.update_task_cache()
|
||||
|
||||
def update_task_cache(self) -> None:
|
||||
self.protocol.progress.begin(
|
||||
"startup", WorkDoneProgressBegin("Fetching Cache ...", percentage=0, cancellable=True)
|
||||
)
|
||||
self.cache = {}
|
||||
tasks = self.cu_session.get_ta()
|
||||
for ti, t in enumerate(tasks):
|
||||
self.cache[t.id] = t
|
||||
self.protocol.progress.report(
|
||||
"startup",
|
||||
WorkDoneProgressReport(
|
||||
message="Fetched Cache", percentage=int(100 * (1 + ti) / len(tasks))
|
||||
),
|
||||
)
|
||||
|
||||
self.protocol.progress.end("startup", WorkDoneProgressEnd(message="Done Caching"))
|
||||
|
||||
|
||||
server = CustomServer("mrpy-server", "0.1.0")
|
||||
|
||||
|
||||
@server.feature(TEXT_DOCUMENT_DOCUMENT_SYMBOL)
|
||||
async def list_ids(params: DocumentSymbolParams) -> list[DocumentSymbol]:
|
||||
return [
|
||||
DocumentSymbol(
|
||||
t.id,
|
||||
SymbolKind.Enum,
|
||||
Range(Position(i, 0), Position(i, 0)),
|
||||
Range(Position(i, 0), Position(i, 0)),
|
||||
detail=t.name,
|
||||
)
|
||||
for i, t in enumerate(server.cache.values())
|
||||
]
|
||||
|
||||
|
||||
@server.feature(TEXT_DOCUMENT_COMPLETION)
|
||||
async def complete_cu_ids(params: CompletionParams) -> list[CompletionItem]:
|
||||
return [
|
||||
CompletionItem(
|
||||
t.name,
|
||||
CompletionItemLabelDetails(detail=f" #{t.id}"),
|
||||
kind=CompletionItemKind.Constant,
|
||||
insert_text=f"[{t.name} #{t.id}](https://app.clickup.com/t/{t.id})",
|
||||
)
|
||||
for t in server.cache.values()
|
||||
]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server.start_io()
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
local curl = require("plenary.curl")
|
||||
local helpers = require("eta.helpers")
|
||||
local M = {}
|
||||
|
||||
---@class eta.clickup.Session: eta.Session
|
||||
---@field user string
|
||||
---@field workspace string
|
||||
|
||||
---@class eta.clickup.Ref
|
||||
---@field name string
|
||||
---@field id string
|
||||
|
||||
---@class eta.clickup.Dep
|
||||
---@field task_id string
|
||||
---@field depends_on string
|
||||
|
||||
---@class eta.clickup.Task
|
||||
---@field id string
|
||||
---@field name string
|
||||
---@field tags? table[]
|
||||
---@field locations? table[]
|
||||
---@field list? eta.clickup.Ref
|
||||
---@field parent? string | nil
|
||||
---@field dependencies? eta.clickup.Dep[]
|
||||
---@field [string] string
|
||||
|
||||
---@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})
|
||||
if ret then
|
||||
return ret.tasks
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
---@param self eta.clickup.Session
|
||||
---@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 {}
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param self eta.clickup.Session
|
||||
---@param id string
|
||||
M.task_relations = function(self, id)
|
||||
local ret = helpers.request("get", self, "/task/" .. id .. "/dependency", {}) or {}
|
||||
return ret
|
||||
end
|
||||
|
||||
M.insert_ref = function()
|
||||
local pos = vim.api.nvim_win_get_cursor(0)
|
||||
local row = pos[1] - 1
|
||||
local col = pos[2]
|
||||
local tasks = M.latest_tasks(require("plugin.eta").clickup_session)
|
||||
|
||||
---@type SelectionItem[]
|
||||
local items = {}
|
||||
|
||||
for tix, t in ipairs(tasks) do
|
||||
if string.sub(t.name, -7, -1) ~= "Absence" then
|
||||
local preview_frontmatter = ""
|
||||
|
||||
---@type SelectionItem
|
||||
local prepared = {
|
||||
idx = tix,
|
||||
id = t.id,
|
||||
text = t.name .. t.id .. t.markdown_description,
|
||||
name = t.name,
|
||||
tags = require("plugin.eta").retrieve_subkeys(t.tags, { "name" }),
|
||||
status = t.status.status,
|
||||
parent = t.parent,
|
||||
list = t.list.name,
|
||||
description = t.markdown_description,
|
||||
preview = {
|
||||
ft = "markdown",
|
||||
},
|
||||
action = M._on_select_task
|
||||
}
|
||||
|
||||
for _, k in ipairs({ "id", "name", "status", "tags", "parent" }) do
|
||||
preview_frontmatter = preview_frontmatter .. "\n" .. k .. ": " .. vim.json.encode(prepared[k])
|
||||
end
|
||||
|
||||
prepared.preview.text = "---" .. preview_frontmatter .. "\n---\n" .. t.markdown_description
|
||||
table.insert(items, #items + 1, prepared)
|
||||
end
|
||||
end
|
||||
|
||||
require("snacks.picker").pick({
|
||||
title = "Select Task",
|
||||
format = require("plugin.eta")._item_format,
|
||||
preview = "preview",
|
||||
confirm = function(picker, item)
|
||||
picker:close()
|
||||
vim.api.nvim_buf_set_text(0, row, col, row, col,
|
||||
{ "[#" .. item.id .. "](https://app.clickup.com/t/" .. item.id .. ")" })
|
||||
end,
|
||||
items = items
|
||||
})
|
||||
end
|
||||
return M
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
local notify = require("snacks.notifier").notify
|
||||
local helpers = require("eta.helpers")
|
||||
local M = {}
|
||||
|
||||
---@class eta.gitlab.Session: eta.Session
|
||||
---@field auth string personal access token `PRIVATE_TOKEN: <auth_token>`
|
||||
|
||||
---@class eta.gitlab.Namespace
|
||||
---@field full_path string
|
||||
|
||||
---@class eta.gitlab.Project
|
||||
---@field id number
|
||||
---@field name string
|
||||
---@field path_with_namespace string
|
||||
---@field tag_list string[]
|
||||
---@field text? string
|
||||
---@field namespace eta.gitlab.Namespace
|
||||
---@field preview? {ft: string, text: string}
|
||||
|
||||
---@class eta.gitlab.Milestone
|
||||
---@field id number
|
||||
---@field title string
|
||||
|
||||
---@class eta.gitlab.Assignee
|
||||
---@field username string
|
||||
---@field id number
|
||||
|
||||
---@class eta.gitlab.Issue
|
||||
---@field id number
|
||||
---@field milestone eta.gitlab.Milestone
|
||||
---@field title string
|
||||
---@field assignees eta.gitlab.Assignee[]
|
||||
---@field description string
|
||||
---@field labels string[]
|
||||
|
||||
|
||||
---@param session eta.gitlab.Session
|
||||
---@return eta.gitlab.Project[]
|
||||
M.possible_projects = function(session)
|
||||
return helpers.request("get", session, "/projects", {simple="true", per_page="100"}) or {}
|
||||
end
|
||||
|
||||
---@param prj eta.gitlab.Project
|
||||
M._project_format = function(prj)
|
||||
local ret = {}
|
||||
|
||||
ret[#ret + 1] = { prj.namespace.full_path .. "/", "SnacksPickerComment" }
|
||||
ret[#ret + 1] = { prj.name }
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param self eta.gitlab.Session
|
||||
---@return eta.gitlab.Project | nil
|
||||
M.update_current_project = function(self)
|
||||
local cmd = "git remote -v | grep fetch | cut -f2 | cut -d' ' -f1 | cut -d':' -f2"
|
||||
local handle, _ = io.popen(cmd, 'r')
|
||||
if not handle then return nil end
|
||||
local repo = handle:read("*a")
|
||||
handle:close()
|
||||
|
||||
local prjs = M.possible_projects(self)
|
||||
for _, prj in ipairs(prjs) do
|
||||
if prj.path_with_namespace == repo then
|
||||
M.active_project = prj
|
||||
notify("selected " .. prj.path_with_namespace, "info", { title = "ETA", style = 'fancy' })
|
||||
return prj
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@type eta.gitlab.Project
|
||||
M.active_project = nil
|
||||
|
||||
---@param picker snacks.Picker
|
||||
---@param item eta.gitlab.Project
|
||||
M._on_project_select = function(picker, item)
|
||||
M.active_project = item
|
||||
picker:close()
|
||||
notify("selected " .. item.path_with_namespace, "info", { title = "ETA", style = 'fancy' })
|
||||
end
|
||||
|
||||
---@param self eta.gitlab.Session
|
||||
M.select_project = function(self)
|
||||
local prjs = M.possible_projects(self)
|
||||
require("snacks.picker").pick({
|
||||
title = "Select Project",
|
||||
format = M._project_format,
|
||||
preview = "preview",
|
||||
confirm = M._on_project_select,
|
||||
items = prjs
|
||||
})
|
||||
end
|
||||
|
||||
---@param self eta.gitlab.Session
|
||||
---@return eta.gitlab.Issue[]
|
||||
M.active_issues = function(self)
|
||||
if not M.active_project then
|
||||
if not M.update_current_project(self) then
|
||||
M.select_project(self)
|
||||
end
|
||||
end
|
||||
|
||||
return request("get", self, "/projects/" .. tostring(M.active_project.id) .. "/issues", {})
|
||||
end
|
||||
|
||||
---@param self eta.gitlab.Session
|
||||
---@param name string
|
||||
---@param clickup_task_id string
|
||||
---@param tags string[]
|
||||
M.new_issue = function(self, name, clickup_task_id, tags)
|
||||
if not M.active_project then
|
||||
if not M.update_current_project(self) then
|
||||
M.select_project(self)
|
||||
end
|
||||
end
|
||||
|
||||
local description = "%23" .. clickup_task_id
|
||||
local title = name:gsub("%s", "%20")
|
||||
|
||||
return request("post", self, "/projects/" ..
|
||||
tostring(M.active_project.id) ..
|
||||
"/issues", {
|
||||
title=title, description=description, labels=table.concat(tags, ",")
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
---@param self eta.gitlab.Session
|
||||
---@param name string
|
||||
---@param issue number
|
||||
---@param clickup_task_id string
|
||||
---@param tags string[]
|
||||
M.new_mr = function(self, name, issue, clickup_task_id, tags)
|
||||
if not M.active_project then
|
||||
if not M.update_current_project(self) then
|
||||
M.select_project(self)
|
||||
end
|
||||
end
|
||||
|
||||
local description = "Closes %23" .. tostring(issue) .. " | %23" .. clickup_task_id
|
||||
local title = name:gsub("%s", "%20")
|
||||
|
||||
return request("post", self, "/projects/" .. tostring(M.active_project.id) .. "/merge_requests", {
|
||||
title=title, description=description, labels=table.concat(tags, ",")
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
local curl = require("plenary.curl")
|
||||
local M = {}
|
||||
|
||||
---@class eta.Session
|
||||
---@field auth string
|
||||
---@field base_url string
|
||||
|
||||
---@param method `get` | `post`
|
||||
---@param session eta.Session
|
||||
---@param endpoint string
|
||||
---@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 = {
|
||||
-- ['PRIVATE-TOKEN'] = session.auth,
|
||||
['Authorization'] = session.auth,
|
||||
["content-type"] = "application/json",
|
||||
}})
|
||||
elseif method == "post" then
|
||||
resp = curl.post(url, {headers = {
|
||||
-- ['PRIVATE-TOKEN'] = session.auth,
|
||||
['Authorization'] = session.auth,
|
||||
["content-type"] = "application/json",
|
||||
}})
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
if resp.status == 200 then
|
||||
local prjs = vim.json.decode(resp.body)
|
||||
for _, prj in ipairs(prjs) do
|
||||
local fcmd = "echo '" .. vim.json.encode(prj) .. "' | jq"
|
||||
local fhandle, _ = io.popen(fcmd, 'r')
|
||||
if not fhandle then goto continue end
|
||||
local formatted = fhandle:read("*a")
|
||||
fhandle:close()
|
||||
|
||||
prj.text = prj.path_with_namespace
|
||||
prj.preview = {
|
||||
ft = "json",
|
||||
text = formatted
|
||||
}
|
||||
|
||||
::continue::
|
||||
end
|
||||
return prjs
|
||||
end
|
||||
|
||||
print("failed http request: " .. tostring(resp.status) .. " (" .. resp.body .. ", " .. url .. ")")
|
||||
return nil
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
local curl = require("plenary.curl")
|
||||
local notify = require("snacks.notifier").notify
|
||||
local gitlab = require("eta.gitlab")
|
||||
local clickup = require("eta.clickup")
|
||||
local M = {}
|
||||
|
||||
---@param data table
|
||||
|
|
@ -8,7 +10,7 @@ M.table_to_yaml = function(data)
|
|||
local json = vim.json.encode(data)
|
||||
|
||||
-- Nutzt 'yq' um JSON zu YAML zu konvertieren
|
||||
local handle = io.popen("echo '" .. json .. "' | yq -P e '. ' -")
|
||||
local handle = io.popen("echo '" .. json .. "' | yq -y")
|
||||
local result = handle:read("*a")
|
||||
handle:close()
|
||||
|
||||
|
|
@ -35,12 +37,11 @@ M.yaml_to_table = function(yaml_string)
|
|||
temp_file_handle:flush()
|
||||
temp_file_handle:close()
|
||||
|
||||
local cmd = "yq '.' " .. temp_file
|
||||
local cmd = "cat " .. temp_file .. " | yq"
|
||||
local handle, errres = io.popen(cmd, 'r')
|
||||
local json_result = handle:read("*a")
|
||||
handle:close()
|
||||
|
||||
os.remove(temp_file)
|
||||
|
||||
-- 2. Fehlerprüfung
|
||||
if json_result == "" then
|
||||
|
|
@ -59,53 +60,19 @@ M.yaml_to_table = function(yaml_string)
|
|||
return nil
|
||||
end
|
||||
|
||||
os.remove(temp_file)
|
||||
return table_result
|
||||
end
|
||||
|
||||
---@class ClickupSession
|
||||
---@field auth string
|
||||
---@field user string
|
||||
---@field workspace string
|
||||
---@field base_url string
|
||||
---@type eta.clickup.Session
|
||||
M.clickup_session = nil
|
||||
|
||||
---@type ClickupSession
|
||||
M.session = nil
|
||||
---@type eta.gitlab.Session
|
||||
M.gitlab_session = nil
|
||||
|
||||
---@class ClickupRef
|
||||
---@field name string
|
||||
---@field id string
|
||||
|
||||
---@class ClickupTask
|
||||
---@field id string
|
||||
---@field name string
|
||||
---@field tags? table[]
|
||||
---@field locations? table[]
|
||||
---@field list? ClickupRef
|
||||
---@field parent? string | nil
|
||||
---@field [string] string
|
||||
|
||||
---@return ClickupTask[]
|
||||
M.latest_tasks = function()
|
||||
local resp = curl.get(M.session.base_url ..
|
||||
"/team/" .. M.session.workspace .. "/task?subtasks=true&include_markdown_description=true&assignees[]=" ..
|
||||
M.session.user, {
|
||||
headers = {
|
||||
['Authorization'] = M.session.auth,
|
||||
["accept"] = "application/json",
|
||||
["content-type"] = "application/json",
|
||||
}
|
||||
})
|
||||
|
||||
if resp.status == 200 then
|
||||
return vim.json.decode(resp.body).tasks
|
||||
end
|
||||
|
||||
print("failed http request: " .. tostring(resp.status) .. " (" .. resp.body .. ")")
|
||||
return {}
|
||||
end
|
||||
|
||||
---@param task ClickupTask
|
||||
---@return ClickupTask
|
||||
---@param task eta.clickup.Task
|
||||
---@return eta.clickup.Task
|
||||
M._update_task = function(task)
|
||||
local update_table = {}
|
||||
|
||||
|
|
@ -115,9 +82,9 @@ M._update_task = function(task)
|
|||
end
|
||||
end
|
||||
|
||||
local resp = curl.put(M.session.base_url .. "/task/" .. task.id, {
|
||||
local resp = curl.put(M.clickup_session.base_url .. "/task/" .. task.id, {
|
||||
headers = {
|
||||
['Authorization'] = M.session.auth,
|
||||
['Authorization'] = M.clickup_session.auth,
|
||||
["accept"] = "application/json",
|
||||
["content-type"] = "application/json",
|
||||
},
|
||||
|
|
@ -149,14 +116,16 @@ M._on_tempbuf_write = function(args)
|
|||
end
|
||||
end
|
||||
table.insert(parts, table.concat(current, "\n"))
|
||||
---@type ClickupTask
|
||||
local data = vim.json.decode(parts[2])
|
||||
|
||||
---@type eta.clickup.Task
|
||||
local data = M.yaml_to_table(parts[2]) or {}
|
||||
|
||||
data['markdown_content'] = string.gsub(parts[3], "%-%-%-\n", "")
|
||||
|
||||
M._update_task(data)
|
||||
|
||||
vim.api.nvim_set_option_value("modified", false, { buf = args.buf })
|
||||
local notif_id = notify("updated task #" .. data.id, "info", {title="MrPy", style='fancy'})
|
||||
local notif_id = notify("updated task #" .. data.id, "info", { title = "ETA", style = 'fancy' })
|
||||
end
|
||||
|
||||
---@class SelectionItem
|
||||
|
|
@ -168,9 +137,10 @@ end
|
|||
---@field tags string[]
|
||||
---@field id string
|
||||
|
||||
---@param picker snacks.Picker | nil
|
||||
---@param item SelectionItem
|
||||
M._on_select_task = function(picker, item)
|
||||
local notif_id = notify("opening task #" .. item.id, "info", {title="MrPy", style='fancy'})
|
||||
local notif_id = notify("opening task #" .. item.id, "info", { title = "ETA", style = 'fancy' })
|
||||
local new_name = "[ClickUp] " .. item.name
|
||||
local new_buf_no = vim.api.nvim_create_buf(true, false)
|
||||
|
||||
|
|
@ -179,14 +149,16 @@ 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 = { "---", "{" }
|
||||
for _, k in ipairs({ "id", "name", "status", "tags", "list", "parent" }) do
|
||||
if content[#content] ~= "{" then
|
||||
content[#content] = content[#content] .. ","
|
||||
local content = { "---"}
|
||||
local to_dump = {}
|
||||
for _, k in ipairs({ "id", "name", "status", "tags", "list", "parent", "dependencies" }) do
|
||||
to_dump[k] = item[k]
|
||||
end
|
||||
table.insert(content, ' "' .. k .. '": ' .. vim.json.encode(item[k]))
|
||||
local yaml_string = M.table_to_yaml(to_dump) or ""
|
||||
for line in yaml_string:gmatch("([^\n]*)\n?") do
|
||||
table.insert(content, line)
|
||||
end
|
||||
table.insert(content, "}")
|
||||
-- table.insert(content, "}")
|
||||
table.insert(content, "---")
|
||||
for line in string.gmatch(item.description, "[^\r\n]+") do
|
||||
table.insert(content, line)
|
||||
|
|
@ -196,8 +168,12 @@ M._on_select_task = function(picker, item)
|
|||
vim.api.nvim_win_set_buf(0, new_buf_no)
|
||||
else
|
||||
vim.api.nvim_buf_delete(new_buf_no, {})
|
||||
if picker then
|
||||
picker:close()
|
||||
end
|
||||
local to_open = vim.fn.bufnr(new_name)
|
||||
vim.api.nvim_win_set_buf(0, to_open)
|
||||
end
|
||||
end
|
||||
|
||||
---@param item SelectionItem
|
||||
|
|
@ -249,11 +225,38 @@ M.retrieve_subkeys = function(list, keys)
|
|||
return ret
|
||||
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 t = clickup.task(M.clickup_session, id)
|
||||
---@type SelectionItem
|
||||
local item = {
|
||||
idx = nil,
|
||||
id = t.id,
|
||||
text = t.name .. t.id .. t.markdown_description,
|
||||
name = t.name,
|
||||
tags = M.retrieve_subkeys(t.tags, { "name" }),
|
||||
status = t.status.status,
|
||||
parent = t.parent,
|
||||
list = t.list.name,
|
||||
description = t.markdown_description,
|
||||
preview = {
|
||||
ft = "markdown",
|
||||
},
|
||||
action = nil
|
||||
}
|
||||
pcall(M._on_select_task,nil, item)
|
||||
else
|
||||
error("invalid id format")
|
||||
end
|
||||
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="MrPy", style='fancy'})
|
||||
vim.schedule(function()
|
||||
local tasks = M.latest_tasks()
|
||||
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)
|
||||
|
||||
---@type SelectionItem[]
|
||||
local items = {}
|
||||
|
|
@ -262,6 +265,11 @@ M.select_task = function(data)
|
|||
if string.sub(t.name, -7, -1) ~= "Absence" then
|
||||
local preview_frontmatter = ""
|
||||
|
||||
local deps = {}
|
||||
for _, dependency in ipairs(t.dependencies) do
|
||||
table.insert(deps, dependency.depends_on)
|
||||
end
|
||||
|
||||
---@type SelectionItem
|
||||
local prepared = {
|
||||
idx = tix,
|
||||
|
|
@ -273,6 +281,7 @@ M.select_task = function(data)
|
|||
parent = t.parent,
|
||||
list = t.list.name,
|
||||
description = t.markdown_description,
|
||||
dependencies = deps,
|
||||
preview = {
|
||||
ft = "markdown",
|
||||
},
|
||||
|
|
@ -296,7 +305,15 @@ M.select_task = function(data)
|
|||
confirm = M._on_select_task,
|
||||
items = items
|
||||
})
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
---@param data vim.api.keyset.create_user_command.command_args
|
||||
M.mr_from_task = function(data)
|
||||
if data.args then
|
||||
notify(data.args, "info", { title = "ETA" })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
def main() -> None:
|
||||
pass
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
local eta = require("eta")
|
||||
local eta_clickup = require("eta.clickup")
|
||||
|
||||
vim.api.nvim_create_user_command("ETA", eta.select_task, {})
|
||||
|
||||
---@type eta.clickup.Session
|
||||
eta.clickup_session = {
|
||||
auth = os.getenv("CLICKUP_AUTH") or "",
|
||||
user = os.getenv("CLICKUP_USER_ID") or "",
|
||||
workspace = os.getenv("CLICKUP_WORKSPACE_ID") or "",
|
||||
base_url = "https://api.clickup.com/api/v2",
|
||||
}
|
||||
|
||||
---@type eta.gitlab.Session
|
||||
eta.gitlab_session = {
|
||||
auth = os.getenv("GITLAB_AUTH") or "",
|
||||
base_url = "https://git.extoll.de/api/v4",
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
local mrpy = require("mrpy")
|
||||
|
||||
vim.api.nvim_create_user_command("MrPy", mrpy.select_task, {})
|
||||
|
||||
mrpy.session = {
|
||||
auth = os.getenv("CLICKUP_AUTH") or "",
|
||||
user = os.getenv("CLICKUP_USER_ID") or "",
|
||||
workspace = os.getenv("CLICKUP_WORKSPACE_ID") or "",
|
||||
base_url = "https://api.clickup.com/api/v2",
|
||||
}
|
||||
|
|
@ -3,21 +3,23 @@ requires = ['setuptools>=57', "wheel"]
|
|||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "mrpy-lsp"
|
||||
name = "eta-lsp"
|
||||
version = "0.1.0"
|
||||
description = "Clickup/Gitlab LSP"
|
||||
description = "EXTOLL Task Access"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"pygls~=2.0",
|
||||
"pydantic~=2.12",
|
||||
"requests~=2.32",
|
||||
]
|
||||
authors = [
|
||||
{ name = "Patrick Nisble", email = "acereca@outlook.de"},
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
mrpy-lsp = "mrpy.main:main"
|
||||
eta-lsp = "eta.main:main"
|
||||
|
||||
[tool.setuptools.package.find]
|
||||
[tool.setuptools.packages.find]
|
||||
include = ['mrpy']
|
||||
namespaces = false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "ETA yaml frontmatter",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"backlog",
|
||||
"selected for development",
|
||||
"in progress",
|
||||
"in review",
|
||||
"on hold",
|
||||
"done",
|
||||
"closed"
|
||||
]
|
||||
},
|
||||
"markdown_content": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+$"
|
||||
},
|
||||
"parent_list": {
|
||||
"anyOf": [
|
||||
{
|
||||
"const": 900400316794,
|
||||
"description": "OPE Tooling"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"status",
|
||||
"markdown_content",
|
||||
"parent_list"
|
||||
],
|
||||
"title": "clickup task",
|
||||
"type": "object"
|
||||
}
|
||||
Loading…
Reference in New Issue