-
Notifications
You must be signed in to change notification settings - Fork 11
Replace per-report menu with shared cross-dashboard navigation #52
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
base: master
Are you sure you want to change the base?
Changes from all commits
a2b19d8
e9e8831
a5a4b58
c507e3a
0611949
eb9e08e
68928a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,24 @@ const customStyle = path.join(__dirname, 'custom-style.css'); | |
| const assetFiles = ['custom-script.js', 'custom-style.css']; | ||
| const skippedDirectories = new Set(['data', 'history', 'widgets']); | ||
| const styleTag = ' <link rel="stylesheet" href="custom-style.css">\n'; | ||
| const navDataMarker = 'window.mesheryReportNav ='; | ||
| const scriptTag = ' <script defer src="custom-script.js"></script>\n'; | ||
| const navLabelOverrides = { | ||
| '': 'Home', | ||
| dashboard: 'Dashboard', | ||
| meshery: 'Meshery', | ||
| mesheryctl: 'Mesheryctl', | ||
| layer5Cloud: 'Layer5 Cloud', | ||
| kanvas: 'Kanvas', | ||
| }; | ||
| const navOrder = new Map([ | ||
| ['', 0], | ||
| ['dashboard', 1], | ||
| ['meshery', 2], | ||
| ['mesheryctl', 3], | ||
| ['layer5Cloud', 4], | ||
| ['kanvas', 5], | ||
| ]); | ||
|
|
||
| function findReportPages(dir) { | ||
| const entries = fs.readdirSync(dir, { withFileTypes: true }); | ||
|
|
@@ -43,13 +60,70 @@ function injectBeforeClosingTag(html, tagName, snippet) { | |
| return html.replace(closingTagPattern, (match) => `${snippet}${match}`); | ||
| } | ||
|
|
||
| function ensureInjectedMarkup(html) { | ||
| function formatReportLabel(relativeDir) { | ||
| if (relativeDir in navLabelOverrides) { | ||
| return navLabelOverrides[relativeDir]; | ||
| } | ||
|
|
||
| const reportName = relativeDir.split(path.sep).filter(Boolean).pop() || navLabelOverrides['']; | ||
| return reportName | ||
| .replace(/[-_]+/g, ' ') | ||
| .replace(/([a-z0-9])([A-Z])/g, '$1 $2') | ||
| .replace(/\b\w/g, (letter) => letter.toUpperCase()); | ||
| } | ||
|
|
||
| function toRelativeHref(fromDir, toDir) { | ||
| const relativePath = path.relative(fromDir, toDir).split(path.sep).join('/'); | ||
| return relativePath ? `${relativePath}/` : './'; | ||
| } | ||
|
|
||
| function compareNavEntries(left, right) { | ||
| const leftOrder = navOrder.get(left.relativeDir) ?? Number.MAX_SAFE_INTEGER; | ||
| const rightOrder = navOrder.get(right.relativeDir) ?? Number.MAX_SAFE_INTEGER; | ||
|
|
||
| if (leftOrder !== rightOrder) { | ||
| return leftOrder - rightOrder; | ||
| } | ||
|
|
||
| return left.label.localeCompare(right.label); | ||
| } | ||
|
|
||
| function buildNavEntries(reportPages) { | ||
| return reportPages | ||
| .map((reportPage) => { | ||
| const reportPageDir = path.dirname(reportPage); | ||
| const relativeDir = path.relative(reportDir, reportPageDir); | ||
|
|
||
| return { | ||
| label: formatReportLabel(relativeDir), | ||
| relativeDir, | ||
| reportPageDir, | ||
| }; | ||
| }) | ||
| .sort(compareNavEntries); | ||
| } | ||
|
|
||
| function createNavDataScript(currentPageDir, navEntries) { | ||
| const navData = navEntries.map(({ label, relativeDir, reportPageDir }) => ({ | ||
| label, | ||
| href: toRelativeHref(currentPageDir, reportPageDir), | ||
| })); | ||
| const serializedNavData = JSON.stringify(navData).replace(/</g, '\\u003c'); | ||
|
|
||
| return ` <script>${navDataMarker} ${serializedNavData};</script>\n`; | ||
| } | ||
|
Comment on lines
+106
to
+114
|
||
|
|
||
| function ensureInjectedMarkup(html, navDataScript) { | ||
| let updated = html; | ||
|
|
||
| if (!updated.includes('custom-style.css')) { | ||
| updated = injectBeforeClosingTag(updated, 'head', styleTag); | ||
| } | ||
|
|
||
| if (!updated.includes(navDataMarker)) { | ||
| updated = injectBeforeClosingTag(updated, 'body', navDataScript); | ||
| } | ||
|
|
||
| if (!updated.includes('custom-script.js')) { | ||
| updated = injectBeforeClosingTag(updated, 'body', scriptTag); | ||
| } | ||
|
|
@@ -74,11 +148,13 @@ if (!fs.existsSync(reportDir)) { | |
|
|
||
| const reportPages = findReportPages(reportDir); | ||
| const copiedAssetDirs = new Set(); | ||
| const navEntries = buildNavEntries(reportPages); | ||
|
|
||
| for (const reportPage of reportPages) { | ||
| const reportPageDir = path.dirname(reportPage); | ||
| const html = fs.readFileSync(reportPage, 'utf8'); | ||
| const updatedHtml = ensureInjectedMarkup(html); | ||
| const navDataScript = createNavDataScript(reportPageDir, navEntries); | ||
| const updatedHtml = ensureInjectedMarkup(html, navDataScript); | ||
|
|
||
| if (!copiedAssetDirs.has(reportPageDir)) { | ||
| copyAssets(reportPageDir); | ||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because
applyBranding()is typically triggered multiple times (often via a MutationObserver in this kind of customization script), scanning all buttons and panels each time can become expensive on large Allure pages. Consider adding a single page-level guard (e.g., a module-scoped boolean likelegacyNavHiddenOnce) and early-return once the legacy menu has been hidden, and/or narrowing the selectors to the known navigation container instead of querying the entire document each time.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in
0611949.hideLegacyReportMenu()now uses a module-scopedlegacyNavHiddenOnceguard and exits early after the legacy nav has been hidden, soapplyBranding()no longer keeps rescanning the full page on later observer runs.Screenshot: