mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
Added support for a new link syntax per recommendation:
link <actor>: <label> @ <link-url> Removed documentation for class/icon definitions until we can finalize the design for this. Fixed prettier errors.
This commit is contained in:
parent
b3210ed2ef
commit
85d33ecccd
@ -564,6 +564,7 @@ context('Sequence diagram', () => {
|
||||
links a: {"Repo": "https://www.contoso.com/repo", "Swagger": "https://www.contoso.com/swagger"}
|
||||
links j: {"Repo": "https://www.contoso.com/repo"}
|
||||
links a: {"Dashboard": "https://www.contoso.com/dashboard", "On-Call": "https://www.contoso.com/oncall"}
|
||||
link a: Contacts @ https://contacts.contoso.com/?contact=alice@contoso.com
|
||||
a->>j: Hello John, how are you?
|
||||
j-->>a: Great!
|
||||
`,
|
||||
|
@ -409,6 +409,27 @@ sequenceDiagram
|
||||
## Actor Menus
|
||||
|
||||
Actors can have popup-menus containing individualized links to external pages. For example, if an actor represented a web service, useful links might include a link to the service health dashboard, repo containing the code for the service, or a wiki page describing the service.
|
||||
|
||||
This can be configured by adding one or more link lines with the format:
|
||||
|
||||
link <actor>: <link-label> @ <link-url>
|
||||
|
||||
```
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
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, how are you?
|
||||
John-->>Alice: Great!
|
||||
Alice-)John: See you later!
|
||||
```
|
||||
|
||||
#### Advanced Menu Syntax
|
||||
There is an advanced syntax that relies on JSON formatting. If you are comfortable with JSON format, then this exists as well.
|
||||
|
||||
This can be configured by adding the links lines with the format:
|
||||
|
||||
links <actor>: <json-formatted link-name link-url pairs>
|
||||
@ -426,38 +447,6 @@ sequenceDiagram
|
||||
Alice-)John: See you later!
|
||||
```
|
||||
|
||||
## Actor Individualized Styles & Icons
|
||||
|
||||
Actors can have individualized styling including an embedded icon.
|
||||
This can be configured by adding the properties lines with this format:
|
||||
|
||||
properties <actor>: { "class": "<css className>", "icon": @<built-in-icon-name> -or- <url to an image file>
|
||||
>
|
||||
|
||||
```
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
properties Alice: {"class": "scheduled-job-actor", "icon": "@clock"}
|
||||
properties John: {"class": "database-service-actor", "icon": "https://icons.contoso.com/database.svg"}
|
||||
Alice->>John: Hello John, how are you?
|
||||
John-->>Alice: Great!
|
||||
Alice-)John: See you later!
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
properties Alice: {"icon": "@clock"}
|
||||
properties John: {"icon": "@database"}
|
||||
Alice->>John: Hello John, how are you?
|
||||
John-->>Alice: Great!
|
||||
Alice-)John: See you later!
|
||||
```
|
||||
|
||||
Built-in icon names include @clock, @database, @computer.
|
||||
|
||||
## Styling
|
||||
|
||||
Styling of a sequence diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/sequence.scss
|
||||
|
@ -372,7 +372,7 @@ const config = {
|
||||
*| forceMenus | forces actor popup menus to always be visible (to support E2E testing). | Boolean| Required | True, False |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
*
|
||||
* Default value: false.
|
||||
*/
|
||||
forceMenus: false,
|
||||
|
@ -48,6 +48,7 @@
|
||||
"left of" return 'left_of';
|
||||
"right of" return 'right_of';
|
||||
"links" return 'links';
|
||||
"link" return 'link';
|
||||
"properties" return 'properties';
|
||||
"details" return 'details';
|
||||
"over" return 'over';
|
||||
@ -56,7 +57,7 @@
|
||||
"deactivate" { this.begin('ID'); return 'deactivate'; }
|
||||
"title" return 'title';
|
||||
"sequenceDiagram" return 'SD';
|
||||
"autonumber" return 'autonumber';
|
||||
"autonumber" return 'autonumber';
|
||||
"," return ',';
|
||||
";" return 'NEWLINE';
|
||||
[^\+\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
@ -66,8 +67,8 @@
|
||||
"-->" return 'DOTTED_OPEN_ARROW';
|
||||
\-[x] return 'SOLID_CROSS';
|
||||
\-\-[x] return 'DOTTED_CROSS';
|
||||
\-[\)] return 'SOLID_POINT';
|
||||
\-\-[\)] return 'DOTTED_POINT';
|
||||
\-[\)] return 'SOLID_POINT';
|
||||
\-\-[\)] return 'DOTTED_POINT';
|
||||
":"(?:(?:no)?wrap:)?[^#\n;]+ return 'TXT';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
@ -114,6 +115,7 @@ statement
|
||||
| 'deactivate' actor 'NEWLINE' {$$={type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $2};}
|
||||
| note_statement 'NEWLINE'
|
||||
| links_statement 'NEWLINE'
|
||||
| link_statement 'NEWLINE'
|
||||
| properties_statement 'NEWLINE'
|
||||
| details_statement 'NEWLINE'
|
||||
| title text2 'NEWLINE' {$$=[{type:'setTitle', text:$2}]}
|
||||
@ -183,6 +185,13 @@ links_statement
|
||||
}
|
||||
;
|
||||
|
||||
link_statement
|
||||
: 'link' actor text2
|
||||
{
|
||||
$$ = [$2, {type:'addALink', actor:$2.actor, text:$3}];
|
||||
}
|
||||
;
|
||||
|
||||
properties_statement
|
||||
: 'properties' actor text2
|
||||
{
|
||||
|
@ -218,8 +218,24 @@ export const addLinks = function (actorId, text) {
|
||||
const links = JSON.parse(text.text);
|
||||
// add the deserialized text to the actor's links field.
|
||||
insertLinks(actor, links);
|
||||
} catch (e) {
|
||||
log.error('error while parsing actor link text', e);
|
||||
}
|
||||
catch (e) {
|
||||
};
|
||||
|
||||
export const addALink = function (actorId, text) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
try {
|
||||
const links = {};
|
||||
var sep = text.text.indexOf('@');
|
||||
var label = text.text.slice(0, sep - 1).trim();
|
||||
var link = text.text.slice(sep + 1).trim();
|
||||
|
||||
links[label] = link;
|
||||
// add the deserialized text to the actor's links field.
|
||||
insertLinks(actor, links);
|
||||
} catch (e) {
|
||||
log.error('error while parsing actor link text', e);
|
||||
}
|
||||
};
|
||||
@ -227,8 +243,7 @@ export const addLinks = function (actorId, text) {
|
||||
function insertLinks(actor, links) {
|
||||
if (actor.links == null) {
|
||||
actor.links = links;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (let key in links) {
|
||||
actor.links[key] = links[key];
|
||||
}
|
||||
@ -243,8 +258,7 @@ export const addProperties = function (actorId, text) {
|
||||
const properties = JSON.parse(text.text);
|
||||
// add the deserialized text to the actor's property field.
|
||||
insertProperties(actor, properties);
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
log.error('error while parsing actor properties text', e);
|
||||
}
|
||||
};
|
||||
@ -252,8 +266,7 @@ export const addProperties = function (actorId, text) {
|
||||
function insertProperties(actor, properties) {
|
||||
if (actor.properties == null) {
|
||||
actor.properties = properties;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (let key in properties) {
|
||||
actor.properties[key] = properties[key];
|
||||
}
|
||||
@ -270,15 +283,14 @@ export const addDetails = function (actorId, text) {
|
||||
const text = elem.innerHTML;
|
||||
const details = JSON.parse(text);
|
||||
// add the deserialized text to the actor's property field.
|
||||
if (details["properties"]) {
|
||||
insertProperties(actor, details["properties"]);
|
||||
if (details['properties']) {
|
||||
insertProperties(actor, details['properties']);
|
||||
}
|
||||
|
||||
if (details["links"]) {
|
||||
insertLinks(actor, details["links"]);
|
||||
if (details['links']) {
|
||||
insertLinks(actor, details['links']);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
log.error('error while parsing actor details text', e);
|
||||
}
|
||||
};
|
||||
@ -318,6 +330,9 @@ export const apply = function (param) {
|
||||
case 'addLinks':
|
||||
addLinks(param.actor, param.text);
|
||||
break;
|
||||
case 'addALink':
|
||||
addALink(param.actor, param.text);
|
||||
break;
|
||||
case 'addProperties':
|
||||
addProperties(param.actor, param.text);
|
||||
break;
|
||||
|
@ -908,6 +908,9 @@ participant c as Charlie
|
||||
links a: { "Repo": "https://repo.contoso.com/", "Dashboard": "https://dashboard.contoso.com/" }
|
||||
links b: { "Dashboard": "https://dashboard.contoso.com/" }
|
||||
links a: { "On-Call": "https://oncall.contoso.com/?svc=alice" }
|
||||
link a: Endpoint @ https://alice.contoso.com
|
||||
link a: Swagger @ https://swagger.contoso.com
|
||||
link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com
|
||||
`;
|
||||
console.log(str);
|
||||
|
||||
@ -919,6 +922,9 @@ links a: { "On-Call": "https://oncall.contoso.com/?svc=alice" }
|
||||
expect(actors.b.links["Dashboard"]).toBe("https://dashboard.contoso.com/");
|
||||
expect(actors.a.links["On-Call"]).toBe("https://oncall.contoso.com/?svc=alice");
|
||||
expect(actors.c.links["Dashboard"]).toBe(undefined);
|
||||
expect(actors.a.links["Endpoint"]).toBe("https://alice.contoso.com");
|
||||
expect(actors.a.links["Swagger"]).toBe("https://swagger.contoso.com");
|
||||
expect(actors.a.links["Tests"]).toBe("https://tests.contoso.com/?svc=alice@contoso.com");
|
||||
});
|
||||
|
||||
it('it should handle properties', function () {
|
||||
|
@ -446,7 +446,7 @@ export const drawActors = function (diagram, actors, actorKeys, verticalPos) {
|
||||
bounds.bumpVerticalPos(conf.height);
|
||||
};
|
||||
|
||||
export const drawActorsPopup = function(diagram, actors, actorKeys) {
|
||||
export const drawActorsPopup = function (diagram, actors, actorKeys) {
|
||||
var maxHeight = 0;
|
||||
var maxWidth = 0;
|
||||
for (let i = 0; i < actorKeys.length; i++) {
|
||||
@ -870,7 +870,7 @@ const getMaxMessageWidthPerActor = function (actors, messages) {
|
||||
return maxMessageWidthPerActor;
|
||||
};
|
||||
|
||||
const getRequiredPopupWidth = function(actor) {
|
||||
const getRequiredPopupWidth = function (actor) {
|
||||
let requiredPopupWidth = 0;
|
||||
const textFont = actorFont(conf);
|
||||
for (let key in actor.links) {
|
||||
@ -881,8 +881,8 @@ const getRequiredPopupWidth = function(actor) {
|
||||
}
|
||||
}
|
||||
|
||||
return requiredPopupWidth;
|
||||
}
|
||||
return requiredPopupWidth;
|
||||
};
|
||||
|
||||
/**
|
||||
* This will calculate the optimal margin for each given actor, for a given
|
||||
|
@ -95,6 +95,17 @@ const getStyles = (options) =>
|
||||
fill: ${options.activationBkgColor};
|
||||
stroke: ${options.activationBorderColor};
|
||||
}
|
||||
|
||||
.actorPopupMenu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.actorPopupMenuPanel {
|
||||
position: absolute;
|
||||
fill: ${options.actorBkg};
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
||||
|
File diff suppressed because one or more lines are too long
@ -94,14 +94,3 @@ text.actor > tspan {
|
||||
fill: $activationBkgColor;
|
||||
stroke: $activationBorderColor;
|
||||
}
|
||||
|
||||
.actorPopupMenu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.actorPopupMenuPanel {
|
||||
position: absolute;
|
||||
fill: $actorBkg;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user