Skip to content

fix confluence links to open in new tab, improve rendering #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions plugins/confluence-plugin/src/components/PageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,89 @@ import {

import "../baseStyles.css";

const addTargetBlank = (htmlString: string): string => {
try {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, "text/html");

doc.querySelectorAll("a").forEach((link) => {
link.setAttribute("target", "_blank");
});

return doc.body.innerHTML;
} catch (error) {
console.error("Error parsing HTML string in addTargetBlank:", error);
return htmlString;
}
};

const makeLinksAbsolute = (htmlString: string, host: string): string => {
try {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, "text/html");

// Loop over all <a> tags
doc.querySelectorAll("a").forEach((link) => {
const href = link.getAttribute("href");
if (href) {
// Check if the link is relative by testing for absolute URL prefixes
if (!href.match(/^https?:\/\//) && !href.startsWith("//")) {
// Create an absolute URL by resolving against the provided host
const absoluteUrl = new URL(href, host).href;
link.setAttribute("href", absoluteUrl);
}
}
});

// Loop over all <img> tags
doc.querySelectorAll("img").forEach((img) => {
const src = img.getAttribute("src");
if (src) {
// Check if the src is relative by testing for absolute URL prefixes
if (!src.match(/^https?:\/\//) && !src.startsWith("//")) {
// Create an absolute URL by resolving against the provided host
const absoluteUrl = new URL(src, host).href;
img.setAttribute("src", absoluteUrl);
}
}
});
// Loop over all <link> tags
doc.querySelectorAll("link").forEach((link) => {
const href = link.getAttribute("href");
if (href) {
// Check if the href is relative by testing for absolute URL prefixes
if (!href.match(/^https?:\/\//) && !href.startsWith("//")) {
// Create an absolute URL by resolving against the provided host
const absoluteUrl = new URL(href, host).href;
link.setAttribute("href", absoluteUrl);
}
}
});
// Loop over all <script> tags
doc.querySelectorAll("script").forEach((script) => {
const src = script.getAttribute("src");
if (src) {
// Check if the src is relative by testing for absolute URL prefixes
if (!src.match(/^https?:\/\//) && !src.startsWith("//")) {
// Create an absolute URL by resolving against the provided host
const absoluteUrl = new URL(src, host).href;
script.setAttribute("src", absoluteUrl);
}
}
});

return doc.body.innerHTML;
} catch (error) {
console.error("Error parsing HTML string in makeLinksAbsolute:", error);
return htmlString;
}
};

const fixHtml = (htmlString: string, host: string): string => {
const updatedHtmlString = makeLinksAbsolute(htmlString, host);
return addTargetBlank(updatedHtmlString);
};

const PageContent: React.FC = () => {
const [entityPage, setEntityPage] = useState<EntityPageI>();
const [errorStr, setErrorStr] = useState<string>("");
Expand Down Expand Up @@ -103,6 +186,19 @@ const PageContent: React.FC = () => {
);
}

if (!contents[`${entityPage.id}`]?.body) {
return (
<Notice>
Confluence page not found. Please check the page ID in the entity.
</Notice>
);
}

contents[`${entityPage.id}`].body = fixHtml(
contents[`${entityPage.id}`].body,
baseConfluenceUrl
);

return (
<Box w="full" minH={600}>
{entityPages.length > 1 && (
Expand Down
6 changes: 3 additions & 3 deletions plugins/confluence-plugin/src/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,15 @@ export const useConfluencePageContent = (
const response = await fetch(
`${baseConfluenceUrl}/wiki/api/v2/pages/${
page.id as string
}?body-format=styled_view`
}?body-format=export_view`
);
const content = await response.json();
if (content.title && content.body?.styled_view?.value) {
if (content.title && content.body?.export_view?.value) {
setContents((prev) => ({
...prev,
[page.id]: {
title: content.title,
body: content.body.styled_view.value,
body: content.body.export_view.value,
},
}));
} else if (content.errors) {
Expand Down
2 changes: 1 addition & 1 deletion plugins/confluence-plugin/src/mocks/mockBodies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const successMockBodies = {
title: "AppDirect Runbook",
macroRenderedOutput: {},
body: {
styled_view: {
export_view: {
value:
'<p><style>[data-colorid=kggi8475gd]{color:#bf2600} html[data-color-mode=dark] [data-colorid=kggi8475gd]{color:#ff6640}</style><strong>This document describes what we do when it breaks!</strong></p><p><br />Step 1 - <span data-colorid="kggi8475gd">EVERYBODY</span> PANIC!!!!!!!</p><p>Step2 - Run to the hills</p><p>Step3 - Run for your lives</p><p /><h2 id="AppDirectRunbook-ArchitecturalDigram">Architectural Digram</h2><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" alt="cloud_infrastructure (3).png" width="760" loading="lazy" src="https://cortex-se-test.atlassian.net/wiki/download/thumbnails/131073/cloud_infrastructure%20(3).png?version=1&amp;modificationDate=1706209753278&amp;cacheVersion=1&amp;api=v2&amp;width=760&amp;height=888" data-image-src="https://cortex-se-test.atlassian.net/wiki/download/attachments/131073/cloud_infrastructure%20(3).png?version=1&amp;modificationDate=1706209753278&amp;cacheVersion=1&amp;api=v2" data-height="1632" data-width="1396" data-unresolved-comment-count="0" data-linked-resource-id="2523157" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="cloud_infrastructure (3).png" data-base-url="https://cortex-se-test.atlassian.net/wiki" data-linked-resource-content-type="image/png" data-linked-resource-container-id="131073" data-linked-resource-container-version="4" data-media-id="d04b592d-798d-486e-80af-6af581929d0b" data-media-type="file" srcset="https://cortex-se-test.atlassian.net/wiki/download/thumbnails/131073/cloud_infrastructure%20(3).png?version=1&amp;modificationDate=1706209753278&amp;cacheVersion=1&amp;api=v2&amp;width=1095&amp;height=1280 2x, https://cortex-se-test.atlassian.net/wiki/download/thumbnails/131073/cloud_infrastructure%20(3).png?version=1&amp;modificationDate=1706209753278&amp;cacheVersion=1&amp;api=v2&amp;width=760&amp;height=888 1x" /></span><p />',
representation: "view",
Expand Down