Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Use Case diagram type #4628

Open
karollewandowski opened this issue Jul 11, 2023 · 69 comments · May be fixed by #6141
Open

Add Use Case diagram type #4628

karollewandowski opened this issue Jul 11, 2023 · 69 comments · May be fixed by #6141
Labels

Comments

@karollewandowski
Copy link

karollewandowski commented Jul 11, 2023

Please do not +1 via comments. Click 👍 under this post.

Proposal

There is a lack of UML Use Case diagrams (or I failed to find it):
https://www.lucidchart.com/pages/uml-use-case-diagram

Use Cases

In the Unified Modeling Language (UML), a use case diagram can summarize the details of your system's users (also known as actors) and their interactions with the system

Screenshots

image
Source: https://www.lucidchart.com/pages/uml-use-case-diagram

Syntax

I have no knowledge of Mermaid conventions, but PlantUML can be a good inspiration:
https://plantuml.com/use-case-diagram

Implementation

This is a proposal which I'd love to see built into mermaid by the wonderful community.

@karollewandowski karollewandowski added Status: Triage Needs to be verified, categorized, etc Type: Enhancement New feature or request Type: New Diagram labels Jul 11, 2023
@fidding
Copy link

fidding commented Aug 29, 2023

This is very important, even making me want to give up mermaid

@paul-friedli
Copy link

paul-friedli commented Sep 1, 2023

I totally agree with the above comments : the "Use Case" diagram is probably one of the most important of all UML diagrams !

The "Use Case" diagram is usually the first to show in a projet, as it clearly presents the whole app/solution functionalities visually, without delving into technical details (as they are usually not known at this analysis stage).

Actors, resources, ... are all there on a single diagram focusing on "who" and "what" and not on "how".

Mermaid developers : that diagram availability would really be wonderful and super useful, since the whole project UML documentation could be done with mermaid.

@Yokozuna59 Yokozuna59 added Contributor needed Status: Approved Is ready to be worked on and removed Status: Triage Needs to be verified, categorized, etc labels Sep 1, 2023
@Angelles
Copy link

Angelles commented Sep 4, 2023

I would also love to have the use case diagram type.

@simone-boa-ideas
Copy link

I'll add my voice to the growing chorus 😉
I would love to have this option too. It's one of the most important diagrams for the documentation since it's perfect for aligning separate teams with different backgrounds on the features of a project.
At the moment I'm forced to implement it separately (with draw.io, exporting it as an image and importing it in GH), but this is not a scalable and maintainable solution. It would be much better if it had its own support in mermaid.

@kurt-o-sys
Copy link

yes please!

@luhui
Copy link

luhui commented Oct 16, 2023

+1. Using flowcharts to simulate the effect of use cases for now

@ronnykwon
Copy link

+1 for this feature

@Flecart
Copy link

Flecart commented Oct 25, 2023

+1

11 similar comments
@7agustibm
Copy link

+1

@lefkisamuel
Copy link

+1

@ramalhom
Copy link

ramalhom commented Nov 2, 2023

+1

@haizenburg
Copy link

+1

@buudi
Copy link

buudi commented Nov 9, 2023

+1

@smusali
Copy link

smusali commented Nov 11, 2023

+1

@tienminhvy
Copy link

+1

@MiboraMinima
Copy link

+1

@kenchopa
Copy link

+1

@CamiloSinningUN
Copy link

+1

@osbyrne
Copy link

osbyrne commented Dec 4, 2023

+1

@kkrafft1999
Copy link

+100
In our software development process everything starts with a use case diagram.

@iacobucci
Copy link

+1

3 similar comments
@dholakashyap
Copy link

+1

@haibbo
Copy link

haibbo commented Dec 13, 2023

+1

@mstfkhazaal
Copy link

+1

@YB-A
Copy link

YB-A commented Feb 21, 2024

Hello @karollewandowski @simone-boa-ideas @fidding @paul-friedli you can use flow chart; try and adapt this :)
Bonus => you can add emoji

flowchart LR
    subgraph 'Online Shopping'
    uc1((View items))
    uc2((Make purchase))
    uc3((Complete Checkout))
    uc4((Log In))

    end
    customer[Customer👤]
    credit[credit_payment_service 💳]
    id[identity_provider🆔]
    sa[service_authentification🔑]
    pa[paypal💲]
    id--->uc1
    sa--->uc1

    customer----->uc1
    customer-->uc2
    uc2 -. include .-> uc1
    uc2 -. include .-> uc3
    credit---->uc3
    pa---->uc3
    customer--->uc4

mermaid_uc

yas in

@tom-craven
Copy link

+1

2 similar comments
@enriquesaou
Copy link

+1

@Azevedo-Erick
Copy link

+1

@hgsgtk
Copy link

hgsgtk commented Apr 17, 2024

+1

1 similar comment
@sylvia-shen
Copy link

+1

@Nguyen-Xuan-Tien-2001
Copy link

+10

@Emk0oo
Copy link

Emk0oo commented Jun 17, 2024

+1

@simasch
Copy link

simasch commented Jun 27, 2024

Any plans to support use case diagrams?

@richardfwashington
Copy link

We could do with this too. Loving Mermaid but this does feel like it is missing.

@phuongdnguyen
Copy link

+1

2 similar comments
@aviv-vladimirsedlar
Copy link

+1

@acodercat
Copy link

+1

@lux10n
Copy link

lux10n commented Aug 10, 2024

+1. It's a really useful, if not one of the most useful UML diagrams...so it should be a no brainer

I didnt read quite well, sorry about that :)

@insinfo
Copy link

insinfo commented Sep 5, 2024

it would be very important to have this feature, I'm currently trying to do this with jointjs

const { shapes: defaultShapes, dia, util, linkTools } = joint;

const paperContainer = document.getElementById("paper-container");

const COLORS = [
  "#3f84e5", // Azul
  "#49306B", // Roxo
  "#fe7f2d", // Laranja
  "#ad343e", // Vermelho
  "#899e8b", // Verde
  "#ede9e9", // Cinza Claro
  "#b2a29f", // Bege
  "#392F2D"  // Marrom
];

const shapes = { ...defaultShapes };
const graph = new dia.Graph({}, { cellNamespace: shapes });
const paper = new dia.Paper({
  el: document.getElementById("paper"),
  width: "100%",
  height: "100%",
  model: graph,
  async: true,
  multiLinks: false,
  linkPinning: false,
  cellViewNamespace: shapes,
  sorting: dia.Paper.sorting.APPROX,
  defaultConnectionPoint: {
    name: "boundary",
    args: {
      offset: 5
    }
  },
  defaultConnector: {
    name: "jumpover"
  },
  background: {
    color: "#f6f4f4"
  },
  highlighting: {
    connecting: {
      name: "mask",
      options: {
        attrs: {
          stroke: "#0A100D",
          "stroke-width": 3
        }
      }
    }
  },
  restrictTranslate: function (elementView) {
    const parent = elementView.model.getParentCell();
    if (parent) {
      return parent.getBBox().inflate(-6);
    }
    return null;
  },
  validateConnection: function (cellViewS, _, cellViewT) {
    if (cellViewT.model instanceof UseCase) return true;
    return false;
  }
});

paperContainer.appendChild(paper.el);

class Boundary extends dia.Element {
  defaults() {
    return {
      ...super.defaults,
      type: "Boundary",
      attrs: {
        body: {
          width: "calc(w)",
          height: "calc(h)",
          fill: COLORS[5],
          stroke: COLORS[6],
          strokeWidth: 1,
          rx: 20,
          ry: 20
        },
        label: {
          y: 10,
          x: "calc(w / 2)",
          textAnchor: "middle",
          textVerticalAnchor: "top",
          fontSize: 18,
          fontFamily: "sans-serif",
          fontWeight: "bold",
          fill: COLORS[7]
        },
      }
    };
  }

  preinitialize(...args) {
    super.preinitialize(...args);
    this.markup = util.svg`
      <rect @selector="body" />
      <text @selector="label" />
      <image @selector="logo" />
    `;
  }
}

class Actor extends dia.Element {
  defaults() {
    return {
      ...super.defaults,
      type: "Actor",
      attrs: {
        background: {
          width: "calc(w)",
          height: "calc(h)",
          fill: "transparent"
        },
        body: {
          d: `M 0 calc(0.4 * h) h calc(w) M 0 calc(h) calc(0.5 * w) calc(0.7 * h) calc(w) calc(h) M calc(0.5 * w) calc(0.7 * h) V calc(0.3 * h)`,
          fill: "none",
          stroke: COLORS[7],
          strokeWidth: 2
        },
        head: {
          cx: "calc(0.5 * w)",
          cy: `calc(0.15 * h)`,
          r: `calc(0.15 * h)`,
          stroke: COLORS[7],
          strokeWidth: 2,
          fill: "#ffffff"
        },
        label: {
          y: "calc(h + 10)",
          x: "calc(0.5 * w)",
          textAnchor: "middle",
          textVerticalAnchor: "top",
          fontSize: 14,
          fontFamily: "sans-serif",
          fill: COLORS[7],
          textWrap: {
            width: "calc(3 * w)",
            height: null
          }
        }
      }
    };
  }

  preinitialize(...args) {
    super.preinitialize(...args);
    this.markup = util.svg`
      <rect @selector="background" />
      <path @selector="body" />
      <circle @selector="head" />
      <text @selector="label" />
    `;
  }
}

class UseCase extends dia.Element {
  defaults() {
    return {
      ...super.defaults,
      type: "UseCase",
      attrs: {
        root: {
          highlighterSelector: "body"
        },
        body: {
          cx: "calc(0.5 * w)",
          cy: "calc(0.5 * h)",
          rx: "calc(0.5 * w)",
          ry: "calc(0.5 * h)",
          stroke: COLORS[7],
          strokeWidth: 2
        },
        label: {
          x: "calc(0.5 * w)",
          y: "calc(0.5 * h)",
          textVerticalAnchor: "middle",
          textAnchor: "middle",
          fontSize: 14,
          fontFamily: "sans-serif",
          fill: "#ffffff",
          textWrap: {
            width: "calc(w - 30)",
            height: "calc(h - 10)",
            ellipsis: true
          }
        }
      }
    };
  }

  preinitialize(...args) {
    super.preinitialize(...args);
    this.markup = util.svg`
      <ellipse @selector="body" />
      <text @selector="label" />
    `;
  }
}

class Use extends shapes.standard.Link {
  defaults() {
    return util.defaultsDeep(
      {
        type: "Use",
        attrs: {
          line: {
            stroke: COLORS[7],
            strokeWidth: 2,
            targetMarker: null
          }
        }
      },
      super.defaults
    );
  }
}

class Include extends shapes.standard.Link {
  defaults() {
    return util.defaultsDeep(
      {
        type: "Include",
        attrs: {
          line: {
            stroke: COLORS[7],
            strokeDasharray: "6,2",
            strokeWidth: 2,
            targetMarker: {
              type: "path",
              fill: "none",
              stroke: COLORS[7],
              "stroke-width": 2,
              d: "M 10 -5 0 0 10 5"
            }
          }
        },
        labels: [
          {
            position: 0.5,
            attrs: {
              labelText: {
                text: "<<include>>",
                fill: COLORS[7],
                fontSize: 12
              }
            }
          }
        ]
      },
      super.defaults
    );
  }
}

class Extend extends shapes.standard.Link {
  defaults() {
    return util.defaultsDeep(
      {
        type: "Extend",
        attrs: {
          line: {
            stroke: COLORS[7],
            strokeDasharray: "6,2",
            strokeWidth: 2,
            targetMarker: {
              type: "path",
              fill: "none",
              stroke: COLORS[7],
              "stroke-width": 2,
              d: "M 10 -5 0 0 10 5"
            }
          }
        },
        labels: [
          {
            position: 0.5,
            attrs: {
              labelText: {
                text: "<<extend>>",
                fill: COLORS[7],
                fontSize: 12
              }
            }
          }
        ]
      },
      super.defaults
    );
  }
}


// Criando Boundary (Sistema Bancário)
const boundary = new Boundary({
  size: { width: 800, height: 1000 },
  position: { x: 200, y: 100 },
  attrs: { label: { text: "Sistema Bancário" } }
});

// Criando Atores
const cliente = new Actor({
  position: { x: 50, y: 150 },
  size: { width: 40, height: 80 },
  attrs: { label: { text: "Cliente" } }
});
const funcionario = new Actor({
  position: { x: 50, y: 400 },
  size: { width: 40, height: 80 },
  attrs: { label: { text: "Funcionário" } }
});
const caixaEletronico = new Actor({
  position: { x: 50, y: 650 },
  size: { width: 40, height: 80 },
  attrs: { label: { text: "Caixa Eletrônico" } }
});

// Cor para os casos de uso
const useCaseColor = { body: { fill: "lightblue", stroke: "blue" } };

// Criando Casos de Uso
const abrirConta = new UseCase({ 
  position: { x: 300, y: 150 }, 
  size: { width: 125, height: 75 }, 
  attrs: { label: { text: "Abrir Conta" }, ...useCaseColor } 
});
const encerrarConta = new UseCase({ 
  position: { x: 500, y: 150 }, 
  size: { width: 125, height: 75 }, 
  attrs: { label: { text: "Encerrar Conta" }, ...useCaseColor } 
});
const sacar = new UseCase({ 
  position: { x: 300, y: 300 }, 
  size: { width: 125, height: 75 }, 
  attrs: { label: { text: "Sacar" }, ...useCaseColor } 
});
const depositar = new UseCase({ 
  position: { x: 500, y: 300 }, 
  size: { width: 125, height: 75 }, 
  attrs: { label: { text: "Depositar" }, ...useCaseColor } 
});
const consultarSaldo = new UseCase({ 
  position: { x: 400, y: 450 }, 
  size: { width: 125, height: 75 }, 
  attrs: { label: { text: "Consultar Saldo" }, ...useCaseColor } 
});

// Adicionando elementos ao gráfico
graph.addCell([boundary, cliente, funcionario, caixaEletronico, abrirConta, encerrarConta, sacar, depositar, consultarSaldo]);

// Criando Conexões
new Use({ source: { id: cliente.id }, target: { id: abrirConta.id } }).addTo(graph);
new Use({ source: { id: cliente.id }, target: { id: sacar.id } }).addTo(graph);
new Use({ source: { id: cliente.id }, target: { id: depositar.id } }).addTo(graph);
new Use({ source: { id: cliente.id }, target: { id: consultarSaldo.id } }).addTo(graph);

new Use({ source: { id: funcionario.id }, target: { id: abrirConta.id } }).addTo(graph);
new Use({ source: { id: funcionario.id }, target: { id: encerrarConta.id } }).addTo(graph);

new Use({ source: { id: caixaEletronico.id }, target: { id: sacar.id } }).addTo(graph);
new Use({ source: { id: caixaEletronico.id }, target: { id: depositar.id } }).addTo(graph);
new Use({ source: { id: caixaEletronico.id }, target: { id: consultarSaldo.id } }).addTo(graph);

// Relação <<include>> entre Consultar Saldo e outros casos de uso
new Include({ source: { id: sacar.id }, target: { id: consultarSaldo.id } }).addTo(graph);
new Include({ source: { id: depositar.id }, target: { id: consultarSaldo.id } }).addTo(graph);

// Relação <<extend>> entre Encerrar Conta e Sacar
new Extend({ source: { id: encerrarConta.id }, target: { id: sacar.id } }).addTo(graph);

// Ajustando cores ao conectar elementos
function fillUseCaseColors() {
  const colorMap = {};
  graph.getLinks().forEach(link => {
    const targetId = link.getTargetElement().id;
    const sourceId = link.getSourceElement().id;
    colorMap[targetId] = COLORS[graph.getCells().indexOf(graph.getCell(sourceId)) % COLORS.length];
  });

  graph.getElements().forEach(element => {
    if (element instanceof UseCase && colorMap[element.id]) {
      element.attr("body/stroke", colorMap[element.id]);
    }
  });
}

graph.on("change:target", fillUseCaseColors);
graph.on("remove", fillUseCaseColors);
fillUseCaseColors();

I tried like this but it didn't turn out well

graph TD
    Cliente((Cliente))
    Funcionario((Funcionário))
    CaixaEletronico((Caixa Eletrônico))

    subgraph Sistema Bancário
        AbrirConta[Abrir Conta]
        EncerrarConta[Encerrar Conta]
        Depositar[Depositar]
        Sacar[Sacar]
        EmitirSaldo[Emitir Saldo]
        EmitirExtrato[Emitir Extrato]
        RegistrarMovimentacao[Registrar Movimentação]
        AbrirContaEspecial[Abrir Conta Especial]
        AbrirContaPoupanca[Abrir Conta Poupança]
        VerificarSaldoZerado[Verificar Saldo Zerado]
    end

    Cliente --> AbrirConta
    Cliente --> EncerrarConta
    Cliente --> Depositar
    Cliente --> Sacar
    Cliente --> EmitirSaldo
    Cliente --> EmitirExtrato

    Funcionario --> AbrirConta
    Funcionario --> EncerrarConta

    CaixaEletronico --> Depositar
    CaixaEletronico --> Sacar
    CaixaEletronico --> EmitirSaldo
    CaixaEletronico --> EmitirExtrato

    AbrirContaEspecial -.-> |<<extend>>| AbrirConta
    AbrirContaPoupanca -.-> |<<extend>>| AbrirConta
    EncerrarConta -.-> |<<include>>| VerificarSaldoZerado

    Depositar -.-> |<<include>>| RegistrarMovimentacao
    Sacar -.-> |<<include>>| RegistrarMovimentacao

@ChekeGT
Copy link

ChekeGT commented Sep 15, 2024

+1

@SalahAdDin
Copy link

Yes please!

@chrisdeso
Copy link

+1

3 similar comments
@lokmanzeddoun
Copy link

+1

@tausif-zaag
Copy link

+1

@minhdqdev
Copy link

+1

@ClementValot
Copy link

Ngl I'm monitoring the issue and it's getting quite annoying having almost only notifications about messages adding a "+1" and no contribution 🙂

iffn added a commit to iffn/MarchingCubeEditorForUnity that referenced this issue Nov 30, 2024
With PlantUML, since Mermaid currently does not support use case diagrams (...)
Issue is just a +1 spam:
mermaid-js/mermaid#4628
@teyc
Copy link

teyc commented Dec 19, 2024

I've got a stab at it here: #6141
There are still some work to be done

  • the sub items do not appear
  • the layout is still a little ugly
usecase-beta
  title Student Management System Use Cases

  actor Student
  actor Admin
  service Authentication
  service Grades
  service Courses

  systemboundary
    title Student Management System
    (Login) {
      - Authenticate
    }
    (Submit Assignment) {
      - Upload Assignment
    }
    (View Grades)
    (Manage Users) {
      - Add User
      - Edit User
      - Delete User
    }
    (Manage Courses) {
      - Add Course
      - Edit Course
      - Delete Course
    }
    (Generate Reports) {
      - Generate User Report
      - Generate Course Report
    }
    (View Grades) {
      - View User Grades
      - View Course Grades
    }
  end

  Student -> (Login) -> Authentication
  Student -> (Submit Assignment) -> Courses
  Student -> (View Grades) -> Grades
  Admin -> (Login) -> Authentication
  Admin -> (Manage Users) -> Courses
  Admin -> (Manage Courses) -> Courses
  Admin -> (Generate Reports) -> Courses, Grades
  Admin -> (View Grades) -> Grades
image

@jppascale
Copy link

Thanks @teyc !!! You're a genius!
Will you add use case relations?
Ex: c1 --- includes ---> c2, c1 --- extends ---> c3, etc

@teyc teyc linked a pull request Dec 19, 2024 that will close this issue
4 tasks
@teyc
Copy link

teyc commented Dec 20, 2024

Thanks @teyc !!! You're a genius! Will you add use case relations? Ex: c1 --- includes ---> c2, c1 --- extends ---> c3, etc

yes
image

@SalahAdDin
Copy link

I've got a stab at it here: #6141 There are still some work to be done

* the sub items do not appear

* the layout is still a little ugly
usecase-beta
  title Student Management System Use Cases

  actor Student
  actor Admin
  service Authentication
  service Grades
  service Courses

  systemboundary
    title Student Management System
    (Login) {
      - Authenticate
    }
    (Submit Assignment) {
      - Upload Assignment
    }
    (View Grades)
    (Manage Users) {
      - Add User
      - Edit User
      - Delete User
    }
    (Manage Courses) {
      - Add Course
      - Edit Course
      - Delete Course
    }
    (Generate Reports) {
      - Generate User Report
      - Generate Course Report
    }
    (View Grades) {
      - View User Grades
      - View Course Grades
    }
  end

  Student -> (Login) -> Authentication
  Student -> (Submit Assignment) -> Courses
  Student -> (View Grades) -> Grades
  Admin -> (Login) -> Authentication
  Admin -> (Manage Users) -> Courses
  Admin -> (Manage Courses) -> Courses
  Admin -> (Generate Reports) -> Courses, Grades
  Admin -> (View Grades) -> Grades
image

yeah, the layout indeed is ugly, hahaha

@teyc
Copy link

teyc commented Dec 29, 2024

I've got a stab at it here: #6141 There are still some work to be done

* the sub items do not appear

* the layout is still a little ugly
usecase-beta
  title Student Management System Use Cases

  actor Student
  actor Admin
  service Authentication
  service Grades
  service Courses

  systemboundary
    title Student Management System
    (Login) {
      - Authenticate
    }
    (Submit Assignment) {
      - Upload Assignment
    }
    (View Grades)
    (Manage Users) {
      - Add User
      - Edit User
      - Delete User
    }
    (Manage Courses) {
      - Add Course
      - Edit Course
      - Delete Course
    }
    (Generate Reports) {
      - Generate User Report
      - Generate Course Report
    }
    (View Grades) {
      - View User Grades
      - View Course Grades
    }
  end

  Student -> (Login) -> Authentication
  Student -> (Submit Assignment) -> Courses
  Student -> (View Grades) -> Grades
  Admin -> (Login) -> Authentication
  Admin -> (Manage Users) -> Courses
  Admin -> (Manage Courses) -> Courses
  Admin -> (Generate Reports) -> Courses, Grades
  Admin -> (View Grades) -> Grades
image

yeah, the layout indeed is ugly, hahaha

It's improving, latest iteration looks like

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.