- `jira-sync-block-start-` docs fix
- custom fields functions correct load on startup
- jira values highlight rollback due to contributor dropped feature full realization. (In current state it's too buggy to release)
This commit is contained in:
Alamion 2026-06-03 18:28:38 +03:00
parent e3a2a01270
commit ad06c8f4d8
No known key found for this signature in database
GPG key ID: 0DBEAC95BA38C9EF
13 changed files with 20 additions and 186 deletions

View file

@ -69,9 +69,9 @@ The responsible person for this task is `jira-sync-inline-start-assignee`Bob`jir
Example:
```md
The responsible person for this task is `jira-sync-block-assignee`
The responsible person for this task is `jira-sync-block-start-assignee`
Bob
`jira-sync-end`, and the description is `jira-sync-block-description`
`jira-sync-end`, and the description is `jira-sync-block-start-description`
Some description
`jira-sync-end`.
```

View file

@ -68,9 +68,9 @@
Пример:
```md
Ответственным за эту задачу является `jira-sync-block-assignee`
Ответственным за эту задачу является `jira-sync-block-start-assignee`
Bob
`jira-sync-end`, а описание — `jira-sync-block-description`
`jira-sync-end`, а описание — `jira-sync-block-start-description`
Некоторое описание
`jira-sync-end`.
```

View file

@ -1,7 +1,7 @@
{
"id": "jira-sync",
"name": "Jira Issue Manager",
"version": "1.7.0",
"version": "1.6.1",
"minAppVersion": "1.10.1",
"description": "Get Jira issues, create and update them. Issue status and worklog management.",
"author": "Alamion",

View file

@ -1,6 +1,6 @@
{
"name": "obsidian-jira-sync",
"version": "1.7.0",
"version": "1.6.1",
"packageManager": "yarn@1.22.22",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"main": "main.js",

View file

@ -5,10 +5,6 @@ folder:
desc: Folder where Jira issues will be stored and searched for
placeholder: Jira Issues
highlight:
name: Highlight sync sections
desc: Highlight jira-sync-(line | inline | block) sections in file content. Reopen notes after toggling to see changes.
template:
name: Template path
desc: Select a template file for creating Jira tasks

View file

@ -5,10 +5,6 @@ folder:
desc: Папка, в которой будут создаваться и искаться задачи Jira
placeholder: Jira Issues
highlight:
name: Подсвечивать синхронизируемые разделы
desc: Подсвечивать jira-sync-(line | inline | block) разделы в файле. Переоткройте файл после переключения настройки чтобы увидеть изменения.
template:
name: Путь к шаблону
desc: Выберите файл шаблона для создания задач Jira

View file

@ -47,7 +47,7 @@ export default class JiraPlugin extends Plugin {
this.addSettingTab(new JiraSettingTab(this.app, this));
// Handle Reading mode (post-processor for rendered markdown)
this.registerMarkdownPostProcessor(hideJiraPointersReading(this));
this.registerMarkdownPostProcessor(hideJiraPointersReading());
// Handle Live Preview/Edit mode (CodeMirror extension)
this.registerEditorExtension(createJiraSyncExtension(this));
@ -61,7 +61,14 @@ export default class JiraPlugin extends Plugin {
// TODO: Cancel and delete migration check in future (approximately 2026-2027)
const new_data = checkMigrateSettings(old_data, this.saveSettings);
this.settings = Object.assign({}, DEFAULT_SETTINGS, new_data);
this.settings = {
...DEFAULT_SETTINGS,
...new_data,
fieldMapping: {
...DEFAULT_SETTINGS.fieldMapping,
...(new_data?.fieldMapping || {}),
},
};
this.settings.fieldMapping.fieldMappings = await transform_string_to_functions_mappings(
this.settings.fieldMapping.fieldMappingsStrings,
);

View file

@ -31,14 +31,10 @@ export function createJiraSyncExtension(plugin: JiraPlugin): Extension {
buildDecorations(view: EditorView) {
const builder = new RangeSetBuilder<Decoration>();
const isHighlight = plugin.settings.global.highlightSyncSections;
const sel = view.state.selection;
const allDecs: Array<{ from: number; to: number; dec: Decoration }> = [];
// Scan full document for block pairs so long blocks work when scrolled
const blockRanges = isHighlight ? this.findBlockRanges(view) : [];
for (let { from, to } of view.visibleRanges) {
const text = view.state.doc.sliceString(from, to);
const codeBlocks = this.findCodeBlocks(text, from);
@ -59,52 +55,6 @@ export function createJiraSyncExtension(plugin: JiraPlugin): Extension {
const cls = isActive ? 'jira-sync-hidden jira-sync-active' : 'jira-sync-hidden';
allDecs.push({ from: start, to: end, dec: Decoration.mark({ class: cls }) });
}
if (!isHighlight) continue;
// Inline content: `jira-sync-inline-start-*` ... `jira-sync-end`
for (let i = 0; i < markers.length; i++) {
const m = markers[i];
if (!m.name.startsWith('jira-sync-inline-start-')) continue;
const endMarker = markers.find((em, j) => j > i && em.name === 'jira-sync-end');
if (!endMarker || endMarker.start <= m.end) continue;
allDecs.push({
from: m.end,
to: endMarker.start,
dec: Decoration.mark({ class: 'jira-sync-content' }),
});
}
// Line content: `jira-sync-line-*` followed by text to end of line
for (const m of markers) {
if (!m.name.startsWith('jira-sync-line-')) continue;
const line = view.state.doc.lineAt(m.end);
const nextOnLine = markers.find((nm) => nm.start > m.end && nm.start <= line.to);
const contentEnd = nextOnLine ? nextOnLine.start : line.to;
if (contentEnd > m.end) {
allDecs.push({
from: m.end,
to: contentEnd,
dec: Decoration.mark({ class: 'jira-sync-content' }),
});
}
}
// Block content: decorate visible lines that fall within a full-document block range
const firstVisLine = view.state.doc.lineAt(from).number;
const lastVisLine = view.state.doc.lineAt(to).number;
for (const { startLine, endLine } of blockRanges) {
const decorStart = Math.max(startLine + 1, firstVisLine);
const decorEnd = Math.min(endLine - 1, lastVisLine);
for (let lineNum = decorStart; lineNum <= decorEnd; lineNum++) {
const line = view.state.doc.line(lineNum);
allDecs.push({
from: line.from,
to: line.from,
dec: Decoration.line({ class: 'jira-sync-block-content' }),
});
}
}
}
// RangeSetBuilder requires ranges in ascending order of `from`, then `to`
@ -116,30 +66,6 @@ export function createJiraSyncExtension(plugin: JiraPlugin): Extension {
return builder.finish() as DecorationSet;
}
findBlockRanges(view: EditorView): Array<{ startLine: number; endLine: number }> {
const fullText = view.state.doc.toString();
const codeBlocks = this.findCodeBlocks(fullText, 0);
const ranges: Array<{ startLine: number; endLine: number }> = [];
const blockStarts: Array<{ pos: number }> = [];
for (const match of fullText.matchAll(/`(jira-sync-[^`]+)`/g)) {
const start = match.index!;
const end = start + match[0].length;
if (this.isInsideCodeBlock(start, end, codeBlocks)) continue;
const name = match[1];
if (name.startsWith('jira-sync-block-start-')) {
blockStarts.push({ pos: end });
} else if (name === 'jira-sync-end' && blockStarts.length > 0) {
const bs = blockStarts.pop()!;
const startLine = view.state.doc.lineAt(bs.pos).number;
const endLine = view.state.doc.lineAt(start).number;
ranges.push({ startLine, endLine });
}
}
return ranges;
}
findCodeBlocks(text: string, offset: number) {
const blocks = [];
const regex = /```[\s\S]*?```/g;

View file

@ -1,75 +1,12 @@
import JiraPlugin from '../main';
export function hideJiraPointersReading(plugin: JiraPlugin) {
export function hideJiraPointersReading() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return function (element: HTMLElement, _: any) {
const isHighlight = plugin.settings.global.highlightSyncSections;
const codeElements = Array.from(element.querySelectorAll(':not(pre) > code')).filter((el) =>
el.textContent?.startsWith('jira-sync-'),
) as HTMLElement[];
for (const codeEl of codeElements) {
const text = codeEl.textContent || '';
codeEl.addClass('jira-sync-hidden');
if (!isHighlight) continue;
if (text.startsWith('jira-sync-inline-start-')) {
wrapContentBetween(codeEl, 'jira-sync-end');
} else if (text.startsWith('jira-sync-line-')) {
wrapContentAfter(codeEl);
}
}
};
}
// Wrap sibling nodes between this element and the next jira-sync-end code element
function wrapContentBetween(startEl: HTMLElement, endMarker: string) {
const parent = startEl.parentElement;
if (!parent) return;
const nodesToWrap: Node[] = [];
let node: Node | null = startEl.nextSibling;
while (node) {
if (node.nodeType === Node.ELEMENT_NODE) {
const el = node as HTMLElement;
if (el.tagName === 'CODE' && (el.textContent || '').startsWith(endMarker)) break;
}
nodesToWrap.push(node);
node = node.nextSibling;
}
if (nodesToWrap.length === 0) return;
const wrapper = createSpanWrapper(parent, nodesToWrap[0]);
for (const n of nodesToWrap) wrapper.appendChild(n);
}
// Wrap all sibling nodes after this element (until next jira-sync marker)
function wrapContentAfter(lineEl: HTMLElement) {
const parent = lineEl.parentElement;
if (!parent) return;
const nodesToWrap: Node[] = [];
let node: Node | null = lineEl.nextSibling;
while (node) {
if (node.nodeType === Node.ELEMENT_NODE) {
const el = node as HTMLElement;
if (el.tagName === 'CODE' && (el.textContent || '').startsWith('jira-sync-')) break;
}
nodesToWrap.push(node);
node = node.nextSibling;
}
if (nodesToWrap.length === 0) return;
const wrapper = createSpanWrapper(parent, nodesToWrap[0]);
for (const n of nodesToWrap) wrapper.appendChild(n);
}
function createSpanWrapper(parent: HTMLElement, insertBefore: Node): HTMLElement {
const wrapper = document.createElement('span');
wrapper.addClass('jira-sync-content');
parent.insertBefore(wrapper, insertBefore);
return wrapper;
}

View file

@ -38,17 +38,6 @@ export class GeneralSettingsComponent implements SettingsComponent {
new FolderSuggest(plugin.app, search.inputEl, onChange);
});
// Highlight sync sections toggle
new Setting(containerEl)
.setName(t('highlight.name'))
.setDesc(t('highlight.desc'))
.addToggle((toggle) =>
toggle.setValue(plugin.settings.global.highlightSyncSections).onChange(async (value) => {
plugin.settings.global.highlightSyncSections = value;
await plugin.saveSettings();
}),
);
// Template path setting with native search
const templateInfo = this.detectTemplatePlugins(plugin.app);

View file

@ -14,7 +14,6 @@ export interface ConnectionSettingsInterface {
export interface GlobalSettingsInterface {
issuesFolder: string;
templatePath: string;
highlightSyncSections: boolean;
}
export interface FieldMappingSettingsInterface {
@ -86,7 +85,6 @@ export const DEFAULT_SETTINGS: JiraSettingsInterface = {
global: {
issuesFolder: 'jira-issues',
templatePath: '',
highlightSyncSections: false,
},
fieldMapping: {

View file

@ -340,13 +340,13 @@ export async function transform_string_to_functions_mappings(
// Also convert to functions for runtime use
const transformedMappings: Record<string, FieldMapping> = {};
for (const [fieldName, { toJira, fromJira }] of Object.entries(mappings)) {
const toJiraFn = safeStringToFunction(toJira, 'toJira', extraValidate);
const fromJiraFn = safeStringToFunction(fromJira, 'fromJira', extraValidate);
const toJiraFn = await safeStringToFunction(toJira, 'toJira', extraValidate);
const fromJiraFn = await safeStringToFunction(fromJira, 'fromJira', extraValidate);
if (toJiraFn && fromJiraFn) {
transformedMappings[fieldName] = {
toJira: (await toJiraFn) as (value: any, api_version?: '2' | '3') => any,
fromJira: (await fromJiraFn) as (
toJira: toJiraFn as (value: any, api_version?: '2' | '3') => any,
fromJira: fromJiraFn as (
issue: JiraIssue,
api_version?: '2' | '3',
data_source?: Record<string, any>,

View file

@ -947,21 +947,6 @@ code.hljs {
padding: 0 !important;
}
/* Inline / line synced content highlight */
.jira-sync-content {
background: color-mix(in srgb, var(--interactive-accent) 12%, transparent);
border-radius: 3px;
padding: 0 2px;
outline: 1px solid color-mix(in srgb, var(--interactive-accent) 35%, transparent);
outline-offset: 1px;
}
/* Block content lines — left accent border */
.jira-sync-block-content {
box-shadow: inset 3px 0 0 var(--interactive-accent) !important;
background: color-mix(in srgb, var(--interactive-accent) 5%, transparent) !important;
}
/* JQL Preview Container */
.jql-preview-container {
margin-top: 1rem;