robocanic commented on code in PR #1429:
URL: https://github.com/apache/dubbo-admin/pull/1429#discussion_r3000790725


##########
pkg/console/model/service.go:
##########
@@ -107,16 +110,136 @@ type BaseServiceReq struct {
 }
 
 func (s *BaseServiceReq) Query(c *gin.Context) error {
-       s.ServiceName = c.Query("serviceName")
-       if s.ServiceName == "" {
+       s.ServiceName = strings.TrimSpace(c.Query("serviceName"))
+       if strutil.IsBlank(s.ServiceName) {
                return fmt.Errorf("service name is empty")
        }
-       s.Group = c.Query("group")
-       s.Version = c.Query("version")
-       s.Mesh = c.Query("mesh")
+       s.Group = strings.TrimSpace(c.Query("group"))
+       s.Version = strings.TrimSpace(c.Query("version"))
+       s.Mesh = strings.TrimSpace(c.Query("mesh"))
        return nil
 }
 
 func (s *BaseServiceReq) ServiceKey() string {
        return s.ServiceName + constants.ColonSeparator + s.Version + 
constants.ColonSeparator + s.Group
 }
+
+type ServiceMethodsReq struct {

Review Comment:
   Suggestion: 这个结构体是不是和BaseServiceReq一样的?可以直接服用BaseServiceReq
   



##########
ui-vue3/src/views/resources/services/tabs/debug.vue:
##########
@@ -16,135 +16,698 @@
 -->
 <template>
   <div class="__container_services_tabs_debug">
-    <div class="tabs-title">方法列表</div>
-    <a-tabs v-model:activeKey="activeKey" tab-position="left" :tabBarStyle="{ 
width: '200px' }">
-      <a-tab-pane v-for="tabName in methodTabs" :key="tabName" 
:tab="`${tabName}`">
-        <a-descriptions :column="2" layout="vertical">
-          <a-descriptions-item label="接口">
-            <p class="description-item-content">
-              org.apache.dubbo.samples.UserService:getPermissions
-            </p>
-          </a-descriptions-item>
-          <a-descriptions-item label="指定生产者">
-            <a-select
-              v-model:value="versionAndGroup"
-              size="large"
-              :options="versionAndGroupOptions"
-              class="description-item-content"
-            ></a-select>
-          </a-descriptions-item>
-          <a-descriptions-item label="入参类型">
-            <a-tree block-node :tree-data="enterParamType" 
class="description-item-content" />
-          </a-descriptions-item>
-          <a-descriptions-item label="出参类型">
-            <a-tree block-node :tree-data="outputParamType" 
class="description-item-content" />
-          </a-descriptions-item>
-          <a-descriptions-item label="请求">
-            <monaco-editor editorId="requestEditor" width="90%" height="300px" 
/>
-          </a-descriptions-item>
-          <a-descriptions-item label="响应">
-            <monaco-editor editorId="responseEditor" width="90%" 
height="300px" />
-          </a-descriptions-item>
-        </a-descriptions>
-        <a-button type="primary">发送请求</a-button>
-      </a-tab-pane>
-    </a-tabs>
+    <a-card :bordered="false" :body-style="{ padding: '24px' }">
+      <div class="tabs-title">方法列表</div>
+      <a-spin :spinning="loadingMethods">
+        <a-empty
+          v-if="!loadingMethods && methodList.length === 0"
+          :description="emptyDescription"
+        />
+        <a-tabs
+          v-else
+          v-model:activeKey="activeKey"
+          tab-position="left"
+          class="debug-tabs"
+          @change="onTabChange"
+        >
+          <a-tab-pane
+            v-for="(method, index) in methodList"
+            :key="String(index)"
+            :tab="method.methodName"
+          >
+            <a-spin :spinning="loadingDetail">
+              <div class="tab-content">
+                <a-row :gutter="[24, 24]">
+                  <!-- Row 1: Parameter Types -->
+                  <a-col :span="12">
+                    <div class="section-title">入参类型:</div>
+                    <a-tree
+                      v-if="enterParamType.length > 0"
+                      block-node
+                      :tree-data="enterParamType"
+                      default-expand-all
+                    />
+                    <span v-else class="empty-hint">无入参</span>
+                  </a-col>
+                  <a-col :span="12">
+                    <div class="section-title">出参类型:</div>
+                    <a-tree
+                      v-if="outputParamType.length > 0"
+                      block-node
+                      :tree-data="outputParamType"
+                      default-expand-all
+                    />
+                    <span v-else class="empty-hint">无出参</span>
+                  </a-col>
+
+                  <!-- Row 2: Request & Response Editors -->
+                  <a-col :span="12">
+                    <div class="section-title">请求:</div>
+                    <div class="editor-wrapper">
+                      <monaco-editor
+                        v-model="requestValue"
+                        :editor-id="`requestEditor-${index}`"
+                        height="300px"
+                      />
+                      <div class="editor-tag">JSON</div>
+                    </div>
+                  </a-col>
+                  <a-col :span="12">
+                    <div class="section-title">响应:</div>
+                    <div class="editor-wrapper">
+                      <monaco-editor

Review Comment:
   Suggestion: 响应里面的rawResult 
json转义之后放到编辑器里面,elapasedMs可以放到编辑器外面提示用户耗时![Image](https://github.com/user-attachments/assets/a0ba1a97-275c-4bf7-82fd-183d43a7bd69)



##########
pkg/console/service/service.go:
##########
@@ -160,6 +162,456 @@ func ToServiceSearchRespByConsumer(res 
*meshresource.ServiceConsumerMetadataReso
        }
 }
 
+type serviceMethodCandidate struct {
+       detail    *model.ServiceMethodDetailResp
+       signature string
+       method    *meshproto.Method
+}
+
+type serviceProviderMetadataLookupReq struct {
+       ServiceName     string
+       Group           string
+       Version         string
+       Mesh            string
+       ProviderAppName string
+}
+
+type serviceMethodLookupReq struct {
+       Metadata   serviceProviderMetadataLookupReq
+       MethodName string
+       Signature  string
+}
+
+type serviceMethodResolveReq struct {
+       ServiceName string
+       MethodName  string
+       Signature   string
+}
+
+type resolvedServiceMethod struct {
+       metadataList []*meshresource.ServiceProviderMetadataResource
+       candidate    *serviceMethodCandidate
+}
+
+func newServiceProviderMetadataLookupReqFromServiceMethodsReq(req 
model.ServiceMethodsReq) serviceProviderMetadataLookupReq {
+       return serviceProviderMetadataLookupReq{
+               ServiceName: req.ServiceName,
+               Group:       req.Group,
+               Version:     req.Version,
+               Mesh:        req.Mesh,
+       }
+}
+
+func newServiceMethodLookupReqFromServiceMethodDetailReq(req 
model.ServiceMethodDetailReq) serviceMethodLookupReq {
+       return serviceMethodLookupReq{
+               Metadata:   
newServiceProviderMetadataLookupReqFromServiceMethodsReq(req.ServiceMethodsReq),
+               MethodName: req.MethodName,
+               Signature:  req.Signature,
+       }
+}
+
+func newServiceMethodLookupReqFromGenericInvokeReq(req 
model.ServiceGenericInvokeReq, providerAppName string) serviceMethodLookupReq {
+       return serviceMethodLookupReq{
+               Metadata: serviceProviderMetadataLookupReq{
+                       ServiceName:     req.ServiceName,
+                       Group:           req.Group,
+                       Version:         req.Version,
+                       Mesh:            req.Mesh,
+                       ProviderAppName: providerAppName,
+               },
+               MethodName: req.MethodName,
+               Signature:  req.Signature,
+       }
+}
+
+func GetServiceMethodNames(ctx consolectx.Context, req 
model.ServiceMethodsReq) ([]model.ServiceMethodSummaryResp, error) {
+       metadataList, err := listServiceProviderMetadata(ctx, 
newServiceProviderMetadataLookupReqFromServiceMethodsReq(req))
+       if err != nil {
+               return nil, err
+       }
+
+       return buildServiceMethodSummaries(metadataList), nil
+}
+
+func GetServiceMethodDetail(ctx consolectx.Context, req 
model.ServiceMethodDetailReq) (*model.ServiceMethodDetailResp, error) {
+       resolvedMethod, err := resolveServiceMethod(ctx, 
newServiceMethodLookupReqFromServiceMethodDetailReq(req))
+       if err != nil {
+               return nil, err
+       }
+
+       detail := cloneServiceMethodDetailResp(resolvedMethod.candidate.detail)
+       detail.Types = 
buildServiceMethodRelatedTypes(resolvedMethod.metadataList, 
resolvedMethod.candidate.method)
+       return detail, nil
+}
+
+func resolveServiceMethod(ctx consolectx.Context, req serviceMethodLookupReq) 
(*resolvedServiceMethod, error) {
+       metadataList, err := listServiceProviderMetadata(ctx, req.Metadata)
+       if err != nil {
+               return nil, err
+       }
+
+       candidate, err := 
resolveStructuredServiceMethodCandidate(buildServiceMethodCandidates(metadataList),
 serviceMethodResolveReq{
+               ServiceName: req.Metadata.ServiceName,
+               MethodName:  req.MethodName,
+               Signature:   req.Signature,
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       return &resolvedServiceMethod{
+               metadataList: metadataList,
+               candidate:    candidate,
+       }, nil
+}
+
+func shouldUseExactServiceProviderLookup(req serviceProviderMetadataLookupReq) 
bool {

Review Comment:
   Correction: 
这里ServiceName在前面就会被过滤掉不可能为空,另外,version和group为空字符串是有意义的,不应该作为过滤条件,所以listServiceProviderMetadata里面的if分支是多余的,直接用拼接好的ServiceKey来作为索引条件就行



##########
pkg/console/service/service.go:
##########
@@ -160,6 +162,456 @@ func ToServiceSearchRespByConsumer(res 
*meshresource.ServiceConsumerMetadataReso
        }
 }
 
+type serviceMethodCandidate struct {
+       detail    *model.ServiceMethodDetailResp
+       signature string
+       method    *meshproto.Method
+}
+
+type serviceProviderMetadataLookupReq struct {
+       ServiceName     string
+       Group           string
+       Version         string
+       Mesh            string
+       ProviderAppName string
+}
+
+type serviceMethodLookupReq struct {
+       Metadata   serviceProviderMetadataLookupReq
+       MethodName string
+       Signature  string
+}
+
+type serviceMethodResolveReq struct {
+       ServiceName string
+       MethodName  string
+       Signature   string
+}
+
+type resolvedServiceMethod struct {
+       metadataList []*meshresource.ServiceProviderMetadataResource
+       candidate    *serviceMethodCandidate
+}
+
+func newServiceProviderMetadataLookupReqFromServiceMethodsReq(req 
model.ServiceMethodsReq) serviceProviderMetadataLookupReq {

Review Comment:
   Suggestion: 方法名太长啦,可以用一个简短的方法名,附上注释,多写注释;其他方法也简短一些,写一写注释。



##########
pkg/console/service/service.go:
##########
@@ -160,6 +162,456 @@ func ToServiceSearchRespByConsumer(res 
*meshresource.ServiceConsumerMetadataReso
        }
 }
 
+type serviceMethodCandidate struct {
+       detail    *model.ServiceMethodDetailResp
+       signature string
+       method    *meshproto.Method
+}
+
+type serviceProviderMetadataLookupReq struct {
+       ServiceName     string
+       Group           string
+       Version         string
+       Mesh            string
+       ProviderAppName string
+}
+
+type serviceMethodLookupReq struct {
+       Metadata   serviceProviderMetadataLookupReq
+       MethodName string
+       Signature  string
+}
+
+type serviceMethodResolveReq struct {
+       ServiceName string
+       MethodName  string
+       Signature   string
+}
+
+type resolvedServiceMethod struct {
+       metadataList []*meshresource.ServiceProviderMetadataResource
+       candidate    *serviceMethodCandidate
+}
+
+func newServiceProviderMetadataLookupReqFromServiceMethodsReq(req 
model.ServiceMethodsReq) serviceProviderMetadataLookupReq {
+       return serviceProviderMetadataLookupReq{
+               ServiceName: req.ServiceName,
+               Group:       req.Group,
+               Version:     req.Version,
+               Mesh:        req.Mesh,
+       }
+}
+
+func newServiceMethodLookupReqFromServiceMethodDetailReq(req 
model.ServiceMethodDetailReq) serviceMethodLookupReq {
+       return serviceMethodLookupReq{
+               Metadata:   
newServiceProviderMetadataLookupReqFromServiceMethodsReq(req.ServiceMethodsReq),
+               MethodName: req.MethodName,
+               Signature:  req.Signature,
+       }
+}
+
+func newServiceMethodLookupReqFromGenericInvokeReq(req 
model.ServiceGenericInvokeReq, providerAppName string) serviceMethodLookupReq {
+       return serviceMethodLookupReq{
+               Metadata: serviceProviderMetadataLookupReq{
+                       ServiceName:     req.ServiceName,
+                       Group:           req.Group,
+                       Version:         req.Version,
+                       Mesh:            req.Mesh,
+                       ProviderAppName: providerAppName,
+               },
+               MethodName: req.MethodName,
+               Signature:  req.Signature,
+       }
+}
+
+func GetServiceMethodNames(ctx consolectx.Context, req 
model.ServiceMethodsReq) ([]model.ServiceMethodSummaryResp, error) {
+       metadataList, err := listServiceProviderMetadata(ctx, 
newServiceProviderMetadataLookupReqFromServiceMethodsReq(req))
+       if err != nil {
+               return nil, err
+       }
+
+       return buildServiceMethodSummaries(metadataList), nil
+}
+
+func GetServiceMethodDetail(ctx consolectx.Context, req 
model.ServiceMethodDetailReq) (*model.ServiceMethodDetailResp, error) {
+       resolvedMethod, err := resolveServiceMethod(ctx, 
newServiceMethodLookupReqFromServiceMethodDetailReq(req))
+       if err != nil {
+               return nil, err
+       }
+
+       detail := cloneServiceMethodDetailResp(resolvedMethod.candidate.detail)

Review Comment:
   Question: 这里为什么要做一次clone?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to