Browse Source

fix(drawio): redirect stencil URLs to local instance when using custom draw.io

viewer-static.min.js defaults all resource paths (stencils, shapes) to
https://viewer.diagrams.net, which is unreachable in offline/air-gapped
environments. When a custom draw.io URI is configured, patch the
mxStencilRegistry.libraries URL map in the onLoad handler before any
diagram is rendered so stencil fetches go to the local instance instead.

Fixes #10726
Claude 1 day ago
parent
commit
ca3392a49b

+ 31 - 1
apps/app/src/components/Script/DrawioViewerScript/DrawioViewerScript.tsx

@@ -6,12 +6,33 @@ import { generateViewerMinJsUrl } from './use-viewer-min-js-url';
 
 declare global {
   var GraphViewer: IGraphViewerGlobal;
+  var mxStencilRegistry: { libraries: Record<string, string[]> } | undefined;
 }
 
 type Props = {
   drawioUri: string;
 };
 
+// viewer-static.min.js defaults all resource paths to viewer.diagrams.net.
+// For local draw.io instances the default is unreachable, so we replace those
+// URLs in mxStencilRegistry.libraries (which are fetched lazily on first use)
+// with paths on the configured local origin before any diagram is rendered.
+// refs: https://github.com/growilabs/growi/issues/10726
+const DEFAULT_DRAWIO_ORIGIN = 'https://embed.diagrams.net';
+const VIEWER_DIAGRAMS_NET_ORIGIN = 'https://viewer.diagrams.net';
+
+const patchStencilRegistryUrls = (localOrigin: string): void => {
+  const libs = mxStencilRegistry?.libraries;
+  if (libs == null) return;
+  for (const key of Object.keys(libs)) {
+    libs[key] = libs[key].map((url) =>
+      typeof url === 'string'
+        ? url.replace(VIEWER_DIAGRAMS_NET_ORIGIN, localOrigin)
+        : url,
+    );
+  }
+};
+
 export const DrawioViewerScript = ({ drawioUri }: Props): JSX.Element => {
   const loadedHandler = useCallback(() => {
     // disable useResizeSensor and checkVisibleState
@@ -29,8 +50,17 @@ export const DrawioViewerScript = ({ drawioUri }: Props): JSX.Element => {
     GraphViewer.prototype.lightboxZIndex = 1200;
     GraphViewer.prototype.toolbarZIndex = 1200;
 
+    try {
+      const origin = new URL(drawioUri).origin;
+      if (origin !== DEFAULT_DRAWIO_ORIGIN) {
+        patchStencilRegistryUrls(origin);
+      }
+    } catch {
+      // skip patching if drawioUri cannot be parsed
+    }
+
     GraphViewer.processElements();
-  }, []);
+  }, [drawioUri]);
 
   // Return empty element if drawioUri is not provided to avoid Invalid URL error
   if (!drawioUri) {