mirror of
https://github.com/alamion/obsidian-jira-sync.git
synced 2026-07-22 05:43:04 +00:00
Fix:
- `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:
parent
e3a2a01270
commit
ad06c8f4d8
13 changed files with 20 additions and 186 deletions
|
|
@ -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`.
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ folder:
|
|||
desc: Папка, в которой будут создаваться и искаться задачи Jira
|
||||
placeholder: Jira Issues
|
||||
|
||||
highlight:
|
||||
name: Подсвечивать синхронизируемые разделы
|
||||
desc: Подсвечивать jira-sync-(line | inline | block) разделы в файле. Переоткройте файл после переключения настройки чтобы увидеть изменения.
|
||||
|
||||
template:
|
||||
name: Путь к шаблону
|
||||
desc: Выберите файл шаблона для создания задач Jira
|
||||
|
|
|
|||
11
src/main.ts
11
src/main.ts
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
15
styles.css
15
styles.css
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue