Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e20fd47
chore: 在App.vue中添加注释标记
sohandsomejie Jan 24, 2026
d4397cc
feat(graph): add service graph visualization and related data structures
ambiguous-pointer Feb 8, 2026
13f7855
feat(service): enhance SearchServiceAsCrossLinkedList to merge duplic…
ambiguous-pointer Feb 10, 2026
c9e76b5
fix(license): restore license header in graph.go
ambiguous-pointer Feb 10, 2026
605e63e
Merge branch 'develop' into develop
ambiguous-pointer Feb 10, 2026
82474b6
Apply suggestion from @Copilot
ambiguous-pointer Feb 12, 2026
82e2512
rm: remove useless files (#1416)
robocanic Mar 1, 2026
7b1550d
feat(ui): 新增应用与服务拓扑图功能并引入图标字体
sohandsomejie Mar 8, 2026
a570632
Merge branch 'develop' of https://github.com/sohandsomejie/dubbo-admi…
sohandsomejie Mar 8, 2026
14a9f70
Merge branch 'apache:develop' into develop
sohandsomejie Mar 8, 2026
7820521
chore: 移除 App.vue 中遗留的注释标记
sohandsomejie Mar 8, 2026
9adece0
feat(service): add service detail and interfaces endpoints with reque…
ambiguous-pointer Mar 8, 2026
705adf1
Merge branch 'develop' of https://github.com/ambiguous-pointer/dubbo-…
ambiguous-pointer Mar 8, 2026
c91ca09
Potential fix for pull request finding
sohandsomejie Mar 15, 2026
4906c48
feat:Update the list interface and detail interface
sohandsomejie Mar 15, 2026
6d6a353
Merge pull request #1 from ambiguous-pointer/develop
sohandsomejie Mar 15, 2026
3295434
feat:update baseURL
sohandsomejie Mar 15, 2026
2d44a99
refactor(api): Unify interface naming and adjust service topology par…
sohandsomejie Mar 15, 2026
4d17607
refactor(router): Temporarily comment out the application topology ro…
sohandsomejie Mar 15, 2026
ec894a1
refactor(api): Optimize service and application details interface par…
sohandsomejie Mar 15, 2026
6fb340d
feat(service topology): Support application details display and enhan…
sohandsomejie Mar 22, 2026
1efdb31
refactor(ui): Optimize the topology detail display logic and remove d…
sohandsomejie Mar 26, 2026
07d3027
feat(application graph): Add endpoint and model for application graph…
ambiguous-pointer Mar 29, 2026
8ee5b0d
feat: enhance service management with detailed service graph and deta…
mochengqian Mar 29, 2026
862778a
Merge remote-tracking branch 'origin-yj/topology-chengqian' into feat…
ambiguous-pointer Mar 29, 2026
d66cf0a
feat(service): refactor service detail and graph retrieval functions;…
ambiguous-pointer Mar 29, 2026
cdfef00
feat(graph): enhance application graph generation by initializing sel…
ambiguous-pointer Mar 30, 2026
4eee43b
refactor(service): remove providerAppName from service pages and use …
mochengqian Apr 1, 2026
89d38ca
fix(service): infer language when provider metadata omits it
mochengqian Apr 4, 2026
6d6f5ce
chore(test): remove language inference unit test
mochengqian Apr 4, 2026
5ed12b5
feat(router): Enable application domain topology view routing
sohandsomejie Apr 4, 2026
76c9443
Merge branch 'feat/topology' of https://github.com/sohandsomejie/dubb…
sohandsomejie Apr 4, 2026
4f0b9f6
refactor(topology): Remove the blacklist filtering logic for detailed…
sohandsomejie Apr 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 26 additions & 54 deletions api/mesh/v1alpha1/service.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 11 additions & 15 deletions api/mesh/v1alpha1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,19 @@ option go_package = "github.com/apache/dubbo-admin/api/mesh/v1alpha1";
import "api/mesh/options.proto";


message Service{
option (dubbo.mesh.resource).name = "Service";
option (dubbo.mesh.resource).plural_name = "Services";
option (dubbo.mesh.resource).package = "mesh";
option (dubbo.mesh.resource).is_experimental = true;
message Service{
option (dubbo.mesh.resource).name = "Service";
option (dubbo.mesh.resource).plural_name = "Services";
option (dubbo.mesh.resource).package = "mesh";
option (dubbo.mesh.resource).is_experimental = true;

string name = 1;

string group = 2;

string version = 3;

string language = 4;

repeated string providers = 5;

repeated string consumers = 6;

map<string, string> features = 99;
}
string version = 3;

string language = 4;

repeated string methods = 5;
}
17 changes: 17 additions & 0 deletions pkg/console/handler/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ func ApplicationSearch(ctx consolectx.Context) gin.HandlerFunc {
}
}

func GetApplicationGraph(ctx consolectx.Context) gin.HandlerFunc {
return func(c *gin.Context) {
req := model.NewApplicationGraphReq()
if err := c.ShouldBindQuery(req); err != nil {
util.HandleArgumentError(c, err)
return
}

resp, err := service.GraphApplications(ctx, req)
if err != nil {
util.HandleServiceError(c, err)
return
}
c.JSON(http.StatusOK, model.NewSuccessResp(resp))
}
}

func ApplicationConfigAccessLogPut(ctx consolectx.Context) gin.HandlerFunc {
return func(c *gin.Context) {
appName := c.Query("appName")
Expand Down
58 changes: 58 additions & 0 deletions pkg/console/handler/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,61 @@ func ServiceConfigArgumentRoutePUT(ctx consolectx.Context) gin.HandlerFunc {
c.JSON(http.StatusOK, model.NewSuccessResp(nil))
}
}

// GetServiceGraph returns the service graph as graph data (nodes and edges) for visualization
func GetServiceGraph(ctx consolectx.Context) gin.HandlerFunc {
return func(c *gin.Context) {
req := &model.ServiceGraphReq{}
if err := c.ShouldBindQuery(req); err != nil {
c.JSON(http.StatusBadRequest, model.NewErrorResp(err.Error()))
return
}

resp, err := service.GraphServices(ctx, req)
if err != nil {
util.HandleServiceError(c, err)
return
}

c.JSON(http.StatusOK, model.NewSuccessResp(resp))
}
}

// GetServiceDetail returns service detail information
func GetServiceDetail(ctx consolectx.Context) gin.HandlerFunc {
return func(c *gin.Context) {
req := &model.ServiceDetailReq{}
if err := c.ShouldBindQuery(req); err != nil {
c.JSON(http.StatusBadRequest, model.NewErrorResp(err.Error()))
return
}

resp, err := service.GetServiceDetail(ctx, req)
if err != nil {
util.HandleServiceError(c, err)
return
}

c.JSON(http.StatusOK, model.NewSuccessResp(resp))
}
}

// GetServiceInterfaces returns service interfaces information
func GetServiceInterfaces(ctx consolectx.Context) gin.HandlerFunc {
// return func(c *gin.Context) {
// req := &model.ServiceInterfacesReq{}
// if err := c.ShouldBindQuery(req); err != nil {
// c.JSON(http.StatusBadRequest, model.NewErrorResp(err.Error()))
// return
// }

// resp, err := service.GetServiceInterfaces(ctx, req)
// if err != nil {
// util.HandleServiceError(c, err)
// return
// }

// c.JSON(http.StatusOK, model.NewSuccessResp(resp))
// }
return nil
}
17 changes: 17 additions & 0 deletions pkg/console/model/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,23 @@ func NewApplicationSearchReq() *ApplicationSearchReq {
}
}

type ApplicationGraphReq struct {
coremodel.PageReq

AppName string `form:"appName" json:"appName"`
Keywords string `form:"keywords" json:"keywords"`
Mesh string `form:"mesh" json:"mesh"`
}

func NewApplicationGraphReq() *ApplicationGraphReq {
return &ApplicationGraphReq{
PageReq: coremodel.PageReq{
PageOffset: 0,
PageSize: 15,
},
}
}

type ApplicationSearchResp struct {
AppName string `json:"appName"`
DeployClusters []string `json:"deployClusters"`
Expand Down
73 changes: 73 additions & 0 deletions pkg/console/model/graph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package model

import (
meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"

"github.com/apache/dubbo-admin/pkg/common/constants"
)

// GraphNode represents a node in the graph for AntV G6
type GraphNode struct {
ID string `json:"id"`
Label string `json:"label"`
Type string `json:"type"` // "application" or "service"
Rule string `json:"rule"` // "provider", "consumer", or ""
Data interface{} `json:"data,omitempty"`
}

// GraphEdge represents an edge in the graph for AntV G6
type GraphEdge struct {
Source string `json:"source"`
Target string `json:"target"`
Data map[string]interface{} `json:"data,omitempty"` // Additional data for the edge
}

// GraphData represents the complete graph structure for AntV G6
type GraphData struct {
Nodes []GraphNode `json:"nodes"`
Edges []GraphEdge `json:"edges"`
}

// CrossNode represents a node in the cross-linked list structure
type CrossNode struct {
Instance *meshresource.InstanceResource
Next *CrossNode // pointer to next node in the same row
Down *CrossNode // pointer to next node in the same column
}

// CrossLinkedListGraph represents the cross-linked list structure as a directed graph
type CrossLinkedListGraph struct {
Head *CrossNode
Rows int // number of rows
Cols int // number of columns
}

// ServiceGraphReq represents the request parameters for fetching the service graph
type ServiceGraphReq struct {
Mesh string `json:"mesh" form:"mesh" binding:"required"`
ServiceName string `json:"serviceName" form:"serviceName" binding:"required"`
Version string `json:"version" form:"version"`
Group string `json:"group" form:"group"`
}

// ServiceKey returns the unique service identifier
func (s *ServiceGraphReq) ServiceKey() string {
return s.ServiceName + constants.ColonSeparator + s.Version + constants.ColonSeparator + s.Group
}
9 changes: 4 additions & 5 deletions pkg/console/model/observability.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ type InstanceDashboardReq struct {
}

type ServiceDashboardReq struct {
ServiceName string `form:"serviceName"`
Version string `form:"version"`
Group string `form:"group"`
ProviderAppName string `form:"providerAppName"`
Mesh string `form:"mesh"`
ServiceName string `form:"serviceName"`
Version string `form:"version"`
Group string `form:"group"`
Mesh string `form:"mesh"`
}

type DashboardResp struct {
Expand Down
Loading