From 108fdc502a7beef1de982ab4cffbf9ec92c08134 Mon Sep 17 00:00:00 2001 From: Alamion Date: Mon, 25 Aug 2025 15:05:32 +0300 Subject: [PATCH] Tested and fixed issues from last update --- README.md | 2 ++ manifest.json | 2 +- package.json | 2 +- src/api/base.ts | 6 ++--- src/api/projects.ts | 13 ++++++----- src/commands/addWorkLogBatch.ts | 18 +++++++++++---- src/commands/createIssue.ts | 8 +++---- .../source/ru/commands/add_worklog.yaml | 4 ++-- .../source/ru/commands/create_issue.yaml | 2 +- .../source/ru/commands/get_issue.yaml | 4 ++-- .../source/ru/commands/update_issue.yaml | 2 +- .../source/ru/commands/update_status.yaml | 2 +- src/localization/source/ru/settings/fm.yaml | 2 +- src/main.ts | 1 - src/modals/IssueStatusModal.ts | 15 +++++++++++-- src/tools/mapObsidianJiraFields.ts | 3 +++ src/tools/sectionTools.ts | 22 +++++++++++-------- styles.css | 2 +- 18 files changed, 70 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index abbf968..dea021c 100644 --- a/README.md +++ b/README.md @@ -79,4 +79,6 @@ The auth middleware needs to... `jira-sync-line-openLink` [Open in Jira](http://jira/browse/DEV-42) ``` + + Docs with more detailed info and examples: [GitHub](https://github.com/Alamion/obsidian-jira-sync/tree/master/docs) diff --git a/manifest.json b/manifest.json index 543a0e2..90722df 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "jira-sync", "name": "Jira Issue Manager", - "version": "1.1.9", + "version": "1.2.0", "minAppVersion": "1.7.7", "description": "Get Jira issues, create and update them. Issue status and worklog management.", "author": "Alamion", diff --git a/package.json b/package.json index 7a1cfed..ab98f90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-sample-plugin", - "version": "1.1.9", + "version": "1.2.0", "description": "This is a sample plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { diff --git a/src/api/base.ts b/src/api/base.ts index bf0620f..2906db9 100644 --- a/src/api/base.ts +++ b/src/api/base.ts @@ -18,9 +18,9 @@ export async function baseRequest( throw: false, body } - debugLog(requestParams) + debugLog("Request:\n", requestParams) const response = await requestUrl(requestParams); - debugLog(response); + debugLog("Response:\n", response); if (response.status < 200 || response.status >= 300) { if (response.status === 401 && retries > 0) { await authenticate(plugin); @@ -31,7 +31,7 @@ export async function baseRequest( ${response.text || "Unknown error"} ${body && '\nbody:' + body || ""}`); } - debugLog({"url": `${plugin.settings.jiraUrl}/rest/api/2${additional_url_path}`, + debugLog("Additional request info:\n", {"url": `${plugin.settings.jiraUrl}/rest/api/2${additional_url_path}`, "method": method, "body": body}); return response.status === 204 ? null : response.json; diff --git a/src/api/projects.ts b/src/api/projects.ts index e2133ff..2dcee0a 100644 --- a/src/api/projects.ts +++ b/src/api/projects.ts @@ -1,17 +1,18 @@ import JiraPlugin from "../main"; import {baseRequest} from "./base"; +import {JiraIssueType, JiraProject} from "../interfaces"; -export async function fetchProjects(plugin: JiraPlugin): Promise { +export async function fetchProjects(plugin: JiraPlugin): Promise { const result = await baseRequest(plugin, 'get', '/project'); - plugin.temp_vars.projects = result.map((project: any) => ({ + return result.map((project: any) => ({ id: project.key, name: project.name, - })); + })) as JiraProject[]; } -export async function fetchIssueTypes(plugin: JiraPlugin, projectKey: string): Promise { +export async function fetchIssueTypes(plugin: JiraPlugin, projectKey: string): Promise { const result = await baseRequest(plugin, 'get', `/issue/createmeta/${projectKey}/issuetypes`); - plugin.temp_vars.issueTypes = result.map((type: any) => ({ + return result.values.map((type: any) => ({ name: type.name, - })); + })) as JiraIssueType[]; } diff --git a/src/commands/addWorkLogBatch.ts b/src/commands/addWorkLogBatch.ts index c8b1793..e689f22 100644 --- a/src/commands/addWorkLogBatch.ts +++ b/src/commands/addWorkLogBatch.ts @@ -33,10 +33,13 @@ async function processFrontmatterWorkLogs(plugin: JiraPlugin, _: TFile, jira_wor throw new TypeError(`jira_worklog_batch has an invalid type: ${typeof jira_worklog_batch}`); } } catch (error) { + new Notice("Failed to parse jira_worklog_batch"); console.error("Failed to parse jira_worklog_batch:", error); } if (!foundData || workLogData.length === 0) { + new Notice("No work log data to process"); + console.warn("No work log data to process"); return; } await processWorkLogBatch(plugin, workLogData); @@ -109,10 +112,17 @@ function addFailure(results: { failures: { reason: string; issueKeys: string[] } function convertToStandardDate(dateString: string): string | null { try { - const [datePart, timePart] = dateString.split(' '); - const [day, month, year] = datePart.split('-'); - const [hours, minutes] = timePart.split(':'); - return `${year}-${month}-${day}T${hours}:${minutes}:00.000+0000`; + // Try to parse the date string directly + const date = new Date(dateString); + + if (isNaN(date.getTime())) { + throw new Error("Invalid date format"); + } + + // Format to ISO string and adjust to desired format + const isoString = date.toISOString(); + return isoString.replace('Z', '+0000'); + } catch (error) { console.error("Error converting date:", error); return null; diff --git a/src/commands/createIssue.ts b/src/commands/createIssue.ts index 4db35d0..193167c 100644 --- a/src/commands/createIssue.ts +++ b/src/commands/createIssue.ts @@ -28,15 +28,15 @@ export async function createIssue(plugin: JiraPlugin, file: TFile): Promise { + new ProjectModal(plugin.app, projects, async (projectKey: string) => { // Fetch issue types for the selected project - await fetchIssueTypes(plugin, projectKey); + const issueTypes = await fetchIssueTypes(plugin, projectKey); // Open issue type selection modal - new IssueTypeModal(plugin.app, plugin.temp_vars.issueTypes, async (issueType: string) => { + new IssueTypeModal(plugin.app, issueTypes, async (issueType: string) => { try { // Create the issue with selected project and issue type const issueKey = await createIssueFromFile(plugin, file, projectKey, issueType); diff --git a/src/localization/source/ru/commands/add_worklog.yaml b/src/localization/source/ru/commands/add_worklog.yaml index cc3da34..d20564f 100644 --- a/src/localization/source/ru/commands/add_worklog.yaml +++ b/src/localization/source/ru/commands/add_worklog.yaml @@ -1,4 +1,4 @@ manual: - name: Вести журнал работы в Jira вручную + name: Вести журнал работы в Jira вручную (Update work log in Jira manually) batch: - name: Вести журнал работы в Jira массово + name: Вести журнал работы в Jira массово (Update work log in Jira by batch) diff --git a/src/localization/source/ru/commands/create_issue.yaml b/src/localization/source/ru/commands/create_issue.yaml index cd3c1c3..e2bb9da 100644 --- a/src/localization/source/ru/commands/create_issue.yaml +++ b/src/localization/source/ru/commands/create_issue.yaml @@ -1,3 +1,3 @@ -name: Создать задачу в Jira +name: Создать задачу в Jira (Create issue in Jira) success: Задача {issueKey} успешно создана error: Ошибка при создании задачи diff --git a/src/localization/source/ru/commands/get_issue.yaml b/src/localization/source/ru/commands/get_issue.yaml index 3077254..6bd63b9 100644 --- a/src/localization/source/ru/commands/get_issue.yaml +++ b/src/localization/source/ru/commands/get_issue.yaml @@ -1,2 +1,2 @@ -with_key: Получить данные задачи из Jira по указанному ключу -without_key: Получить данные текущей задачи из Jira +with_key: Получить данные задачи из Jira по номеру (Get issue from Jira with custom key) +without_key: Получить данные текущей задачи из Jira (Get current issue from Jira) diff --git a/src/localization/source/ru/commands/update_issue.yaml b/src/localization/source/ru/commands/update_issue.yaml index 148770c..afcd2b5 100644 --- a/src/localization/source/ru/commands/update_issue.yaml +++ b/src/localization/source/ru/commands/update_issue.yaml @@ -1,3 +1,3 @@ -name: Обновить задачу в Jira +name: Обновить задачу в Jira (Update issue in Jira) success: Задача {issueKey} успешно обновлена error: Ошибка при обновлении задачи diff --git a/src/localization/source/ru/commands/update_status.yaml b/src/localization/source/ru/commands/update_status.yaml index 942b894..a4f6a8a 100644 --- a/src/localization/source/ru/commands/update_status.yaml +++ b/src/localization/source/ru/commands/update_status.yaml @@ -1,3 +1,3 @@ -name: Обновить статус задачи в Jira +name: Обновить статус задачи в Jira (Update issue status in Jira) success: Статус задачи {issueKey} успешно обновлён error: Ошибка при обновлении статуса задачи diff --git a/src/localization/source/ru/settings/fm.yaml b/src/localization/source/ru/settings/fm.yaml index 3829949..273d74e 100644 --- a/src/localization/source/ru/settings/fm.yaml +++ b/src/localization/source/ru/settings/fm.yaml @@ -21,4 +21,4 @@ reset_confirm_title: Сбросить сопоставление полей reset_confirm_text: Сопоставление полей будет очищено. Вы уверены? reload_defaults_tooltip: Обновить reload_confirm_title: Обновить сопоставления полей по умолчанию -reload_confirm_text: Текущие сопоставления полей будут перезаписаны сопоставлениями. Вы уверены? +reload_confirm_text: Текущие сопоставления полей будут перезаписаны сопоставлениями по умолчанию. Вы уверены? diff --git a/src/main.ts b/src/main.ts index 450810c..fb7c463 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,7 +14,6 @@ import {transform_string_to_functions_mappings} from "./tools/convertFunctionStr */ export default class JiraPlugin extends Plugin { settings: JiraSettings; - temp_vars = {projects: [] as JiraProject[], issueTypes: [] as JiraIssueType[]}; async onload() { await this.loadSettings(); diff --git a/src/modals/IssueStatusModal.ts b/src/modals/IssueStatusModal.ts index 69fee62..8697d8b 100644 --- a/src/modals/IssueStatusModal.ts +++ b/src/modals/IssueStatusModal.ts @@ -26,8 +26,19 @@ export class IssueStatusModal extends SuggestModal { } renderSuggestion(type: JiraTransitionType, el: HTMLElement) { - el.createEl("div", {text: type.action && type.status ? `${type.action} -> ${type.status}` : - type.action ? `${type.action}` : `${type.status}`}); + let result = ""; + if (type.action && type.status) { + if (type.action === type.status) { + result = type.action; + } else { + result = `${type.action} (${type.status})`; + } + } else if (type.action) { + result = type.action; + } else if (type.status) { + result = type.status; + } + el.createEl("div", {text: result}); } onChooseSuggestion(type: JiraTransitionType) { diff --git a/src/tools/mapObsidianJiraFields.ts b/src/tools/mapObsidianJiraFields.ts index a3b4666..a8a0623 100644 --- a/src/tools/mapObsidianJiraFields.ts +++ b/src/tools/mapObsidianJiraFields.ts @@ -4,6 +4,7 @@ import {Notice, TFile} from "obsidian"; import JiraPlugin from "../main"; import {extractAllJiraSyncValuesFromContent, updateJiraSyncContent} from "./sectionTools"; import {FieldMapping, obsidianJiraFieldMappings} from "../default/obsidianJiraFieldsMapping"; +import {debugLog} from "./debugLogging"; export function localToJiraFields( @@ -65,6 +66,7 @@ export async function updateJiraToLocal( let updatedContent = fileContent; for (const [fieldName, fieldValue] of Object.entries(syncSections)) { const markdownValue = jiraToMarkdown(fieldValue); + debugLog(`Updating sync section: ${fieldName}: ${markdownValue}`); updatedContent = updateJiraSyncContent(updatedContent, fieldName, markdownValue); } @@ -104,6 +106,7 @@ function updateFieldFromJira( if (key in fieldMappings) { value = fieldMappings[key].fromJira(issue, targetObject); } + // debugLog(`Updating field: ${key}: ${issue.fields[key]}`); // Only update if value exists if (value !== null && value !== undefined) { diff --git a/src/tools/sectionTools.ts b/src/tools/sectionTools.ts index 9bd2d0e..cc1d42f 100644 --- a/src/tools/sectionTools.ts +++ b/src/tools/sectionTools.ts @@ -1,5 +1,9 @@ import {debugLog} from "./debugLogging"; +const getSectionRegex = (sectionName: string) => new RegExp(`\`jira-sync-section-${sectionName}\`([\\s\\S]*?)\\n([\\s\\S]*?)(?=\\n#+ |\\n\`jira-sync-|$)`, 'g'); +const getLineRegex = (sectionName: string) => new RegExp(`\`jira-sync-line-${sectionName}\` *(.*?)(?=\\n|$)`, 'g'); +// ([w-]+) + /** * Updates or adds a Jira sync section in the file content * @param fileContent - The current content of the file @@ -23,17 +27,16 @@ export function updateJiraSyncContent(fileContent: string, sectionName: string, * @returns The updated file content */ function updateJiraSyncSection(fileContent: string, sectionName: string, markdownContent: string, force: boolean = false): string { - const sectionRegex = new RegExp(`(\`jira-sync-section-${sectionName}\` [\\s\\S]*?)\\n([\\s\\S]*?)(?=\\n##|\`jira-sync-|$)`, 'g'); + const sectionRegex = getSectionRegex(sectionName); // If section exists, update it, otherwise append it // debugLog(`Trying to find field ${sectionName} in section`) if (sectionRegex.test(fileContent)) { // Reset regex lastIndex - // debugLog(`Found a field ${sectionName} in section`) sectionRegex.lastIndex = 0; return fileContent.replace( sectionRegex, - (match, group1) => `${group1}\n${markdownContent}\n` + (_, group1) => `\`jira-sync-section-${sectionName}\`${group1}\n${markdownContent}` ); } else if (force) { // No section found, append it @@ -52,7 +55,7 @@ function updateJiraSyncSection(fileContent: string, sectionName: string, markdow * @returns The updated file content */ function updateJiraSyncLine(fileContent: string, lineName: string, lineContent: string, force: boolean = false): string { - const lineRegex = new RegExp(`\`jira-sync-line-${lineName}\`.*?(?=\\n|$)`, 'g'); + const lineRegex = getLineRegex(lineName); const newLine = `\`jira-sync-line-${lineName}\` ${lineContent.split('\n')[0]}`; // If line exists, update it, otherwise append it @@ -88,10 +91,11 @@ export function extractAllJiraSyncValuesFromContent(fileContent: string): Record * @returns Object mapping section names to their content */ function extractAllJiraSyncValuesFromSections(fileContent: string): Record { - const syncSectionRegex = /`jira-sync-section-([\w-]+)` ([\s\S]*?)\n([\s\S]*?)(?=\n##|\n`jira-sync-|$)/g; + const sectionRegex = getSectionRegex(`([\\w-]+)`); + debugLog(sectionRegex); const sections: Record = {}; let match; - while ((match = syncSectionRegex.exec(fileContent)) !== null) { + while ((match = sectionRegex.exec(fileContent)) !== null) { // debugLog(`Found match ${JSON.stringify(match)} in section`) const sectionName = match[1]; sections[sectionName] = match[3].trim(); @@ -106,11 +110,11 @@ function extractAllJiraSyncValuesFromSections(fileContent: string): Record { - const syncLineRegex = /`jira-sync-line-([\w-]+)`\s+(.*?)(?=\n|$)/g; + const lineRegex = getLineRegex(`([\\w-]+)`); + debugLog(lineRegex); const lines: Record = {}; - let match; - while ((match = syncLineRegex.exec(fileContent)) !== null) { + while ((match = lineRegex.exec(fileContent)) !== null) { // debugLog(`Found match ${JSON.stringify(match)} in line`) const lineName = match[1]; lines[lineName] = match[2].trim(); diff --git a/styles.css b/styles.css index 75448a8..ab57bfa 100644 --- a/styles.css +++ b/styles.css @@ -566,7 +566,7 @@ code.hljs { } /* Main display container */ -.all-periods-display { +.jira-copyable { margin-top: 1.5rem; user-select: text; -webkit-user-select: text;