mirror of
https://github.com/callumalpass/tasknotes.git
synced 2026-07-22 12:50:26 +00:00
extend bundled release notes
This commit is contained in:
parent
3a27991755
commit
d9d6f511af
4 changed files with 130 additions and 33 deletions
|
|
@ -34,6 +34,7 @@ When a change has user-facing documentation, include a canonical tasknotes.dev l
|
|||
|
||||
## Added
|
||||
|
||||
- Added Canvas Bases to the companion plugin documentation and first-install starter note. See [Canvas Bases](https://tasknotes.dev/companion-plugins/canvas-bases/) for setup and TaskNotes integration details.
|
||||
- Added a TaskNotes starter note that is created and opened automatically on first install to introduce task creation, inline conversion, and embedded Bases views.
|
||||
- Added a runtime API surface for companion plugins to show or populate the standard TaskNotes task context menu.
|
||||
- (#2000) Added separate settings for using the active note as a project during normal task creation and during inline task creation or instant conversion. Thanks to @BlueScreen32 for suggesting the split.
|
||||
|
|
@ -48,6 +49,7 @@ When a change has user-facing documentation, include a canonical tasknotes.dev l
|
|||
- Added a local review-type lint check that catches dependency-resolution warnings from Obsidian's online review before submission.
|
||||
- Improved dependency and project relationship cache updates so ordinary note edits avoid unnecessary relationship recalculation, while blocked and blocking state stays current when dependency status changes.
|
||||
- Improved filter and view query caching so filter options update immediately after relevant task-field changes while large Task List, Kanban, and Calendar queries avoid repeated vault scans.
|
||||
- Extended the in-app release notes bundle to include the current major release, with collapsed versions rendered only when opened.
|
||||
|
||||
## Fixed
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function getVersionDate(version) {
|
|||
}
|
||||
}
|
||||
|
||||
// Get all release note files and bundle versions since last minor (includes pre-release versions)
|
||||
// Get all release note files and bundle versions from the current major series (includes pre-release versions)
|
||||
const releaseFiles = readdirSync("docs/releases")
|
||||
.filter(f => f.match(/^\d+\.\d+\.\d+(?:-[\w.]+)?\.md$/))
|
||||
.map(f => f.replace('.md', ''))
|
||||
|
|
@ -46,21 +46,10 @@ if (!current) {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
// Find all versions in current minor series (e.g., 3.25.x)
|
||||
const currentMinorVersions = releaseFiles.filter(v =>
|
||||
v.major === current.major && v.minor === current.minor
|
||||
);
|
||||
|
||||
// Find all versions from previous minor series (e.g., 3.24.x)
|
||||
const previousMinorVersions = releaseFiles.filter(v =>
|
||||
v.major === current.major && v.minor === current.minor - 1
|
||||
);
|
||||
|
||||
// Bundle current minor + all patches from previous minor
|
||||
const versionsToBundle = [
|
||||
...currentMinorVersions.map(v => v.full),
|
||||
...previousMinorVersions.map(v => v.full)
|
||||
];
|
||||
// Bundle all patches from the current major series.
|
||||
const versionsToBundle = releaseFiles
|
||||
.filter(v => v.major === current.major)
|
||||
.map(v => v.full);
|
||||
|
||||
// Fetch dates and sort by date (newest first)
|
||||
const versionsWithDates = versionsToBundle.map(version => ({
|
||||
|
|
@ -74,6 +63,7 @@ const versionsWithDates = versionsToBundle.map(version => ({
|
|||
// Sort by date descending (newest first)
|
||||
return new Date(b.date).getTime() - new Date(a.date).getTime();
|
||||
});
|
||||
const bundledVersionList = versionsWithDates.map(({ version }) => version);
|
||||
|
||||
// Generate imports and metadata
|
||||
const imports = versionsWithDates.map(({ version }, index) =>
|
||||
|
|
@ -112,4 +102,4 @@ ${releaseNotesArray}
|
|||
writeFileSync("src/releaseNotes.ts", content);
|
||||
|
||||
console.log(`✓ Generated release notes bundle for version ${currentVersion}`);
|
||||
console.log(` Bundled versions: ${versionsToBundle.join(', ')}`);
|
||||
console.log(` Bundled versions: ${bundledVersionList.join(', ')}`);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ItemView, WorkspaceLeaf, MarkdownRenderer } from "obsidian";
|
||||
import { format, parseISO } from "date-fns";
|
||||
import TaskNotesPlugin from "../main";
|
||||
import { ReleaseNoteVersion } from "../releaseNotes";
|
||||
import type { ReleaseNoteVersion } from "../releaseNotes";
|
||||
|
||||
export const RELEASE_NOTES_VIEW_TYPE = "tasknotes-release-notes";
|
||||
|
||||
|
|
@ -80,6 +80,24 @@ export class ReleaseNotesView extends ItemView {
|
|||
}
|
||||
}
|
||||
|
||||
private async renderVersionContent(
|
||||
content: HTMLElement,
|
||||
versionData: ReleaseNoteVersion
|
||||
): Promise<void> {
|
||||
// Transform issue references into clickable links and render the markdown
|
||||
const transformedNotes = this.transformIssueLinks(versionData.content);
|
||||
const releaseContent = versionData.isCurrent
|
||||
? `${this.plugin.i18n.translate("views.releaseNotes.baseFilesNotice")}\n\n${transformedNotes}`
|
||||
: transformedNotes;
|
||||
await MarkdownRenderer.render(
|
||||
this.plugin.app,
|
||||
releaseContent,
|
||||
content,
|
||||
"",
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a collapsible section for a release version
|
||||
*/
|
||||
|
|
@ -378,24 +396,26 @@ export class ReleaseNotesView extends ItemView {
|
|||
content.classList.add("tn-static-padding-0-16px-16px-16px-f1aa998c");
|
||||
content.style.display = isExpanded ? "block" : "none";
|
||||
|
||||
// Transform issue references into clickable links and render the markdown
|
||||
const transformedNotes = this.transformIssueLinks(versionData.content);
|
||||
const releaseContent = versionData.isCurrent
|
||||
? `${this.plugin.i18n.translate("views.releaseNotes.baseFilesNotice")}\n\n${transformedNotes}`
|
||||
: transformedNotes;
|
||||
await MarkdownRenderer.render(
|
||||
this.plugin.app,
|
||||
releaseContent,
|
||||
content,
|
||||
"",
|
||||
this
|
||||
);
|
||||
let renderPromise: Promise<void> | null = null;
|
||||
const renderIfNeeded = () => {
|
||||
if (!renderPromise) {
|
||||
renderPromise = this.renderVersionContent(content, versionData);
|
||||
}
|
||||
return renderPromise;
|
||||
};
|
||||
|
||||
if (isExpanded) {
|
||||
await renderIfNeeded();
|
||||
}
|
||||
|
||||
// Toggle functionality
|
||||
header.addEventListener("click", () => {
|
||||
const isCurrentlyExpanded = content.style.display !== "none";
|
||||
content.style.display = isCurrentlyExpanded ? "none" : "block";
|
||||
chevron.textContent = isCurrentlyExpanded ? "▶" : "▼";
|
||||
if (!isCurrentlyExpanded) {
|
||||
void renderIfNeeded();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -516,11 +536,11 @@ export class ReleaseNotesView extends ItemView {
|
|||
starMessage.appendText(messageText);
|
||||
}
|
||||
|
||||
// Render all versions
|
||||
// Create all version sections
|
||||
const versionsContainer = container.createEl("div", { cls: "release-notes-versions" });
|
||||
for (let i = 0; i < this.releaseNotesBundle.length; i++) {
|
||||
const versionData = this.releaseNotesBundle[i];
|
||||
// Current version and first patch in minor series expanded, others collapsed
|
||||
// Current version and newest bundled version expanded, others collapsed
|
||||
const isExpanded = versionData.isCurrent || i === 0;
|
||||
await this.createVersionSection(versionsContainer, versionData, isExpanded);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { transformReleaseNoteIssueLinks } from "../../../src/views/ReleaseNotesView";
|
||||
import { MarkdownRenderer } from "obsidian";
|
||||
import { ReleaseNotesView, transformReleaseNoteIssueLinks } from "../../../src/views/ReleaseNotesView";
|
||||
import type { ReleaseNoteVersion } from "../../../src/releaseNotes";
|
||||
|
||||
describe("transformReleaseNoteIssueLinks", () => {
|
||||
it("links a single parenthesized issue reference", () => {
|
||||
|
|
@ -26,3 +28,86 @@ describe("transformReleaseNoteIssueLinks", () => {
|
|||
expect(output).toBe(input);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ReleaseNotesView", () => {
|
||||
const createView = () =>
|
||||
new ReleaseNotesView(
|
||||
{} as never,
|
||||
{
|
||||
app: {},
|
||||
i18n: {
|
||||
translate: (key: string) =>
|
||||
key === "views.releaseNotes.baseFilesNotice" ? "Base files notice" : key,
|
||||
},
|
||||
} as never,
|
||||
[],
|
||||
"4.10.2"
|
||||
);
|
||||
|
||||
const releaseNote = (overrides: Partial<ReleaseNoteVersion> = {}): ReleaseNoteVersion => ({
|
||||
version: "4.10.1",
|
||||
content: "Release content",
|
||||
date: null,
|
||||
isCurrent: false,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const createSection = async (versionData: ReleaseNoteVersion, isExpanded: boolean) => {
|
||||
const view = createView();
|
||||
const container = document.createElement("div");
|
||||
await (view as unknown as {
|
||||
createVersionSection: (
|
||||
container: HTMLElement,
|
||||
versionData: ReleaseNoteVersion,
|
||||
isExpanded: boolean
|
||||
) => Promise<void>;
|
||||
}).createVersionSection(container, versionData, isExpanded);
|
||||
return container;
|
||||
};
|
||||
|
||||
const flushPromises = async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.mocked(MarkdownRenderer.render).mockClear();
|
||||
});
|
||||
|
||||
it("renders initially expanded release notes immediately", async () => {
|
||||
const container = await createSection(releaseNote(), true);
|
||||
|
||||
expect(MarkdownRenderer.render).toHaveBeenCalledTimes(1);
|
||||
expect(container.querySelector(".release-notes-version-content")?.textContent).toBe(
|
||||
"Release content"
|
||||
);
|
||||
});
|
||||
|
||||
it("defers collapsed release note rendering until first expansion", async () => {
|
||||
const container = await createSection(releaseNote(), false);
|
||||
|
||||
expect(MarkdownRenderer.render).not.toHaveBeenCalled();
|
||||
expect(container.querySelector(".release-notes-version-content")?.textContent).toBe("");
|
||||
|
||||
container.querySelector<HTMLElement>(".release-notes-version-header")?.click();
|
||||
await flushPromises();
|
||||
|
||||
expect(MarkdownRenderer.render).toHaveBeenCalledTimes(1);
|
||||
expect(container.querySelector(".release-notes-version-content")?.textContent).toBe(
|
||||
"Release content"
|
||||
);
|
||||
});
|
||||
|
||||
it("does not render the same release notes more than once", async () => {
|
||||
const container = await createSection(releaseNote(), false);
|
||||
const header = container.querySelector<HTMLElement>(".release-notes-version-header");
|
||||
|
||||
header?.click();
|
||||
await flushPromises();
|
||||
header?.click();
|
||||
header?.click();
|
||||
await flushPromises();
|
||||
|
||||
expect(MarkdownRenderer.render).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue