diff --git a/.changeset/feat-6270-gantt-multi-line-excludes.md b/.changeset/feat-6270-gantt-multi-line-excludes.md new file mode 100644 index 00000000000..3360653d8a6 --- /dev/null +++ b/.changeset/feat-6270-gantt-multi-line-excludes.md @@ -0,0 +1,5 @@ +--- +'mermaid': minor +--- + +feat(gantt): support multiple `excludes` / `includes` lines so long exclusion lists can be split into commented groups (#6270) diff --git a/cypress/integration/rendering/gantt/gantt.spec.js b/cypress/integration/rendering/gantt/gantt.spec.js index 21b01285a0b..40ce4981c86 100644 --- a/cypress/integration/rendering/gantt/gantt.spec.js +++ b/cypress/integration/rendering/gantt/gantt.spec.js @@ -947,4 +947,21 @@ describe('Gantt diagram', () => { { theme: 'dark' } ); }); + it('should render multi-line excludes (issue #6270)', () => { + imgSnapshotTest( + ` + gantt + dateFormat YYYY-MM-DD + title Multi-line excludes + excludes weekends + %% mid-January closures + excludes 2014-01-15 2014-01-16 + %% one-off holiday + excludes 2014-01-20 + + section A section + Task across closures :a1, 2014-01-13, 14d + ` + ); + }); }); diff --git a/docs/syntax/gantt.md b/docs/syntax/gantt.md index 4ed7acbaa06..3b9bf6463e9 100644 --- a/docs/syntax/gantt.md +++ b/docs/syntax/gantt.md @@ -189,6 +189,18 @@ The `title` is an _optional_ string to be displayed at the top of the Gantt char The `excludes` is an _optional_ attribute that accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays". These date will be marked on the graph, and be excluded from the duration calculation of tasks. Meaning that if there are excluded dates during a task interval, the number of 'skipped' days will be added to the end of the task to ensure the duration is as specified in the code. +Multiple `excludes` lines are supported and their tokens are concatenated, so long exclusion lists can be split across grouped lines with comments: + +``` +gantt + dateFormat DD-MM-YYYY + excludes weekends + %% week 7 is winter break + excludes 10-02-2025 11-02-2025 12-02-2025 13-02-2025 14-02-2025 + %% workers holiday 1 maj + excludes 01-05-2025 +``` + #### Weekend (v\11.0.0+) When excluding weekends, it is possible to configure the weekends to be either Friday and Saturday or Saturday and Sunday. By default weekends are Saturday and Sunday. diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.js b/packages/mermaid/src/diagrams/gantt/ganttDb.js index 6b1d82aff66..88b82c3a57e 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.js +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.js @@ -130,15 +130,23 @@ export const getDateFormat = function () { return dateFormat; }; +const mergeTokens = (existing, txt) => { + const tokens = txt + .toLowerCase() + .split(/[\s,]+/) + .filter((t) => t !== ''); + return [...new Set([...existing, ...tokens])]; +}; + export const setIncludes = function (txt) { - includes = txt.toLowerCase().split(/[\s,]+/); + includes = mergeTokens(includes, txt); }; export const getIncludes = function () { return includes; }; export const setExcludes = function (txt) { - excludes = txt.toLowerCase().split(/[\s,]+/); + excludes = mergeTokens(excludes, txt); }; export const getExcludes = function () { diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts b/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts index 58ab7922267..bd2b88723c2 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts @@ -292,10 +292,34 @@ describe('when using the ganttDb', function () { expect(() => ganttDb.getTasks()).toThrowError('Failed to find a valid date'); // Fridays are now allowed, so it should not throw an error + ganttDb.clear(); + ganttDb.setDateFormat('YYYY-MM-DD'); ganttDb.setExcludes('weekends,monday,tuesday,wednesday,thursday'); + ganttDb.setWeekend('saturday'); + ganttDb.addSection('weekends skip test'); + ganttDb.addTask('test1', 'id1,2019-02-01,7d'); expect(() => ganttDb.getTasks()).not.toThrow(); }); + it('should merge tokens across multiple setExcludes calls (issue #6270)', function () { + ganttDb.setExcludes('weekends'); + ganttDb.setExcludes('2019-02-06'); + ganttDb.setExcludes('friday, monday'); + expect(ganttDb.getExcludes()).toEqual(['weekends', '2019-02-06', 'friday', 'monday']); + }); + + it('should dedupe tokens across multiple setExcludes calls (issue #6270)', function () { + ganttDb.setExcludes('weekends,2019-02-06'); + ganttDb.setExcludes('weekends 2019-02-07'); + expect(ganttDb.getExcludes()).toEqual(['weekends', '2019-02-06', '2019-02-07']); + }); + + it('should merge tokens across multiple setIncludes calls (issue #6270)', function () { + ganttDb.setIncludes('2019-02-06'); + ganttDb.setIncludes('2019-02-07,2019-02-08'); + expect(ganttDb.getIncludes()).toEqual(['2019-02-06', '2019-02-07', '2019-02-08']); + }); + it('should maintain the order in which tasks are created', function () { ganttDb.setAccTitle('Project Execution'); ganttDb.setDateFormat('YYYY-MM-DD'); diff --git a/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js b/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js index 33f91a8825e..0b9923de6b9 100644 --- a/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js +++ b/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js @@ -40,6 +40,26 @@ describe('when parsing a gantt diagram it', function () { expect(parserFnConstructor(str)).not.toThrow(); }); + it('should concatenate tokens across multiple excludes lines (issue #6270)', function () { + const str = [ + 'gantt', + 'dateFormat DD-MM-YYYY', + 'excludes weekends', + '%% week 7 is winter break', + 'excludes 10-02-2025 11-02-2025 12-02-2025', + '%% workers holiday 1 maj', + 'excludes 01-05-2025', + ].join('\n'); + + expect(parserFnConstructor(str)).not.toThrow(); + expect(ganttDb.getExcludes()).toEqual([ + 'weekends', + '10-02-2025', + '11-02-2025', + '12-02-2025', + '01-05-2025', + ]); + }); it('should handle a todayMarker definition', function () { spyOn(ganttDb, 'setTodayMarker'); const str = diff --git a/packages/mermaid/src/docs/syntax/gantt.md b/packages/mermaid/src/docs/syntax/gantt.md index be1930407eb..b1f93548017 100644 --- a/packages/mermaid/src/docs/syntax/gantt.md +++ b/packages/mermaid/src/docs/syntax/gantt.md @@ -131,6 +131,18 @@ The `title` is an _optional_ string to be displayed at the top of the Gantt char The `excludes` is an _optional_ attribute that accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays". These date will be marked on the graph, and be excluded from the duration calculation of tasks. Meaning that if there are excluded dates during a task interval, the number of 'skipped' days will be added to the end of the task to ensure the duration is as specified in the code. +Multiple `excludes` lines are supported and their tokens are concatenated, so long exclusion lists can be split across grouped lines with comments: + +``` +gantt + dateFormat DD-MM-YYYY + excludes weekends + %% week 7 is winter break + excludes 10-02-2025 11-02-2025 12-02-2025 13-02-2025 14-02-2025 + %% workers holiday 1 maj + excludes 01-05-2025 +``` + #### Weekend (v\11.0.0+) When excluding weekends, it is possible to configure the weekends to be either Friday and Saturday or Saturday and Sunday. By default weekends are Saturday and Sunday.