Interactive Sequence diagram using mermaid.js producing parse errors in Observable Notebooks

I tried creating an interactive sequence diagram inspired by https://observablehq.com/@tomlarkworthy/animated-sequence-diagrams
`

The (required) diagram is as shown below:

However when I am trying to animate it(in the observable notebook) I am encountering parse errors.

mermaid`sequenceDiagram
    autonumber
    actor S as Student
    participant s as System
    participant ad as Admin(Librarian)
    participant b as Book database
    participant sdb as Student database
    ${includeIf(
      step > 0,
      `${includeIf(step === 1, `rect rgb(0,255,0)\n`)}
      S->>s: Login
      activate S
      activate s
      ${includeIf(step == 1, "\nend")}
      ${includeIf(
        step > 1,
        `${includeIf(step === 2, `rect rgb(0, 255, 0)\n`)}
            s->>sdb: Authenticate with login details
                        activate sdb
        ${includeIf(step == 2, "\nend")}
        ${includeIf(
          step > 2,`alt authenticated user
          ${includeIf(step === 3, `rect rgb(0, 255, 0)\n`)}
            sdb-->>s: user authenticated
            ${includeIf(step == 3, "\nend")}
          ${includeIf(
            step > 3,
            `${includeIf(step === 4, `rect rgb(0, 255, 0)\n`)}
              s-->>S: Login successful
            ${includeIf(step == 4, "\nend")}
            ${includeIf(
              step > 4,`else else
              ${includeIf(step === 5, `rect rgb(0, 255, 0)\n`)}
                sdb-->>s: authentication failed
              ${includeIf(step == 5, "\nend")}
              ${includeIf(
                step > 5,
                `${includeIf(step === 6, `rect rgb(0, 255,0)\n`)}
                s->>sdb: does the user exist?
              ${includeIf(step == 6, "\nend")}
              ${includeIf(step > 6,
                  `alt user doesn't exist
                ${includeIf(step === 7, `rect rgb(0, 255,0)\n`)}
                sdb-->>s: user does not exist
              ${includeIf(step == 7, "\nend")}
              ${includeIf(step > 7,
                `${includeIf(step === 8, `rect rgb(0, 255,0)\n`)}
                s->>S: Register?
              ${includeIf(step == 8, "\nend")}
              ${includeIf(step > 8,
                  `else else
                ${includeIf(step === 9, `rect rgb(0, 255,0)\n`)}
                sdb-->>s: user already exists
                                deactivate sdb
              ${includeIf(step == 9, "\nend")}
              ${includeIf(step > 9,
                `${includeIf(step === 10, `rect rgb(0,255,0)\n`)}
                s->>S: invalid credentials
              ${includeIf(step == 10, "\nend")}
                        end
                        end`
                      )}`
                    )}`
                  )}`
                )}`
              )}`
            )}`
          )}`
        )}`
      )}`
    )}
`

After observing closely I find that there needs to be an end statement immediately after an alt statement…but if I do so I would not get the required diagram.

Start simple and just have 10 fully defined diagrams in a switch statement. The includeIf is just a hacky thing to reduce some repetition but it does not understand mermaid syntax so you have to balance your expressions manually. That’s hard to do unless you have a very firm grip on the diagram source you want as a goal.

I refactored my code after figuring out how I wanted the animation frames but I think you have jumped straight in at the optimized version.

1 Like

@pixel Can you share your notebook? I’d like to see if I can come up with a more maintainable authoring solution.

@mootari here’s the link to the notebook: Interactive Sequence Diagram : User Login(Library Management System) / Parvathi R / Observable

@pixel I’ve added a steppedMermaid helper to Tom’s notebook which lets you split your steps via %% step %% comments. Check the updated version of his notebook: Interactive Sequence Diagrams / Tom Larkworthy / Observable

1 Like

I just realized that your diagram contains nested blocks which also contain multiple steps. In this case I’d advise against trying to define the steps interpolated into the mermaid markup. Instead split your diagram into multiple blocks of text and recombine them according to the current step.

You’ll likely also want to add some helpers to wrap sections of your diagram. Here is a rough example to get you started:

{
  const wrap = (prefix, body) => `\n${prefix}\n${body}\nend\n`;
  const mark = body => wrap('rect rgb(0,255,0)', body);
  const blockAuth = body => wrap(`alt authenticated user`, body);
  const blockFail = body => wrap(`alt user doesn't exist`, body);

  const head = `
    sequenceDiagram
    autonumber
  
    actor S as Student
    participant s as System
    participant ad as Admin(Librarian)
    participant b as Book database
    participant sdb as Student database
  `;

  return mermaid`
  ${head}

  ${blockAuth(`
    s->>sdb: does the user exist?
    ${blockFail(`
      sdb-->>s: authentication failed
      ${mark(`s->>S: Register?`)}
    `)}
  `)}
  `;
}

Note that mermaid does not care about indentation.

1 Like

Thank you