diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7e0c78ff1..fa15f39e1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,9 +3,9 @@ contact_links: - name: GitHub Discussions url: https://github.com/mermaid-js/mermaid/discussions about: Ask the Community questions or share your own graphs in our discussions. - - name: Slack - url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE - about: Join our Community on Slack for Help and a casual chat. + - name: Discord + url: https://discord.gg/wwtabKgp8y + about: Join our Community on Discord for Help and a casual chat. - name: Documentation url: https://mermaid.js.org about: Read our documentation for all that Mermaid.js can offer. diff --git a/.github/lychee.toml b/.github/lychee.toml index b13e53616..4af304a99 100644 --- a/.github/lychee.toml +++ b/.github/lychee.toml @@ -34,8 +34,8 @@ exclude = [ # Don't check files that are generated during the build via `pnpm docs:code` 'packages/mermaid/src/docs/config/setup/*', -# Ignore slack invite -"https://join.slack.com/" +# Ignore Discord invite +"https://discord.gg" ] # Exclude all private IPs from checking. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 605dea9ab..8901ec345 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,23 +12,23 @@ on: permissions: contents: read +env: + node-version: 18.x + jobs: build-mermaid: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 # uses version from "packageManager" field in package.json - - name: Setup Node.js ${{ matrix.node-version }} + - name: Setup Node.js ${{ env.node-version }} uses: actions/setup-node@v4 with: cache: pnpm - node-version: ${{ matrix.node-version }} + node-version: ${{ env.node-version }} - name: Install Packages run: | diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c23dc88ba..cdd2e27a2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -17,8 +17,9 @@ permissions: contents: read env: + node-version: 18.x # For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used. - targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }} + targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || (github.event.before == '0000000000000000000000000000000000000000' && 'develop' || github.event.before) }} jobs: cache: @@ -30,7 +31,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18.x - - name: Cache snapshots id: cache-snapshot uses: actions/cache@v4 @@ -61,7 +61,6 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x] containers: [1, 2, 3, 4] steps: - uses: actions/checkout@v4 @@ -69,10 +68,10 @@ jobs: - uses: pnpm/action-setup@v2 # uses version from "packageManager" field in package.json - - name: Setup Node.js ${{ matrix.node-version }} + - name: Setup Node.js ${{ env.node-version }} uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ env.node-version }} # These cached snapshots are downloaded, providing the reference snapshots. - name: Cache snapshots diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f0c5560a1..babae3fda 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,23 +13,23 @@ on: permissions: contents: write +env: + node-version: 18.x + jobs: lint: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 # uses version from "packageManager" field in package.json - - name: Setup Node.js ${{ matrix.node-version }} + - name: Setup Node.js ${{ env.node-version }} uses: actions/setup-node@v4 with: cache: pnpm - node-version: ${{ matrix.node-version }} + node-version: ${{ env.node-version }} - name: Install Packages run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a18b31c9c..5ca235b0d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,23 +5,23 @@ on: [push, pull_request, merge_group] permissions: contents: read +env: + node-version: 18.x + jobs: unit-test: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 # uses version from "packageManager" field in package.json - - name: Setup Node.js ${{ matrix.node-version }} + - name: Setup Node.js ${{ env.node-version }} uses: actions/setup-node@v4 with: cache: pnpm - node-version: ${{ matrix.node-version }} + node-version: ${{ env.node-version }} - name: Install Packages run: | diff --git a/README.md b/README.md index 5acafa95d..58287c634 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Generate diagrams from markdown-like text. Live Editor!

- ๐Ÿ“– Documentation | ๐Ÿš€ Getting Started | ๐ŸŒ CDN | ๐Ÿ™Œ Join Us + ๐Ÿ“– Documentation | ๐Ÿš€ Getting Started | ๐ŸŒ CDN | ๐Ÿ™Œ Join Us

็ฎ€ไฝ“ไธญๆ–‡ @@ -33,7 +33,7 @@ Try Live Editor previews of future releases: diff --git a/README.zh-CN.md b/README.zh-CN.md index 23c9bc722..c468b2d9f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -15,7 +15,7 @@ Mermaid ๅฎžๆ—ถ็ผ–่พ‘ๅ™จ!

- ๐Ÿ“– ๆ–‡ๆกฃ | ๐Ÿš€ ๅ…ฅ้—จ | ๐ŸŒ CDN | ๐Ÿ™Œ ๅŠ ๅ…ฅๆˆ‘ไปฌ + ๐Ÿ“– ๆ–‡ๆกฃ | ๐Ÿš€ ๅ…ฅ้—จ | ๐ŸŒ CDN | ๐Ÿ™Œ ๅŠ ๅ…ฅๆˆ‘ไปฌ

English @@ -34,7 +34,7 @@ Mermaid [![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) -[![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) +[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_) diff --git a/applitools.config.js b/applitools.config.js deleted file mode 100644 index 4cf02220a..000000000 --- a/applitools.config.js +++ /dev/null @@ -1,19 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { defineConfig } = require('cypress'); - -module.exports = defineConfig({ - testConcurrency: 1, - browser: [ - // Add browsers with different viewports - // { width: 800, height: 600, name: 'chrome' }, - // { width: 700, height: 500, name: 'firefox' }, - // { width: 1600, height: 1200, name: 'ie11' }, - // { width: 1024, height: 768, name: 'edgechromium' }, - // { width: 800, height: 600, name: 'safari' }, - // // Add mobile emulation devices in Portrait mode - // { deviceName: 'iPhone X', screenOrientation: 'portrait' }, - // { deviceName: 'Pixel 2', screenOrientation: 'portrait' }, - ], - // set batch name to the configuration - // batchName: `Mermaid ${process.env.APPLI_BRANCH ?? "'no APPLI_BRANCH set'"}`, -}); diff --git a/cypress.config.cjs b/cypress.config.cjs deleted file mode 100644 index 33633920a..000000000 --- a/cypress.config.cjs +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - -const { defineConfig } = require('cypress'); -const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin'); -const coverage = require('@cypress/code-coverage/task'); - -module.exports = defineConfig({ - projectId: 'n2sma2', - viewportWidth: 1440, - viewportHeight: 1024, - e2e: { - specPattern: 'cypress/integration/**/*.{js,ts}', - setupNodeEvents(on, config) { - coverage(on, config); - on('before:browser:launch', (browser = {}, launchOptions) => { - if (browser.name === 'chrome' && browser.isHeadless) { - launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1'); - } - return launchOptions; - }); - addMatchImageSnapshotPlugin(on, config); - // copy any needed variables from process.env to config.env - config.env.useAppli = process.env.USE_APPLI ? true : false; - - // do not forget to return the changed config object! - return config; - }, - }, - video: false, -}); - -require('@applitools/eyes-cypress')(module); diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 000000000..4182d92a8 --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from 'cypress'; +import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin'; +import coverage from '@cypress/code-coverage/task'; +import eyesPlugin from '@applitools/eyes-cypress'; +export default eyesPlugin( + defineConfig({ + projectId: 'n2sma2', + viewportWidth: 1440, + viewportHeight: 1024, + e2e: { + specPattern: 'cypress/integration/**/*.{js,ts}', + setupNodeEvents(on, config) { + coverage(on, config); + on('before:browser:launch', (browser, launchOptions) => { + if (browser.name === 'chrome' && browser.isHeadless) { + launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1'); + } + return launchOptions; + }); + addMatchImageSnapshotPlugin(on, config); + // copy any needed variables from process.env to config.env + config.env.useAppli = process.env.USE_APPLI ? true : false; + + // do not forget to return the changed config object! + return config; + }, + }, + video: false, + }) +); diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index e23820ffa..857d395be 100644 --- a/cypress/integration/rendering/flowchart-v2.spec.js +++ b/cypress/integration/rendering/flowchart-v2.spec.js @@ -741,6 +741,25 @@ A ~~~ B ); }); + it('5059: Should render when subgraph contains only subgraphs, has link to outside and itself is part of a link', () => { + imgSnapshotTest( + `flowchart + + subgraph Main + subgraph Child1 + Node1 + Node2 + end + subgraph Child2 + Node3 + Node4 + end + end + Main --> Out1 + Child2 --> Out2` + ); + }); + describe('Markdown strings flowchart (#4220)', () => { describe('html labels', () => { it('With styling and classes', () => { diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js index 73ff4ee00..4abde9d44 100644 --- a/cypress/integration/rendering/gantt.spec.js +++ b/cypress/integration/rendering/gantt.spec.js @@ -583,4 +583,106 @@ describe('Gantt diagram', () => { {} ); }); + + it("should render when there's a semicolon in the title", () => { + imgSnapshotTest( + ` + gantt + title ;Gantt With a Semicolon in the Title + dateFormat YYYY-MM-DD + section Section + A task :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d + `, + {} + ); + }); + + it("should render when there's a semicolon in a section is true", () => { + imgSnapshotTest( + ` + gantt + title Gantt Digram + dateFormat YYYY-MM-DD + section ;Section With a Semicolon + A task :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d + `, + {} + ); + }); + + it("should render when there's a semicolon in the task data", () => { + imgSnapshotTest( + ` + gantt + title Gantt Digram + dateFormat YYYY-MM-DD + section Section + ;A task with a semiclon :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d + `, + {} + ); + }); + + it("should render when there's a hashtag in the title", () => { + imgSnapshotTest( + ` + gantt + title #Gantt With a Hashtag in the Title + dateFormat YYYY-MM-DD + section Section + A task :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d + `, + {} + ); + }); + + it("should render when there's a hashtag in a section is true", () => { + imgSnapshotTest( + ` + gantt + title Gantt Digram + dateFormat YYYY-MM-DD + section #Section With a Hashtag + A task :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d + `, + {} + ); + }); + + it("should render when there's a hashtag in the task data", () => { + imgSnapshotTest( + ` + gantt + title Gantt Digram + dateFormat YYYY-MM-DD + section Section + #A task with a hashtag :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d + `, + {} + ); + }); }); diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index d3e4dd9dd..19ddde31d 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -826,4 +826,121 @@ gitGraph TB: cherry-pick id: "M" parent:"B"` ); }); + it('41: should render default GitGraph with parallelCommits set to false', () => { + imgSnapshotTest( + `gitGraph + commit id:"1-abcdefg" + commit id:"2-abcdefg" + branch develop + commit id:"3-abcdefg" + commit id:"4-abcdefg" + checkout main + branch feature + commit id:"5-abcdefg" + commit id:"6-abcdefg" + checkout main + commit id:"7-abcdefg" + commit id:"8-abcdefg" + `, + { gitGraph: { parallelCommits: false } } + ); + }); + it('42: should render GitGraph with parallel commits', () => { + imgSnapshotTest( + `gitGraph + commit id:"1-abcdefg" + commit id:"2-abcdefg" + branch develop + commit id:"3-abcdefg" + commit id:"4-abcdefg" + checkout main + branch feature + commit id:"5-abcdefg" + commit id:"6-abcdefg" + checkout main + commit id:"7-abcdefg" + commit id:"8-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); + it('43: should render GitGraph with parallel commits | Vertical Branch', () => { + imgSnapshotTest( + `gitGraph TB: + commit id:"1-abcdefg" + commit id:"2-abcdefg" + branch develop + commit id:"3-abcdefg" + commit id:"4-abcdefg" + checkout main + branch feature + commit id:"5-abcdefg" + commit id:"6-abcdefg" + checkout main + commit id:"7-abcdefg" + commit id:"8-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); + it('44: should render GitGraph with unconnected branches and no parallel commits', () => { + imgSnapshotTest( + `gitGraph + branch dev + branch v2 + branch feat + commit id:"1-abcdefg" + commit id:"2-abcdefg" + checkout main + commit id:"3-abcdefg" + checkout dev + commit id:"4-abcdefg" + checkout v2 + commit id:"5-abcdefg" + checkout main + commit id:"6-abcdefg" + `, + { gitGraph: { parallelCommits: false } } + ); + }); + it('45: should render GitGraph with unconnected branches and parallel commits', () => { + imgSnapshotTest( + `gitGraph + branch dev + branch v2 + branch feat + commit id:"1-abcdefg" + commit id:"2-abcdefg" + checkout main + commit id:"3-abcdefg" + checkout dev + commit id:"4-abcdefg" + checkout v2 + commit id:"5-abcdefg" + checkout main + commit id:"6-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); + it('46: should render GitGraph with unconnected branches and parallel commits | Vertical Branch', () => { + imgSnapshotTest( + `gitGraph TB: + branch dev + branch v2 + branch feat + commit id:"1-abcdefg" + commit id:"2-abcdefg" + checkout main + commit id:"3-abcdefg" + checkout dev + commit id:"4-abcdefg" + checkout v2 + commit id:"5-abcdefg" + checkout main + commit id:"6-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); }); diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js index 27e03da9c..10432f057 100644 --- a/cypress/integration/rendering/sequencediagram.spec.js +++ b/cypress/integration/rendering/sequencediagram.spec.js @@ -792,6 +792,34 @@ context('Sequence diagram', () => { }); }); context('links', () => { + it('should support actor links', () => { + renderGraph( + ` + sequenceDiagram + link Alice: Dashboard @ https://dashboard.contoso.com/alice + link Alice: Wiki @ https://wiki.contoso.com/alice + link John: Dashboard @ https://dashboard.contoso.com/john + link John: Wiki @ https://wiki.contoso.com/john + Alice->>John: Hello John
+ John-->>Alice: Great

day! + `, + { securityLevel: 'loose' } + ); + cy.get('#actor0_popup').should((popupMenu) => { + const style = popupMenu.attr('style'); + expect(style).to.undefined; + }); + cy.get('#root-0').click(); + cy.get('#actor0_popup').should((popupMenu) => { + const style = popupMenu.attr('style'); + expect(style).to.match(/^display: block;$/); + }); + cy.get('#root-0').click(); + cy.get('#actor0_popup').should((popupMenu) => { + const style = popupMenu.attr('style'); + expect(style).to.match(/^display: none;$/); + }); + }); it('should support actor links and properties EXPERIMENTAL: USE WITH CAUTION', () => { //Be aware that the syntax for "properties" is likely to be changed. imgSnapshotTest( diff --git a/demos/gantt.html b/demos/gantt.html index 88f52ef5c..9c82371ab 100644 --- a/demos/gantt.html +++ b/demos/gantt.html @@ -30,6 +30,21 @@


+
+      gantt
+        title #; Gantt Diagrams Allow Semicolons and Hashtags #;!
+        accTitle: A simple sample gantt diagram
+        accDescr: 2 sections with 2 tasks each, from 2014
+        dateFormat  YYYY-MM-DD
+        section #;Section
+        #;A task           :a1, 2014-01-01, 30d
+        #;Another task     :after a1  , 20d
+        section #;Another
+        Task in sec      :2014-01-12  , 12d
+        another task      : 24d
+    
+
+
     gantt
       title Airworks roadmap
diff --git a/demos/pie.html b/demos/pie.html
index 3c315ab63..823f61716 100644
--- a/demos/pie.html
+++ b/demos/pie.html
@@ -15,7 +15,7 @@
   
     

Pie chart demos

-      pie title Pets adopted by volunteers
+      pie title Default text position: Animal adoption
         accTitle: simple pie char demo
         accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
         "Dogs": 386
@@ -27,7 +27,7 @@
     
       %%{init: {"pie": {"textPosition": 0.9}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
       pie
-        title Key elements in Product X
+        title Offset labels close to border: Product X
         accTitle: Key elements in Product X
         accDescr: This is a pie chart showing the key elements in Product X.
         "Calcium": 42.96
@@ -36,6 +36,19 @@
         "Iron": 5
     
+
+      %%{init: {"pie": {"textPosition": 0.45}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
+      pie
+        title Centralized labels: Languages
+        accTitle: Key elements in Product X
+        accDescr: This is a pie chart showing the key elements in Product X.
+        "JavaScript": 30
+        "Python": 25
+        "Java": 20
+        "C#": 15
+        "Others": 10
+    
+