Tested and fixed issues from last update

This commit is contained in:
Alamion 2025-08-25 15:05:32 +03:00
parent 67308c0fec
commit 108fdc502a
No known key found for this signature in database
GPG key ID: 0DBEAC95BA38C9EF
18 changed files with 70 additions and 40 deletions

View file

@ -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)

View file

@ -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",

View file

@ -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": {

View file

@ -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;

View file

@ -1,17 +1,18 @@
import JiraPlugin from "../main";
import {baseRequest} from "./base";
import {JiraIssueType, JiraProject} from "../interfaces";
export async function fetchProjects(plugin: JiraPlugin): Promise<void> {
export async function fetchProjects(plugin: JiraPlugin): Promise<JiraProject[]> {
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<void> {
export async function fetchIssueTypes(plugin: JiraPlugin, projectKey: string): Promise<JiraIssueType[]> {
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[];
}

View file

@ -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;

View file

@ -28,15 +28,15 @@ export async function createIssue(plugin: JiraPlugin, file: TFile): Promise<void
try {
// Fetch projects to show in selection modal
await fetchProjects(plugin);
const projects = await fetchProjects(plugin);
// Open project selection modal
new ProjectModal(plugin.app, plugin.temp_vars.projects, async (projectKey: string) => {
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);

View file

@ -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)

View file

@ -1,3 +1,3 @@
name: Создать задачу в Jira
name: Создать задачу в Jira (Create issue in Jira)
success: Задача {issueKey} успешно создана
error: Ошибка при создании задачи

View file

@ -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)

View file

@ -1,3 +1,3 @@
name: Обновить задачу в Jira
name: Обновить задачу в Jira (Update issue in Jira)
success: Задача {issueKey} успешно обновлена
error: Ошибка при обновлении задачи

View file

@ -1,3 +1,3 @@
name: Обновить статус задачи в Jira
name: Обновить статус задачи в Jira (Update issue status in Jira)
success: Статус задачи {issueKey} успешно обновлён
error: Ошибка при обновлении статуса задачи

View file

@ -21,4 +21,4 @@ reset_confirm_title: Сбросить сопоставление полей
reset_confirm_text: Сопоставление полей будет очищено. Вы уверены?
reload_defaults_tooltip: Обновить
reload_confirm_title: Обновить сопоставления полей по умолчанию
reload_confirm_text: Текущие сопоставления полей будут перезаписаны сопоставлениями. Вы уверены?
reload_confirm_text: Текущие сопоставления полей будут перезаписаны сопоставлениями по умолчанию. Вы уверены?

View file

@ -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();

View file

@ -26,8 +26,19 @@ export class IssueStatusModal extends SuggestModal<JiraTransitionType> {
}
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) {

View file

@ -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) {

View file

@ -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<string, string> {
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<string, string> = {};
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<strin
* @returns Object mapping line names to their content
*/
function extractAllJiraSyncValuesFromLines(fileContent: string): Record<string, string> {
const syncLineRegex = /`jira-sync-line-([\w-]+)`\s+(.*?)(?=\n|$)/g;
const lineRegex = getLineRegex(`([\\w-]+)`);
debugLog(lineRegex);
const lines: Record<string, string> = {};
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();

View file

@ -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;