refactor(core): publish sync events to global event stream (#22347)
This commit is contained in:
parent
67aaecacac
commit
b22add292c
10 changed files with 597 additions and 409 deletions
|
|
@ -66,31 +66,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/global/sync-event": {
|
||||
"get": {
|
||||
"operationId": "global.sync-event.subscribe",
|
||||
"summary": "Subscribe to global sync events",
|
||||
"description": "Get global sync events",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Event stream",
|
||||
"content": {
|
||||
"text/event-stream": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SyncEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "js",
|
||||
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.global.sync-event.subscribe({\n ...\n})"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/global/config": {
|
||||
"get": {
|
||||
"operationId": "global.config.get",
|
||||
|
|
@ -9925,174 +9900,24 @@
|
|||
},
|
||||
"required": ["type", "properties"]
|
||||
},
|
||||
"Event": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.project.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.server.instance.disposed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.installation.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.installation.update-available"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.server.connected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.global.disposed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.file.edited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.file.watcher.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.lsp.client.diagnostics"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.lsp.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.permission.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.permission.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.error"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.rejected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.todo.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.idle"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.compacted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.prompt.append"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.command.execute"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.toast.show"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.session.select"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.tools.changed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.browser.open.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.command.executed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.vcs.branch.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.worktree.ready"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.worktree.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.exited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.ready"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.deleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GlobalEvent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"project": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace": {
|
||||
"type": "string"
|
||||
},
|
||||
"payload": {
|
||||
"$ref": "#/components/schemas/Event"
|
||||
}
|
||||
},
|
||||
"required": ["directory", "payload"]
|
||||
},
|
||||
"SyncEvent.message.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "message.updated.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10110,16 +9935,26 @@
|
|||
"required": ["sessionID", "info"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent.message.removed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "message.removed.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10138,16 +9973,26 @@
|
|||
"required": ["sessionID", "messageID"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent.message.part.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "message.part.updated.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10168,16 +10013,26 @@
|
|||
"required": ["sessionID", "part", "time"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent.message.part.removed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "message.part.removed.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10200,16 +10055,26 @@
|
|||
"required": ["sessionID", "messageID", "partID"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent.session.created": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "session.created.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10227,16 +10092,26 @@
|
|||
"required": ["sessionID", "info"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent.session.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "session.updated.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10479,16 +10354,26 @@
|
|||
"required": ["sessionID", "info"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent.session.deleted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "sync"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"const": "session.deleted.1"
|
||||
},
|
||||
"aggregate": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "number"
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string",
|
||||
"const": "sessionID"
|
||||
},
|
||||
|
|
@ -10506,16 +10391,185 @@
|
|||
"required": ["sessionID", "info"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregate", "data"]
|
||||
"required": ["type", "name", "id", "seq", "aggregateID", "data"]
|
||||
},
|
||||
"SyncEvent": {
|
||||
"GlobalEvent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"project": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace": {
|
||||
"type": "string"
|
||||
},
|
||||
"payload": {
|
||||
"$ref": "#/components/schemas/SyncEvent"
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.project.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.server.instance.disposed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.installation.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.installation.update-available"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.server.connected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.global.disposed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.file.edited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.file.watcher.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.lsp.client.diagnostics"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.lsp.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.permission.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.permission.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.error"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.rejected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.todo.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.idle"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.compacted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.prompt.append"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.command.execute"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.toast.show"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.session.select"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.tools.changed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.browser.open.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.command.executed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.vcs.branch.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.worktree.ready"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.worktree.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.exited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.ready"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.message.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.message.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.message.part.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.message.part.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.session.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.session.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SyncEvent.session.deleted"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["payload"]
|
||||
"required": ["directory", "payload"]
|
||||
},
|
||||
"LogLevel": {
|
||||
"description": "Log level",
|
||||
|
|
@ -12608,6 +12662,148 @@
|
|||
},
|
||||
"required": ["path", "added", "removed", "status"]
|
||||
},
|
||||
"Event": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.project.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.server.instance.disposed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.installation.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.installation.update-available"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.server.connected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.global.disposed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.file.edited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.file.watcher.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.lsp.client.diagnostics"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.lsp.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.permission.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.permission.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.error"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.question.rejected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.todo.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.idle"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.compacted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.prompt.append"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.command.execute"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.toast.show"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.session.select"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.tools.changed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.browser.open.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.command.executed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.vcs.branch.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.worktree.ready"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.worktree.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.exited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.pty.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.ready"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.workspace.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.message.part.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.session.deleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"MCPStatusConnected": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue