Repository: maxGraph/maxGraph (ts)

Issue:
getting error on edit of graph.
When I double-click on editable node, I get the following:

this.graph.model.isEdge is not a function
TypeError: this.graph.model.isEdge is not a function
    at CellEditorHandler.startEditing 

Am I doing something wrong?

Pull request:
fix: correcly call 'isEdge' in CellEditorHandler
**Summary**
Fix #228 

**Description for the changelog**
`isEdge` is not a model function but rather a function of the cell.


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9dd2541b7..be007d608 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -53,9 +53,9 @@ jobs:
       - name: Build Storybook mini-site
         run: npm run build -w packages/html
       - name: Upload all examples as artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
-          name: bundles-test-results-${{github.sha}}
+          name: bundles-test-results-${{runner.os}}-${{github.sha}}
           path: |
             packages/html/dist/
             packages/ts-example/dist/
diff --git a/.github/workflows/generate-website.yml b/.github/workflows/generate-website.yml
index 82e771632..3e70920ec 100644
--- a/.github/workflows/generate-website.yml
+++ b/.github/workflows/generate-website.yml
@@ -27,7 +27,7 @@ jobs:
       - name: Build website
         run: npm run build -w packages/website
       - name: Upload website artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: website-${{github.sha}}
           path: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b884f4b5..1ac0c12ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ You can use one of the following functions to register codecs:
   - `registerCoreCodecs`
   - `registerEditorCodecs`
 
+To serialize the `maxGraph` model, you can use the `ModelXmlSerializer` class, which registers codecs under the hood.
+
 ## 0.5.0
 
 Release date: `2023-12-07`
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 33ee0a5cd..1a8b55432 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -114,6 +114,7 @@ export { default as SwimlaneOrdering } from './view/layout/hierarchical/Swimlane
 export { default as Codec } from './serialization/Codec';
 export { default as CodecRegistry } from './serialization/CodecRegistry';
 export { default as ObjectCodec } from './serialization/ObjectCodec';
+export * from './serialization/ModelXmlSerializer';
 export * from './serialization/codecs';
 export * from './serialization/register';
 
diff --git a/packages/core/src/serialization/ModelXmlSerializer.ts b/packages/core/src/serialization/ModelXmlSerializer.ts
new file mode 100644
index 000000000..770a1b9ec
--- /dev/null
+++ b/packages/core/src/serialization/ModelXmlSerializer.ts
@@ -0,0 +1,73 @@
+/*
+Copyright 2023-present The maxGraph project Contributors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { registerCoreCodecs } from './register';
+import { getPrettyXml, parseXml } from '../util/xmlUtils';
+import { Codec } from '../index';
+import type GraphDataModel from '../view/GraphDataModel';
+
+/**
+ * Export options of {@link ModelXmlSerializer}.
+ *
+ * **WARN**: this is an experimental feature that is subject to change.
+ *
+ * @alpha
+ * @experimental
+ * @since 0.6.0
+ */
+export type ModelExportOptions = {
+  /**
+   * If `true`, prettify the exported xml.
+   * @default true
+   */
+  pretty?: boolean;
+};
+
+/**
+ * Convenient utility class using {@link Codec} to manage maxGraph model import and export.
+ *
+ * **WARN**: this is an experimental feature that is subject to change (class and method names).
+ *
+ * @alpha
+ * @experimental
+ * @since 0.6.0
+ */
+// Include 'XML' in the class name as there were past discussions about supporting other format like JSON for example
+// See https://github.com/maxGraph/maxGraph/discussions/60 for more details.
+export class ModelXmlSerializer {
+  constructor(private dataModel: GraphDataModel) {
+    this.registerCodecs();
+  }
+
+  import(xml: string): void {
+    const doc = parseXml(xml);
+    new Codec(doc).decode(doc.documentElement, this.dataModel);
+  }
+
+  export(options?: ModelExportOptions): string {
+    const encodedNode = new Codec().encode(this.dataModel);
+    return options?.pretty ?? true
+      ? getPrettyXml(encodedNode)
+      : getPrettyXml(encodedNode, '', '', '');
+  }
+
+  /**
+   * Hook for replacing codecs registered by default (core codecs).
+   */
+  protected registerCodecs(): void {
+    registerCoreCodecs();
+  }
+}
diff --git a/packages/core/src/view/handler/CellEditorHandler.ts b/packages/core/src/view/handler/CellEditorHandler.ts
index 5d878fa7c..c4da8f8cb 100644
--- a/packages/core/src/view/handler/CellEditorHandler.ts
+++ b/packages/core/src/view/handler/CellEditorHandler.ts
@@ -798,8 +798,7 @@ class CellEditorHandler implements GraphPlugin {
       // Workaround for initial offsetHeight not ready for heading in markup
       if (
         this.autoSize &&
-        // @ts-ignore
-        (this.graph.model.isEdge(state.cell) || state.style.overflow !== 'fill')
+        (state.cell.isEdge() || state.style.overflow !== 'fill')
       ) {
         window.setTimeout(() => {
           this.resize();
diff --git a/packages/website/docs/usage/migrate-from-mxgraph.md b/packages/website/docs/usage/migrate-from-mxgraph.md
index a33253776..3e4907397 100644
--- a/packages/website/docs/usage/migrate-from-mxgraph.md
+++ b/packages/website/docs/usage/migrate-from-mxgraph.md
@@ -541,7 +541,9 @@ This is currently not supported in maxGraph: https://github.com/maxGraph/maxGrap
 
 From version 0.6.0 of `maxGraph`, codecs supplied by maxGraph are no longer registered by default, they ** MUST** be registered before performing an `encode` or `decode`
 
-For example, you can use the `registerCoreCodecs` function (or other related functions) to register codecs.
+For example:
+- You can use the `registerCoreCodecs` function (or other related functions) to register codecs.
+- To serialize the `maxGraph` model, you can use the `ModelXmlSerializer` class, which registers codecs under the hood.
 
 :::
 


Test patch:
diff --git a/packages/core/__tests__/serialization/serialization.xml.test.ts b/packages/core/__tests__/serialization/serialization.xml.test.ts
index 13b26c9d2..edaec3866 100644
--- a/packages/core/__tests__/serialization/serialization.xml.test.ts
+++ b/packages/core/__tests__/serialization/serialization.xml.test.ts
@@ -16,47 +16,7 @@ limitations under the License.
 
 import { describe, expect, test } from '@jest/globals';
 import { createGraphWithoutContainer } from '../utils';
-import {
-  Cell,
-  Codec,
-  Geometry,
-  GraphDataModel,
-  Point,
-  registerCoreCodecs,
-} from '../../src';
-import { getPrettyXml, parseXml } from '../../src/util/xmlUtils';
-
-type ModelExportOptions = {
-  /**
-   * @default true
-   */
-  pretty?: boolean;
-};
-
-/**
- * Convenient utility class using {@link Codec} to manage maxGraph model import and export.
- *
- * @internal
- * @alpha subject to change (class and method names)
- */
-class ModelXmlSerializer {
-  // Include 'XML' in the class name as there were past discussions about supporting other format (JSON for example {@link https://github.com/maxGraph/maxGraph/discussions/60}).
-  constructor(private dataModel: GraphDataModel) {
-    registerCoreCodecs();
-  }
-
-  import(xml: string): void {
-    const doc = parseXml(xml);
-    new Codec(doc).decode(doc.documentElement, this.dataModel);
-  }
-
-  export(options?: ModelExportOptions): string {
-    const encodedNode = new Codec().encode(this.dataModel);
-    return options?.pretty ?? true
-      ? getPrettyXml(encodedNode)
-      : getPrettyXml(encodedNode, '', '', '');
-  }
-}
+import { Cell, Geometry, GraphDataModel, ModelXmlSerializer, Point } from '../../src';
 
 // inspired by VertexMixin.createVertex
 const newVertex = (id: string, value: string) => {