diff --git a/.gitignore b/.gitignore index d5706ae..2f26dca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ node_modules/ -dist/ .DS_Store *.log .env .env.local +package-lock.json diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..e4de27e --- /dev/null +++ b/dist/index.js @@ -0,0 +1,42 @@ +(function(){"use strict";const w=`{:title "PPDB" + :query [:find (pull ?h [:db/id :block/uuid :block/content :block/marker :block/priority :block/created-at :block/updated-at {:block/page [:block/journal-day]}]) + :where + [?p :block/original-name "PPDB - TODO"] + [?h :block/marker ?marker] + [(contains? #{"NOW" "DOING" "TODO"} ?marker)] + [?h :block/page ?p] + [?p :block/journal? false]] + :result-transform (fn [result] + (sort-by (fn [h] + [(get h :block/priority "Z") + (or (get h :block/created-at) 999999999999999)]) result)) + :collapsed? true}`,P=`{:title "Gitea" + :query [:find (pull ?h [:db/id :block/uuid :block/content :block/marker :block/priority :block/created-at :block/updated-at {:block/page [:block/journal-day :block/original-name]}]) + :where + [?p :block/original-name ?name] + [(clojure.string/starts-with? ?name "Gitea -")] + [?h :block/marker ?marker] + [(contains? #{"NOW" "DOING" "TODO"} ?marker)] + [?h :block/page ?p] + [?p :block/journal? false]] + :result-transform (fn [result] + (sort-by (fn [h] + [(get h :block/priority "Z") + (or (get h :block/created-at) 999999999999999)]) result)) + :collapsed? true}`,O=[{key:"ppdbEnabled",type:"boolean",default:!1,title:"PPDB - Включить синхронизацию",description:"Синхронизировать задачи из PPDB"},{key:"ppdbUrl",type:"string",default:"https://ppdb.linux-gaming.ru",title:"PPDB - URL сервера",description:"Базовый URL PPDB API"},{key:"ppdbApiKey",type:"string",default:"",title:"PPDB - API ключ",description:"Ключ для доступа к API"},{key:"ppdbPageName",type:"string",default:"PPDB - TODO",title:"PPDB - Имя страницы",description:"Название страницы для задач PPDB"},{key:"ppdbCategories",type:"string",default:"",title:"PPDB - Категории (через запятую)",description:"Фильтр по категориям: ppdb, linux-gaming, portproton, portprotonqt. Пусто = все"},{key:"giteaEnabled",type:"boolean",default:!1,title:"Gitea - Включить синхронизацию",description:"Синхронизировать issues из Gitea"},{key:"giteaSources",type:"string",default:"[]",title:"Gitea - Источники (JSON)",description:'JSON массив источников: [{"name":"MyRepo","url":"https://gitea.example.com","token":"xxx","owner":"user","repo":"repo","enabled":true}]'},{key:"syncOnStartup",type:"boolean",default:!0,title:"Синхронизация при запуске",description:"Автоматически синхронизировать при запуске Logseq"},{key:"syncInterval",type:"number",default:0,title:"Интервал синхронизации (минуты)",description:"0 = только вручную"},{key:"configVersion",type:"number",default:0,title:"Версия конфигурации (не изменять)",description:"Внутренняя переменная для отслеживания настройки config.edn"}],f=1;async function $(){try{const n=await logseq.App.getCurrentGraph();if(!n?.path)return console.error("Cannot get graph path"),!1;const s=`${n.path}/logseq/config.edn`,t=await window.logseq.FileStorage.getItem(s);if(!t)return console.error("Cannot read config.edn"),!1;let a=!1,e=t;if(!t.includes(':title "PPDB"')){const o=h(e);o>0&&(e=e.slice(0,o)+` + `+w+e.slice(o),a=!0)}if(!e.includes(':title "Gitea"')){const o=h(e);o>0&&(e=e.slice(0,o)+` + `+P+e.slice(o),a=!0)}return e.includes('"PPDB - TODO"')||(e=e.replace(/\(not \[\(contains\? #\{([^}]*)"РЕД СОФТ - TODO"([^}]*)\} \?name\)\]\)/g,'(not [(contains? #{$1"РЕД СОФТ - TODO" "PPDB - TODO"$2} ?name)])'),a=!0),e.includes('clojure.string/starts-with? ?name "Gitea -"')||(e=e.replace(/(\(not \[\(contains\? #\{[^}]*"PPDB - TODO"[^}]*\} \?name\)\]\))(\s*)(\[?\?h :block\/marker)/g,`$1 + (not [(clojure.string/starts-with? ?name "Gitea -")])$2$3`),a=!0),e.includes('"PPDB - TODO"')||(e=e.replace(/:favorites \[([^\]]*)"РЕД СОФТ - TODO"([^\]]*)\]/,':favorites [$1"РЕД СОФТ - TODO" "PPDB - TODO"$2]'),a=!0),a?(await window.logseq.FileStorage.setItem(s,e),console.log("config.edn updated successfully"),!0):!1}catch(n){return console.error("Error setting up config:",n),!1}}function h(n){const s=[/:title "Остальные дела"/,/:title "Остальные"/];for(const a of s){const e=n.match(a);if(e&&e.index){let o=e.index;for(;o>0&&n[o]!=="{";)o--;return o}}const t=n.search(/\]\s*\}\s*;;\s*Add custom commands/);return t>0?t:-1}async function D(){logseq.useSettingsSchema(O),(logseq.settings?.configVersion||0){await p()}),logseq.Editor.registerSlashCommand("sync-ppdb",async()=>{await y()}),logseq.Editor.registerSlashCommand("sync-gitea",async()=>{await m()}),logseq.App.registerUIItem("toolbar",{key:"todo-everywhere-sync",template:` + + + + + + `}),logseq.provideModel({async syncAll(){await p()}}),logseq.settings?.syncOnStartup&&setTimeout(()=>p(),3e3);const s=logseq.settings?.syncInterval;s>0&&setInterval(()=>p(),s*60*1e3),console.log("TODO Everywhere plugin loaded")}async function p(){logseq.UI.showMsg("Синхронизация задач...","info");try{const n=[];if(logseq.settings?.ppdbEnabled){const s=await y();n.push(s)}if(logseq.settings?.giteaEnabled){const s=await m();n.push(s)}n.length===0?logseq.UI.showMsg("Нет включенных источников","warning"):logseq.UI.showMsg(n.join(` +`),"success")}catch(n){console.error("Sync error:",n),logseq.UI.showMsg(`Ошибка синхронизации: ${n}`,"error")}}async function y(){const n=logseq.settings?.ppdbUrl,s=logseq.settings?.ppdbApiKey,t=logseq.settings?.ppdbPageName||"PPDB - TODO",a=(logseq.settings?.ppdbCategories||"").split(",").map(u=>u.trim()).filter(Boolean);if(!n||!s)throw new Error("PPDB: не настроены URL или API ключ");let e=`${n}/api/logseq/tasks?api_key=${s}`;a.length===1&&(e+=`&category=${a[0]}`);const o=await fetch(e);if(!o.ok)throw new Error(`PPDB API error: ${o.status}`);let l=(await o.json()).tasks;a.length>1&&(l=l.filter(u=>a.includes(u.category)));const i=B(l);return await b(t,i),`PPDB: ${l.length} задач`}async function m(){const n=logseq.settings?.giteaSources||"[]";let s;try{s=JSON.parse(n)}catch{throw new Error("Gitea: неверный формат JSON источников")}const t=s.filter(e=>e.enabled);if(t.length===0)return"Gitea: нет активных источников";const a=[];for(const e of t)try{const o=await q(e),r=`Gitea - ${e.name} - TODO`,l=T(o,e);await b(r,l),a.push(`${e.name}: ${o.length}`)}catch(o){console.error(`Gitea ${e.name} error:`,o),a.push(`${e.name}: ошибка`)}return`Gitea: ${a.join(", ")}`}async function q(n){const s=`${n.url}/api/v1/repos/${n.owner}/${n.repo}/issues?state=open&type=issues`,t=await fetch(s,{headers:{Authorization:`token ${n.token}`,"Content-Type":"application/json"}});if(!t.ok)throw new Error(`Gitea API error: ${t.status}`);return await t.json()}function B(n){const s=[];s.push("source:: PPDB"),s.push(`synced:: ${new Date().toISOString()}`),s.push("");const t={TODO:[],DOING:[],DONE:[]};for(const e of n){const o=e.logseq_status;t[o]&&t[o].push(e)}const a={A:0,B:1,C:2};for(const e of Object.keys(t))t[e].sort((o,r)=>(a[o.logseq_priority]||1)-(a[r.logseq_priority]||1));for(const e of[...t.DOING,...t.TODO,...t.DONE]){const o=e.logseq_priority?`[#${e.logseq_priority}] `:"",r=e.task_type?`#${e.task_type} `:"",l=`#${e.category} `;let i=`- ${e.logseq_status} ${o}${r}${l}${e.title}`;if(s.push(i),s.push(` id:: ppdb-${e.id}`),e.url&&s.push(` url:: ${e.url}`),e.description){const u=e.description.split(` +`).filter(c=>c.trim());for(const c of u)s.push(` - ${c}`)}e.admin_comment&&s.push(` - **Комментарий:** ${e.admin_comment}`),e.assigned_to_username&&s.push(` assignee:: ${e.assigned_to_username}`),s.push(` author:: ${e.author_username}`),s.push(` created:: ${e.created_at.split("T")[0]}`)}return s.join(` +`)}function T(n,s){const t=[];t.push("source:: Gitea"),t.push(`repo:: ${s.owner}/${s.repo}`),t.push(`synced:: ${new Date().toISOString()}`),t.push("");const a=r=>{const l=r.labels.map(i=>i.name.toLowerCase());return l.some(i=>i.includes("critical")||i.includes("urgent")||i.includes("p0"))||l.some(i=>i.includes("high")||i.includes("important")||i.includes("p1"))?"A":l.some(i=>i.includes("low")||i.includes("minor")||i.includes("p3"))?"C":"B"},e=r=>{const l=r.labels.map(i=>i.name.toLowerCase());return l.some(i=>i.includes("bug")||i.includes("fix"))?"bug":l.some(i=>i.includes("feature")||i.includes("enhancement"))?"feature":""},o={A:0,B:1,C:2};n.sort((r,l)=>(o[a(r)]||1)-(o[a(l)]||1));for(const r of n){const l=a(r),i=e(r),u=i?`#${i} `:"",c=r.labels.map(g=>`#${g.name.replace(/\s+/g,"-")}`).join(" ");let k=`- TODO [#${l}] ${u}#${r.number} ${r.title}`;if(c&&(k+=` ${c}`),t.push(k),t.push(` id:: gitea-${s.name}-${r.number}`),t.push(` url:: ${r.html_url}`),r.assignee&&t.push(` assignee:: ${r.assignee.login}`),r.milestone&&t.push(` milestone:: ${r.milestone.title}`),t.push(` created:: ${r.created_at.split("T")[0]}`),r.body){const g=r.body.split(` +`).filter(d=>d.trim()).slice(0,5);for(const d of g)t.push(` - ${d.substring(0,200)}`);r.body.split(` +`).length>5&&t.push(" - ...")}}return t.join(` +`)}async function b(n,s){let t=await logseq.Editor.getPage(n);if(t||(t=await logseq.Editor.createPage(n,{},{redirect:!1})),!t)throw new Error(`Не удалось создать страницу ${n}`);const a=await logseq.Editor.getPageBlocksTree(n);for(const o of a)await logseq.Editor.removeBlock(o.uuid);const e=s.split(` +`);if(e.length>0){const o=await logseq.Editor.insertBlock(t.uuid,e[0],{sibling:!1});if(o){let r=o.uuid;for(let l=1;l 'index.js' + }, + rollupOptions: { + external: ['@logseq/libs'], + output: { + globals: { + '@logseq/libs': 'logseq' + } + } + } } })