mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d36c66371f | |||
| b7bb409e96 | |||
| 517007c941 | |||
| 4c685a9ec6 | |||
| 1aca2099de | |||
| a93e5b4ff8 | |||
| 85d25bebe2 | |||
| 9fa43ccc00 | |||
| c2a11050dd | |||
| 080bfc3a44 | |||
| f6956ddeca | |||
| 9f56fa5e14 | |||
| ccc39b95de | |||
| 9a2782e54b | |||
| 22455e2301 | |||
| 8ed2c84b68 | |||
| ccd2a209e2 | |||
| baf8ed4830 | |||
| dedb586daf | |||
| 21cd823791 | |||
| c8ab65ef1b | |||
| f1c16fd992 | |||
| 52035341f6 | |||
| aa62d44717 | |||
| a072d1fc8d | |||
| 38a00570d0 | |||
| 43283b9da3 | |||
| ef82cdbed6 | |||
| 2bafe6f31f | |||
| 3eb4f98fd8 | |||
| bb5acad033 | |||
| b8308a446b | |||
| c86f99ce45 | |||
| 952c519e45 | |||
| 07d97fa0bf | |||
| b0defedf04 | |||
| edc2fccdeb | |||
| a75b8a3f13 | |||
| 5aab5f7913 | |||
| 9ab7989c8b | |||
| e3e11d740a | |||
| 4bae2edc49 | |||
| 4eaa47ca25 | |||
| e01f596525 | |||
| 912e8d0d04 | |||
| 570c80af91 | |||
| 7aa0ec0d67 | |||
| 2fea6cb622 | |||
| 2195ff900f | |||
| 836c7699b8 | |||
| 72ed6c814e | |||
| c33b070509 | |||
| de12d5686c | |||
| c55a8ac805 | |||
| df3626f3f0 | |||
| 28bef97faa | |||
| 9897b6e9dc | |||
| 9af6963901 | |||
| c2d3ebecda | |||
| ba543311fc | |||
| 87b8dda97b | |||
| e7facf5686 | |||
| 4dd57837c5 | |||
| d4ebc68e30 | |||
| 1f8e089e51 | |||
| ce6f463fe8 | |||
| a37fe1d794 | |||
| 818d1ec6bf | |||
| fc4a5f7e28 | |||
| 0e3568b584 | |||
| 3617e4fe29 | |||
| f2fddc1727 | |||
| 3b7204f1a6 | |||
| 6646bb1e56 | |||
| c27533f802 | |||
| 613a47c181 | |||
| 90138a142b | |||
| 4bf8db4898 | |||
| 4f887f7204 | |||
| 14e17ccf2c | |||
| 5975670b8c | |||
| dbc4bc3343 | |||
| ada7635703 | |||
| 943a77f718 | |||
| ef02c11efa | |||
| 8c166dae9b | |||
| b23da78c26 | |||
| 93ac7310e8 | |||
| 9376acc456 | |||
| b70a1f9a51 | |||
| ac90a134b4 | |||
| 96bd1cf9f6 | |||
| 960e37a81a | |||
| 044bd550c9 | |||
| 0a9a903d1b | |||
| 84d7606e12 | |||
| febb64b8bb | |||
| 932e433c46 | |||
| b7307cd36d | |||
| 7a0f3efd83 | |||
| 28af1f691c | |||
| 796bc7bc15 | |||
| 8f06073783 | |||
| 7d6251b191 | |||
| e13fff633e | |||
| d984be4b85 | |||
| 213bdbd9d5 | |||
| 6a59d27b84 | |||
| ad45ab2e82 | |||
| 8982a63283 | |||
| 1b1515a8bd | |||
| df50e13db0 | |||
| 89d91c14c9 | |||
| 3a57c609f7 | |||
| 2cd331ec50 | |||
| 3fa02ec65c | |||
| f33f1965b4 | |||
| a70ecea02b | |||
| 8e68eb35f3 | |||
| 2893331ff5 | |||
| 1a3d14cdd6 | |||
| dce9a7addb | |||
| f3e7487482 | |||
| 86c39237dc | |||
| b5ad739b93 | |||
| 0b7f0405d5 | |||
| 522489c9e9 | |||
| a9eb2a790f | |||
| a092ed1108 | |||
| 503515281d | |||
| 2326d4dfb5 | |||
| 2b874fe59f | |||
| 1aa3f2fb05 | |||
| ad6b64ca74 | |||
| d27a2b8cf3 | |||
| bcb68d552f | |||
| 3de87723ae | |||
| 535d70ac5a | |||
| bf2aefe2da | |||
| 540a31f237 | |||
| 0505045c81 | |||
| 1a18d79d94 |
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"Antd",
|
||||
"apinto",
|
||||
"Apipark",
|
||||
"logsettings",
|
||||
"resourcesettings"
|
||||
]
|
||||
}
|
||||
@@ -27,7 +27,7 @@ type imlAPIController struct {
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error) {
|
||||
info, err := i.serviceModule.Get(ctx, serviceId)
|
||||
_, err := i.serviceModule.Get(ctx, serviceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_
|
||||
plugins["ai_formatter"] = api.PluginSetting{
|
||||
Config: plugin_model.ConfigType{
|
||||
"model": input.AiModel.Id,
|
||||
"provider": fmt.Sprintf("%s@ai-provider", info.Provider.Id),
|
||||
"provider": fmt.Sprintf("%s@ai-provider", input.AiModel.Provider),
|
||||
"config": input.AiModel.Config,
|
||||
},
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_
|
||||
Retry: input.Retry,
|
||||
Plugins: plugins,
|
||||
},
|
||||
Upstream: info.Provider.Id,
|
||||
Upstream: input.AiModel.Provider,
|
||||
Disable: false,
|
||||
})
|
||||
|
||||
@@ -86,7 +86,7 @@ func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) (*ai_api_dto.API, error) {
|
||||
info, err := i.serviceModule.Get(ctx, serviceId)
|
||||
_, err := i.serviceModule.Get(ctx, serviceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -106,11 +106,11 @@ func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string
|
||||
proxy.Plugins["ai_formatter"] = api.PluginSetting{
|
||||
Config: plugin_model.ConfigType{
|
||||
"model": input.AiModel.Id,
|
||||
"provider": fmt.Sprintf("%s@ai-provider", info.Provider.Id),
|
||||
"provider": fmt.Sprintf("%s@ai-provider", input.AiModel.Provider),
|
||||
"config": input.AiModel.Config,
|
||||
},
|
||||
}
|
||||
upstream = &info.Provider.Id
|
||||
upstream = &input.AiModel.Provider
|
||||
}
|
||||
|
||||
if input.AiPrompt != nil {
|
||||
|
||||
@@ -45,8 +45,8 @@ func (p *imlCluster) Check(ctx *gin.Context, input *cluster_dto.CheckCluster) ([
|
||||
// return id, nil
|
||||
//}
|
||||
//
|
||||
//func (p *imlCluster) Search(ctx *gin.Context, keyword string) ([]*parition_dto.Item, error) {
|
||||
// return p.module.Search(ctx, keyword)
|
||||
//func (p *imlCluster) SearchByDriver(ctx *gin.Context, keyword string) ([]*parition_dto.Item, error) {
|
||||
// return p.module.SearchByDriver(ctx, keyword)
|
||||
//}
|
||||
//
|
||||
//func (p *imlCluster) Simple(ctx *gin.Context) ([]*parition_dto.Simple, error) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
log_dto "github.com/APIParkLab/APIPark/module/log/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ILogController interface {
|
||||
Save(ctx *gin.Context, driver string, input *log_dto.Save) error
|
||||
Get(ctx *gin.Context, driver string) (*log_dto.LogSource, error)
|
||||
}
|
||||
|
||||
func init() {
|
||||
logController := &imlLogController{}
|
||||
autowire.Auto[ILogController](func() reflect.Value {
|
||||
return reflect.ValueOf(logController)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/APIParkLab/APIPark/module/log"
|
||||
log_dto "github.com/APIParkLab/APIPark/module/log/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type imlLogController struct {
|
||||
module log.ILogModule `autowired:""`
|
||||
}
|
||||
|
||||
func (c *imlLogController) Save(ctx *gin.Context, driver string, input *log_dto.Save) error {
|
||||
return c.module.Save(ctx, driver, input)
|
||||
}
|
||||
|
||||
func (c *imlLogController) Get(ctx *gin.Context, driver string) (*log_dto.LogSource, error) {
|
||||
return c.module.Get(ctx, driver)
|
||||
}
|
||||
@@ -17,6 +17,70 @@ type imlMonitorStatisticController struct {
|
||||
module monitor.IMonitorStatisticModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error) {
|
||||
switch dataType {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.ApiStatistics(ctx, input)
|
||||
case monitor_dto.DataTypeProvider:
|
||||
return i.module.ProviderStatistics(ctx, input)
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
return i.module.SubscriberStatistics(ctx, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported data type: %s", dataType)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) InvokeTrend(ctx *gin.Context, dataType string, id string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
|
||||
switch dataType {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.APITrend(ctx, id, input)
|
||||
case monitor_dto.DataTypeProvider:
|
||||
return i.module.ProviderTrend(ctx, id, input)
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
return i.module.SubscriberTrend(ctx, id, input)
|
||||
default:
|
||||
return nil, "", fmt.Errorf("unsupported data type: %s", dataType)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) InvokeTrendInner(ctx *gin.Context, dataType string, typ string, api string, provider string, subscriber string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
|
||||
if dataType == monitor_dto.DataTypeApi && typ == monitor_dto.DataTypeSubscriber || dataType == monitor_dto.DataTypeSubscriber && typ == monitor_dto.DataTypeApi {
|
||||
return i.module.InvokeTrendWithSubscriberAndApi(ctx, api, subscriber, input)
|
||||
} else if dataType == monitor_dto.DataTypeApi && typ == monitor_dto.DataTypeProvider || dataType == monitor_dto.DataTypeProvider && typ == monitor_dto.DataTypeApi {
|
||||
return i.module.InvokeTrendWithProviderAndApi(ctx, provider, api, input)
|
||||
}
|
||||
return nil, "", fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) StatisticsInner(ctx *gin.Context, dataType string, typ string, id string, input *monitor_dto.StatisticInput) (interface{}, error) {
|
||||
switch dataType {
|
||||
case monitor_dto.DataTypeApi:
|
||||
switch typ {
|
||||
case monitor_dto.DataTypeProvider:
|
||||
return i.module.ProviderStatisticsOnApi(ctx, id, input)
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
return i.module.SubscriberStatisticsOnApi(ctx, id, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
case monitor_dto.DataTypeProvider:
|
||||
switch typ {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.ApiStatisticsOnProvider(ctx, id, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
switch typ {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.ApiStatisticsOnSubscriber(ctx, id, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported data type: %s", dataType)
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) OverviewMessageTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []float64, []float64, string, error) {
|
||||
trend, timeInterval, err := i.module.MessageTrend(ctx, input)
|
||||
if err != nil {
|
||||
|
||||
@@ -16,7 +16,12 @@ type IMonitorStatisticController interface {
|
||||
OverviewInvokeTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []int64, []int64, []int64, []int64, []float64, []float64, string, error)
|
||||
OverviewMessageTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []float64, []float64, string, error)
|
||||
|
||||
//Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error)
|
||||
Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error)
|
||||
|
||||
InvokeTrend(ctx *gin.Context, dataType string, id string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
|
||||
|
||||
InvokeTrendInner(ctx *gin.Context, dataType string, typ string, api string, provider string, subscriber string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
|
||||
StatisticsInner(ctx *gin.Context, dataType string, typ string, id string, input *monitor_dto.StatisticInput) (interface{}, error)
|
||||
}
|
||||
|
||||
type IMonitorConfigController interface {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
api_doc "github.com/APIParkLab/APIPark/module/api-doc"
|
||||
api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto"
|
||||
"github.com/APIParkLab/APIPark/module/router"
|
||||
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
)
|
||||
|
||||
var _ IRouterController = (*imlAPIController)(nil)
|
||||
@@ -15,6 +16,10 @@ type imlAPIController struct {
|
||||
module router.IRouterModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Simple(ctx *gin.Context, input *router_dto.InputSimpleAPI) ([]*router_dto.SimpleItem, error) {
|
||||
return i.module.SimpleAPIs(ctx, input)
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Detail(ctx *gin.Context, serviceId string, apiId string) (*router_dto.Detail, error) {
|
||||
return i.module.Detail(ctx, serviceId, apiId)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto"
|
||||
"reflect"
|
||||
|
||||
api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
@@ -24,6 +25,7 @@ type IRouterController interface {
|
||||
Delete(ctx *gin.Context, serviceId string, apiId string) error
|
||||
// Prefix 获取API前缀
|
||||
Prefix(ctx *gin.Context, serviceId string) (string, bool, error)
|
||||
Simple(ctx *gin.Context, input *router_dto.InputSimpleAPI) ([]*router_dto.SimpleItem, error)
|
||||
}
|
||||
|
||||
type IAPIDocController interface {
|
||||
|
||||
+120
-27
@@ -7,6 +7,16 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/eolinker/go-common/pm3"
|
||||
|
||||
"github.com/APIParkLab/APIPark/module/system"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
api_doc "github.com/APIParkLab/APIPark/module/api-doc"
|
||||
|
||||
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
|
||||
|
||||
"github.com/eolinker/eosc/log"
|
||||
|
||||
application_authorization "github.com/APIParkLab/APIPark/module/application-authorization"
|
||||
@@ -25,7 +35,6 @@ import (
|
||||
"github.com/APIParkLab/APIPark/module/service"
|
||||
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
|
||||
"github.com/APIParkLab/APIPark/module/upstream"
|
||||
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
|
||||
"github.com/eolinker/go-common/store"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
@@ -42,29 +51,102 @@ type imlServiceController struct {
|
||||
docModule service.IServiceDocModule `autowired:""`
|
||||
aiAPIModule ai_api.IAPIModule `autowired:""`
|
||||
routerModule router.IRouterModule `autowired:""`
|
||||
apiDocModule api_doc.IAPIDocModule `autowired:""`
|
||||
providerModule ai.IProviderModule `autowired:""`
|
||||
upstreamModule upstream.IUpstreamModule `autowired:""`
|
||||
settingModule system.ISettingModule `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
}
|
||||
|
||||
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
|
||||
return &upstream_dto.Upstream{
|
||||
Type: "http",
|
||||
Balance: "round-robin",
|
||||
Timeout: 300000,
|
||||
Retry: 0,
|
||||
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
|
||||
LimitPeerSecond: 0,
|
||||
ProxyHeaders: nil,
|
||||
Scheme: uri.Scheme(),
|
||||
PassHost: "node",
|
||||
Nodes: []*upstream_dto.NodeConfig{
|
||||
{
|
||||
Address: uri.Host(),
|
||||
Weight: 100,
|
||||
},
|
||||
},
|
||||
var (
|
||||
loader = openapi3.NewLoader()
|
||||
)
|
||||
|
||||
func (i *imlServiceController) swagger(ctx *gin.Context, id string) (*openapi3.T, error) {
|
||||
doc, err := i.apiDocModule.GetDoc(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmp, err := loader.LoadFromData([]byte(doc.Content))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := i.settingModule.Get(ctx)
|
||||
|
||||
tmp.AddServer(&openapi3.Server{
|
||||
URL: cfg.InvokeAddress,
|
||||
})
|
||||
return tmp, nil
|
||||
}
|
||||
|
||||
func (i *imlServiceController) ExportSwagger(ctx *gin.Context) {
|
||||
id, has := ctx.Params.Get("id")
|
||||
if !has {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: fmt.Sprintf("id is required"),
|
||||
})
|
||||
return
|
||||
}
|
||||
s, err := i.module.Get(ctx, id)
|
||||
if err != nil {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
tmp, err := i.swagger(ctx, id)
|
||||
if err != nil {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
data, _ := tmp.MarshalJSON()
|
||||
ctx.Status(200)
|
||||
// 设置响应头
|
||||
ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.json", strings.Replace(s.Name, " ", "_", -1)))
|
||||
ctx.Header("Content-Type", "application/octet-stream")
|
||||
ctx.Header("Content-Transfer-Encoding", "binary")
|
||||
ctx.Writer.Write(data)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *imlServiceController) Swagger(ctx *gin.Context) {
|
||||
id, has := ctx.Params.Get("id")
|
||||
if !has {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: fmt.Sprintf("id is required"),
|
||||
})
|
||||
return
|
||||
}
|
||||
tmp, err := i.swagger(ctx, id)
|
||||
if err != nil {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.JSON(200, tmp)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *imlServiceController) Simple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error) {
|
||||
return i.module.Simple(ctx)
|
||||
}
|
||||
|
||||
func (i *imlServiceController) MySimple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error) {
|
||||
return i.module.MySimple(ctx)
|
||||
}
|
||||
|
||||
func (i *imlServiceController) editAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error) {
|
||||
@@ -228,21 +310,12 @@ func (i *imlServiceController) SearchMyServices(ctx *gin.Context, teamId string,
|
||||
return i.module.SearchMyServices(ctx, teamId, keyword)
|
||||
}
|
||||
|
||||
//func (i *imlServiceController) Simple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
|
||||
// return i.module.Simple(ctx, keyword)
|
||||
//}
|
||||
//
|
||||
//func (i *imlServiceController) MySimple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
|
||||
// return i.module.MySimple(ctx, keyword)
|
||||
//}
|
||||
|
||||
func (i *imlServiceController) Get(ctx *gin.Context, id string) (*service_dto.Service, error) {
|
||||
now := time.Now()
|
||||
defer func() {
|
||||
log.Infof("get service %s cost %d ms", id, time.Since(now).Milliseconds())
|
||||
}()
|
||||
return i.module.Get(ctx, id)
|
||||
|
||||
}
|
||||
|
||||
func (i *imlServiceController) Search(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error) {
|
||||
@@ -336,3 +409,23 @@ func (i *imlAppController) GetApp(ctx *gin.Context, appId string) (*service_dto.
|
||||
func (i *imlAppController) DeleteApp(ctx *gin.Context, appId string) error {
|
||||
return i.module.DeleteApp(ctx, appId)
|
||||
}
|
||||
|
||||
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
|
||||
return &upstream_dto.Upstream{
|
||||
Type: "http",
|
||||
Balance: "round-robin",
|
||||
Timeout: 300000,
|
||||
Retry: 0,
|
||||
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
|
||||
LimitPeerSecond: 0,
|
||||
ProxyHeaders: nil,
|
||||
Scheme: uri.Scheme(),
|
||||
PassHost: "node",
|
||||
Nodes: []*upstream_dto.NodeConfig{
|
||||
{
|
||||
Address: uri.Host(),
|
||||
Weight: 100,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ type IServiceController interface {
|
||||
Delete(ctx *gin.Context, id string) error
|
||||
ServiceDoc(ctx *gin.Context, id string) (*service_dto.ServiceDoc, error)
|
||||
SaveServiceDoc(ctx *gin.Context, id string, input *service_dto.SaveServiceDoc) error
|
||||
Simple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error)
|
||||
MySimple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error)
|
||||
|
||||
//createAIService(ctx *gin.Context, teamID string, input *service_dto.CreateService) (*service_dto.Service, error)
|
||||
//editAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error)
|
||||
//DeleteAIService(ctx *gin.Context, id string) error
|
||||
//SearchMyAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
|
||||
//SearchAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
|
||||
Swagger(ctx *gin.Context)
|
||||
ExportSwagger(ctx *gin.Context)
|
||||
}
|
||||
|
||||
type IAppController interface {
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
package strategy
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/eolinker/go-common/utils"
|
||||
|
||||
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
|
||||
|
||||
"github.com/APIParkLab/APIPark/module/service"
|
||||
"github.com/APIParkLab/APIPark/module/strategy"
|
||||
strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var _ IStrategyController = (*imlStrategyController)(nil)
|
||||
|
||||
type imlStrategyController struct {
|
||||
strategyModule strategy.IStrategyModule `autowired:""`
|
||||
serviceModule service.IServiceModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) Restore(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Restore(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) DeleteServiceStrategy(ctx *gin.Context, serviceId string, id string) error {
|
||||
return i.strategyModule.DeleteServiceStrategy(ctx, serviceId, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) ToPublish(ctx *gin.Context, driver string) ([]*strategy_dto.ToPublishItem, string, string, bool, error) {
|
||||
list, err := i.strategyModule.ToPublish(ctx, driver)
|
||||
if err != nil {
|
||||
return nil, "", "", false, err
|
||||
}
|
||||
data, _ := json.Marshal(list)
|
||||
source := base64.StdEncoding.EncodeToString(data)
|
||||
return list, source, time.Now().Format("20060102150405") + "-release", len(list) > 0, nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterGlobalRemote(ctx *gin.Context, name string) ([]*strategy_dto.Title, []any, int64, string, string, error) {
|
||||
f, has := strategy_filter.RemoteFilter(name)
|
||||
if !has {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("filter not found: %s", name)
|
||||
}
|
||||
scopeAllow := false
|
||||
for _, s := range f.Scopes() {
|
||||
if s == strategy_filter.ScopeGlobal {
|
||||
scopeAllow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !scopeAllow {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("scope not allowed: %s", name)
|
||||
}
|
||||
|
||||
list, total, err := f.RemoteList(ctx, "", nil, -1, -1)
|
||||
if err != nil {
|
||||
return nil, nil, 0, "", "", err
|
||||
}
|
||||
return utils.SliceToSlice(f.Titles(), func(l strategy_filter.OptionTitle) *strategy_dto.Title {
|
||||
return &strategy_dto.Title{
|
||||
Field: l.Field,
|
||||
Title: l.Title,
|
||||
}
|
||||
}), list, total, f.Key(), f.Key(), nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterServiceRemote(ctx *gin.Context, serviceId string, name string) ([]*strategy_dto.Title, []any, int64, string, string, error) {
|
||||
f, has := strategy_filter.RemoteFilter(name)
|
||||
if !has {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("filter not found: %s", name)
|
||||
}
|
||||
scopeAllow := false
|
||||
for _, s := range f.Scopes() {
|
||||
if s == strategy_filter.ScopeService {
|
||||
scopeAllow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !scopeAllow {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("scope not allowed: %s", name)
|
||||
}
|
||||
list, total, err := f.RemoteList(ctx, "", map[string]interface{}{"service": serviceId}, -1, -1)
|
||||
if err != nil {
|
||||
return nil, nil, 0, "", "", err
|
||||
}
|
||||
return utils.SliceToSlice(f.Titles(), func(l strategy_filter.OptionTitle) *strategy_dto.Title {
|
||||
return &strategy_dto.Title{
|
||||
Field: l.Field,
|
||||
Title: l.Title,
|
||||
}
|
||||
}), list, total, f.Key(), "list", nil
|
||||
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) filterOptions(ctx *gin.Context, scope string) ([]*strategy_dto.FilterOption, error) {
|
||||
m, has := strategy_filter.Options(scope)
|
||||
if !has {
|
||||
return nil, fmt.Errorf("scope not found: %s", scope)
|
||||
}
|
||||
|
||||
list := utils.MapToSlice(m, func(key string, value *strategy_filter.Option) *strategy_dto.FilterOption {
|
||||
pattern := ""
|
||||
if value.Pattern != nil {
|
||||
pattern = value.Pattern.String()
|
||||
}
|
||||
return &strategy_dto.FilterOption{
|
||||
Name: value.Name,
|
||||
Title: value.Title,
|
||||
Type: value.Type,
|
||||
Pattern: pattern,
|
||||
Options: value.Options,
|
||||
}
|
||||
})
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return list[i].Name < list[j].Name
|
||||
})
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterServiceOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error) {
|
||||
return i.filterOptions(ctx, strategy_filter.ScopeService)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterGlobalOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error) {
|
||||
return i.filterOptions(ctx, strategy_filter.ScopeGlobal)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) GetStrategy(ctx *gin.Context, id string) (*strategy_dto.Strategy, error) {
|
||||
return i.strategyModule.Get(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) search(ctx *gin.Context, keyword string, scope strategy_dto.Scope, target string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) {
|
||||
p, err := strconv.Atoi(page)
|
||||
if err != nil {
|
||||
if page != "" {
|
||||
return nil, 0, fmt.Errorf("page error: %s", err)
|
||||
}
|
||||
p = 1
|
||||
}
|
||||
ps, err := strconv.Atoi(pageSize)
|
||||
if err != nil {
|
||||
if pageSize != "" {
|
||||
return nil, 0, fmt.Errorf("page size error: %s", err)
|
||||
}
|
||||
ps = 20
|
||||
}
|
||||
ss := make([]string, 0)
|
||||
json.Unmarshal([]byte(sort), &ss)
|
||||
fs := make([]string, 0)
|
||||
json.Unmarshal([]byte(filters), &fs)
|
||||
list, total, err := i.strategyModule.Search(ctx, keyword, driver, scope, target, p, ps, fs, ss...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) GlobalStrategyList(ctx *gin.Context, keyword string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) {
|
||||
|
||||
return i.search(ctx, keyword, strategy_dto.ToScope(strategy_dto.ScopeGlobal), "", driver, page, pageSize, order, sort, filters)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) CreateGlobalStrategy(ctx *gin.Context, driver string, input *strategy_dto.Create) error {
|
||||
input.Driver = driver
|
||||
input.Scope = strategy_dto.ToScope(strategy_dto.ScopeGlobal)
|
||||
|
||||
return i.strategyModule.Create(ctx, input)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) PublishGlobalStrategy(ctx *gin.Context, driver string) error {
|
||||
return i.strategyModule.Publish(ctx, driver, strategy_dto.ScopeGlobal, "")
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) ServiceStrategyList(ctx *gin.Context, keyword string, serviceId string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) {
|
||||
|
||||
return i.search(ctx, keyword, strategy_dto.ToScope(strategy_dto.ScopeService), serviceId, driver, page, pageSize, order, sort, filters)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) CreateServiceStrategy(ctx *gin.Context, serviceId string, driver string, input *strategy_dto.Create) error {
|
||||
_, err := i.serviceModule.Get(ctx, serviceId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create service strategy error: %s", err)
|
||||
}
|
||||
input.Driver = driver
|
||||
input.Scope = strategy_dto.ToScope(strategy_dto.ScopeService)
|
||||
input.Target = serviceId
|
||||
|
||||
return i.strategyModule.Create(ctx, input)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) EditStrategy(ctx *gin.Context, id string, input *strategy_dto.Edit) error {
|
||||
return i.strategyModule.Edit(ctx, id, input)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) EnableStrategy(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Enable(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) DisableStrategy(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Disable(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) DeleteStrategy(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func genTime(t string, defaultValue time.Time) (time.Time, error) {
|
||||
if t == "" {
|
||||
return defaultValue, nil
|
||||
}
|
||||
|
||||
s, err := strconv.ParseInt(t, 10, 64)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Unix(s, 0), nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) GetStrategyLogs(ctx *gin.Context, keyword string, strategyId string, start string, end string, limit string, offset string) ([]*strategy_dto.LogItem, int64, error) {
|
||||
now := time.Now()
|
||||
|
||||
s, err := genTime(start, now.Add(-time.Hour*24*30))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("start time error: %s", err)
|
||||
}
|
||||
e, err := genTime(end, now)
|
||||
if err != nil {
|
||||
|
||||
return nil, 0, fmt.Errorf("end time error: %s", err)
|
||||
}
|
||||
if s.After(e) {
|
||||
return nil, 0, fmt.Errorf("start time must be less than end time")
|
||||
}
|
||||
l, err := strconv.ParseInt(limit, 10, 64)
|
||||
if err != nil && limit != "" {
|
||||
|
||||
return nil, 0, err
|
||||
}
|
||||
o, err := strconv.ParseInt(offset, 10, 64)
|
||||
if err != nil && offset != "" {
|
||||
return nil, 0, err
|
||||
}
|
||||
if l < 1 {
|
||||
l = 15
|
||||
}
|
||||
if o < 1 {
|
||||
o = 1
|
||||
}
|
||||
return i.strategyModule.GetStrategyLogs(ctx, keyword, strategyId, s, e, l, o)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) LogInfo(ctx *gin.Context, id string) (*strategy_dto.LogInfo, error) {
|
||||
|
||||
return i.strategyModule.StrategyLogInfo(ctx, id)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package strategy
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type IStrategyController interface {
|
||||
GlobalStrategyList(ctx *gin.Context, keyword string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error)
|
||||
CreateGlobalStrategy(ctx *gin.Context, driver string, input *strategy_dto.Create) error
|
||||
PublishGlobalStrategy(ctx *gin.Context, driver string) error
|
||||
|
||||
ServiceStrategyList(ctx *gin.Context, keyword string, serviceId string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error)
|
||||
CreateServiceStrategy(ctx *gin.Context, serviceId string, driver string, input *strategy_dto.Create) error
|
||||
|
||||
EditStrategy(ctx *gin.Context, id string, input *strategy_dto.Edit) error
|
||||
GetStrategy(ctx *gin.Context, id string) (*strategy_dto.Strategy, error)
|
||||
EnableStrategy(ctx *gin.Context, id string) error
|
||||
DisableStrategy(ctx *gin.Context, id string) error
|
||||
|
||||
DeleteStrategy(ctx *gin.Context, id string) error
|
||||
DeleteServiceStrategy(ctx *gin.Context, serviceId string, id string) error
|
||||
|
||||
Restore(ctx *gin.Context, id string) error
|
||||
|
||||
FilterGlobalOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error)
|
||||
FilterServiceOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error)
|
||||
|
||||
FilterGlobalRemote(ctx *gin.Context, name string) ([]*strategy_dto.Title, []any, int64, string, string, error)
|
||||
FilterServiceRemote(ctx *gin.Context, serviceId string, name string) ([]*strategy_dto.Title, []any, int64, string, string, error)
|
||||
|
||||
ToPublish(ctx *gin.Context, driver string) ([]*strategy_dto.ToPublishItem, string, string, bool, error)
|
||||
|
||||
GetStrategyLogs(ctx *gin.Context, keyword string, strategyId string, start string, end string, limit string, offset string) ([]*strategy_dto.LogItem, int64, error)
|
||||
LogInfo(ctx *gin.Context, id string) (*strategy_dto.LogInfo, error)
|
||||
}
|
||||
|
||||
type IStrategyCommonController interface {
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[IStrategyController](func() reflect.Value {
|
||||
return reflect.ValueOf(&imlStrategyController{})
|
||||
})
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
# 部署
|
||||
|
||||
## 代码同步
|
||||
packages目录下,部分子项目为企业版独有,不要同步到开源版:
|
||||
packages/businessEntry, packages/openApi, packages/systemRunning, README.pro.md
|
||||
|
||||
## 安装依赖
|
||||
建议使用pnpm
|
||||
`npm install -g pnpm`
|
||||
使用pnpm安装依赖
|
||||
`pnpm install`
|
||||
|
||||
## 编译
|
||||
### 开源版本
|
||||
`pnpm run build`
|
||||
### 企业版本
|
||||
`pnpm run build:pro`
|
||||
@@ -9,11 +9,9 @@
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"build": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=core --stream --verbose ",
|
||||
"build:pro": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=business-entry --stream --verbose ",
|
||||
"serve": "lerna run preview --parallel",
|
||||
"serve:remotes": "lerna run serve --scope=remote --parallel",
|
||||
"dev": "lerna run dev --scope=core --stream",
|
||||
"dev:pro": "lerna run dev --scope=business-entry --stream",
|
||||
"stop": "kill-port --port 5000",
|
||||
"scan": "i18next-scanner --config i18next-scanner.config.js"
|
||||
},
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
// .env.pro
|
||||
VITE_APP_MODE=pro
|
||||
VITE_APP_TITLE=My Production App
|
||||
VITE_API_BASE_URL=https://api.production.example.com
|
||||
@@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs','public','code-snippet','ace-editor'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
public/tinymce
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# `businessEntry`
|
||||
|
||||
> TODO: description
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
const businessEntry = require('businessEntry');
|
||||
|
||||
// TODO: DEMONSTRATE API
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const businessEntry = require('..');
|
||||
const assert = require('assert').strict;
|
||||
|
||||
assert.strictEqual(businessEntry(), 'Hello from businessEntry');
|
||||
console.info('businessEntry tests passed');
|
||||
@@ -1,15 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/frontend/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>2APIPark</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script src="/frontend/iconpark_eolink.js"></script>
|
||||
<script src="/frontend/iconpark_apinto.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "business-entry",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": " vite --port 5000 --strictPort",
|
||||
"build": "vite build ",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview --port 5000 --strictPort",
|
||||
"serve": "vite preview --port 5000 --strictPort"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
},
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,158 +0,0 @@
|
||||
import '@core/App.css'
|
||||
import { ConfigProvider } from 'antd';
|
||||
import RenderRoutes from '@businessEntry/components/aoplatform/RenderRoutes';
|
||||
import {BreadcrumbProvider} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import useInitializeMonaco from "@common/hooks/useInitializeMonaco";
|
||||
import ThemeSwitcher from '@common/components/aoplatform/ThemeSwitcher'
|
||||
|
||||
const antdComponentThemeToken = {
|
||||
token: {
|
||||
// Seed Token,影响范围大
|
||||
colorPrimary: '#3D46F2',
|
||||
colorLink:'#3D46F2',
|
||||
colorBorder:'#ededed',
|
||||
colorText:'#333',
|
||||
borderRadius: 4,
|
||||
// 派生变量,影响范围小
|
||||
colorBgContainer: '#fff',
|
||||
colorPrimaryBg:'#EBEEF2',
|
||||
colorTextQuaternary:'#BBB',
|
||||
colorTextTertiary:'#999'
|
||||
},
|
||||
components:{
|
||||
// 派生变量,影响范围小
|
||||
Input:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Select:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Checkbox:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Cascader:{
|
||||
activeShadow:'none',
|
||||
optionSelectedBg:'#EBEEF2',
|
||||
optionHoverBg:'#EBEEF2'
|
||||
},
|
||||
Layout: {
|
||||
bodyBg: '#17163E',
|
||||
headerBg: 'transparent',
|
||||
headerColor: '#333',
|
||||
headerPadding: '10 20px',
|
||||
lightSiderBg: 'transparent',
|
||||
siderBg: 'transparent',
|
||||
},
|
||||
Breadcrumb:{
|
||||
itemColor:'#666',
|
||||
linkColor:'#666',
|
||||
lastItemColor:'#333',
|
||||
},
|
||||
Table:{
|
||||
headerBorderRadius:0,
|
||||
headerSplitColor:'#ededed',
|
||||
borderColor:'#ededed',
|
||||
cellPaddingBlockMD:'10px',
|
||||
cellPaddingInlineMD:'12px',
|
||||
cellPaddingBlockSM:'8px',
|
||||
cellPaddingInlineSM:'12px',
|
||||
headerFilterHoverBg:'#EBEEF2',
|
||||
headerSortActiveBg:'#F7F8FA',
|
||||
headerSortHoverBg:'#F7F8FA',
|
||||
fixedHeaderSortActiveBg:'#F7F8FA',
|
||||
headerBg:'#F7F8FA',
|
||||
rowHoverBg:'#EBEEF2'
|
||||
|
||||
},
|
||||
Segmented:{
|
||||
itemColor:'#333',
|
||||
itemSelectedColor:'#333',
|
||||
trackBg:'#f7f8fa',
|
||||
trackPadding:0,
|
||||
// itemHoverColor:'#EBEEF2',
|
||||
itemActiveBg:'#EBEEF2',
|
||||
itemHoverBg:'#EBEEF2',
|
||||
itemSelectedBg:'#EBEEF2',
|
||||
},
|
||||
Tree:{
|
||||
// titleHeight:30,
|
||||
// fontSize:12,
|
||||
directoryNodeSelectedBg:'#EBEEF2',
|
||||
directoryNodeSelectedColor:'#333',
|
||||
nodeSelectedBg:'#EBEEF2',
|
||||
nodeHoverBg:'#EBEEF2'
|
||||
},
|
||||
Collapse:{
|
||||
headerBg:'#f7f8fa',
|
||||
headerPadding:"12px",
|
||||
contentPadding:"0 10px 12px 10px"
|
||||
},
|
||||
Button:{
|
||||
// paddingInline:8,
|
||||
dangerShadow:'none',
|
||||
defaultShadow:'none',
|
||||
primaryShadow:'none'
|
||||
},
|
||||
Tabs:{
|
||||
cardBg:'#EBEEF2',
|
||||
cardHeight:42,
|
||||
horizontalItemGutter:8,
|
||||
horizontalItemPaddingSM:'12px 8px 8px 8px',
|
||||
horizontalItemPadding:'12px 8px 8px 8px',
|
||||
},
|
||||
Menu:{
|
||||
// itemBg:'#F7F8FA',
|
||||
// subMenuItemBg:'#F7F8FA',
|
||||
// itemMarginBlock:0,
|
||||
// activeBarBorderWidth:0,
|
||||
// itemSelectedColor:'#333',
|
||||
// itemSelectedBg:'#EBEEF2',
|
||||
// itemHoverBg:'#EBEEF2'
|
||||
// itemHeight:'72px',
|
||||
// darkItemBg:'transparent',
|
||||
// itemBg:'transparent',
|
||||
// itemSelectedBg:'transparent',
|
||||
// darkItemSelectedBg:'transparent',
|
||||
// subMenuItemBg:'transparent',
|
||||
// itemActiveBg:'transparent',
|
||||
// darkSubMenuItemBg:'transparent',
|
||||
// activeBarHeight:'2px',
|
||||
// activeBarBorderWidth:2
|
||||
},
|
||||
List:{
|
||||
itemPadding:'8px 0'
|
||||
},
|
||||
Form:{
|
||||
itemMarginBottom:10,
|
||||
|
||||
},
|
||||
Alert:{
|
||||
defaultPadding:'12px 16px'
|
||||
},
|
||||
Tag:{
|
||||
defaultBg:"#f7f8fa"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
useInitializeMonaco()
|
||||
|
||||
return (
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={zhCN}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}>
|
||||
<ThemeSwitcher />
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -1,484 +0,0 @@
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from 'react-router-dom';
|
||||
import Login from "@core/pages/Login.tsx"
|
||||
import BasicLayout from '@common/components/aoplatform/BasicLayout';
|
||||
import {createElement, ReactElement,ReactNode,Suspense} from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {App, Skeleton} from "antd";
|
||||
import ApprovalPage from "@core/pages/approval/ApprovalPage.tsx";
|
||||
import {SystemProvider} from "@core/contexts/SystemContext.tsx";
|
||||
import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx";
|
||||
import {FC,lazy} from 'react';
|
||||
import { TeamProvider } from '@core/contexts/TeamContext.tsx';
|
||||
import SystemOutlet from '@core/pages/system/SystemOutlet.tsx';
|
||||
import { DashboardProvider } from '@core/contexts/DashboardContext.tsx';
|
||||
import { TenantManagementProvider } from '@market/contexts/TenantManagementContext.tsx';
|
||||
|
||||
type RouteConfig = {
|
||||
path:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
}
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
}
|
||||
|
||||
const PUBLIC_ROUTES:RouteConfig[] = [
|
||||
{
|
||||
path:'/',
|
||||
component:<Login/>,
|
||||
key: uuidv4(),
|
||||
},
|
||||
{
|
||||
path:'/login',
|
||||
component:<Login/>,
|
||||
key: uuidv4()
|
||||
},
|
||||
{
|
||||
path:'/',
|
||||
component:<ProtectedRoute/>,
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'approval/*',
|
||||
component:<ApprovalPage />,
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'team',
|
||||
component:<Outlet/>,
|
||||
key: uuidv4(),
|
||||
provider: TeamProvider,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamList.tsx'))
|
||||
},
|
||||
{
|
||||
path:'inside/:teamId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsidePage.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'member',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsideMember.tsx')),
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamConfig.tsx')),
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'service',
|
||||
component:<SystemOutlet />,
|
||||
key: uuidv4(),
|
||||
provider: SystemProvider,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:uuidv4(),
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:teamId',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path:':teamId',
|
||||
component:<Outlet/>,
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'inside/:serviceId',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'api',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideApiDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path:'router',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
},
|
||||
{
|
||||
path:'upstream',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/upstream/SystemInsideUpstreamContent.tsx')),
|
||||
},
|
||||
{
|
||||
path:'document',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path:'subscriber',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideSubscriber.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'approval',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApproval.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'topology',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemTopology.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'publish',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublish.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},{
|
||||
path:'datasourcing',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideDashboardSetting.tsx')),
|
||||
},
|
||||
{
|
||||
path:'cluster',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCluster.tsx')),
|
||||
},
|
||||
{
|
||||
path:'cert',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCert.tsx')),
|
||||
},
|
||||
{
|
||||
path:'serviceHub',
|
||||
component:<Outlet />,
|
||||
key:uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'detail/:serviceId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubDetail.tsx')),
|
||||
}]
|
||||
},
|
||||
{
|
||||
path:'commonsetting',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/common/CommonPage.tsx')),
|
||||
key:uuidv4(),
|
||||
},
|
||||
{
|
||||
path:'consumer',
|
||||
component:<Outlet />,
|
||||
provider:TenantManagementProvider,
|
||||
key:uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:uuidv4(),
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:':teamId/inside/:appId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'service',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideService.tsx')),
|
||||
},
|
||||
{
|
||||
path:'authorization',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideAuth.tsx')),
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementAppSetting.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:teamId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'member',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberPage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:uuidv4(),
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:memberGroupId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'role',
|
||||
key:uuidv4(),
|
||||
component:<Outlet></Outlet>,
|
||||
children:[
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleList.tsx')),
|
||||
},
|
||||
{
|
||||
path:':roleType/config',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
},
|
||||
{
|
||||
path:':roleType/config/:roleId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
APP_MODE === 'pro' &&{
|
||||
path:'openapi',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@openApi/pages/OpenApiList.tsx')),
|
||||
key:uuidv4(),
|
||||
},
|
||||
{
|
||||
path:'assets',
|
||||
component:<p>设计中</p>,
|
||||
key:uuidv4()
|
||||
},
|
||||
APP_MODE === 'pro' &&{
|
||||
path:'analytics',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/Dashboard.tsx')),
|
||||
key:uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:':dashboardType',
|
||||
component:<Outlet/>,
|
||||
key:uuidv4(),
|
||||
provider:DashboardProvider,
|
||||
children:[
|
||||
{
|
||||
path:'list',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardList.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'detail/:dashboardDetailId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardDetail.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'systemrunning',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@systemRunning/pages/SystemRunning.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '../../../../common/src/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'logsettings/*',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/logsettings/LogSettings.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:uuidv4()
|
||||
}]
|
||||
|
||||
},
|
||||
APP_MODE ==='pro' && {
|
||||
path:'resourcesettings/*',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/resourcesettings/ResourceSettings.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:uuidv4()
|
||||
}]
|
||||
|
||||
},
|
||||
{
|
||||
path:'userProfile/*',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')),
|
||||
key:uuidv4(),
|
||||
children:[{
|
||||
path:'changepsw',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')),
|
||||
key:uuidv4()
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
const RenderRoutes = ()=> {
|
||||
return (
|
||||
<App className="h-full" message={{ maxCount: 1 }}>
|
||||
<Router>
|
||||
<Routes>
|
||||
{generateRoutes(PUBLIC_ROUTES)}
|
||||
</Routes>
|
||||
</Router>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
const generateRoutes = (routerConfig: RouteConfig[]) => {
|
||||
return routerConfig?.map((route: RouteConfig) => {
|
||||
let routeElement;
|
||||
if (route.lazy) {
|
||||
const LazyComponent = route.lazy as React.ExoticComponent<unknown>;
|
||||
|
||||
routeElement = (
|
||||
<Suspense fallback={ <div className=''><Skeleton className='m-btnbase w-calc-100vw-minus-padding-r' active /></div>}>
|
||||
{route.provider ? (
|
||||
createElement(route.provider, {}, <LazyComponent />)
|
||||
) : (
|
||||
<LazyComponent />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
} else {
|
||||
routeElement = route.provider ? (
|
||||
createElement(route.provider, {}, route.component)
|
||||
) : (
|
||||
route.component
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Route
|
||||
key={route.key}
|
||||
path={route.path}
|
||||
element={routeElement}
|
||||
>
|
||||
{route.children && generateRoutes(route.children as RouteConfig[])}
|
||||
</Route>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 保护的路由组件
|
||||
function ProtectedRoute() {
|
||||
const {state} = useGlobalContext()
|
||||
return state.isAuthenticated? <BasicLayout project="core" /> : <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
export default RenderRoutes
|
||||
@@ -1,27 +0,0 @@
|
||||
import {StrictMode} from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import '@core/index.css'
|
||||
import {GlobalProvider} from "@common/contexts/GlobalStateContext.tsx";
|
||||
|
||||
async function initializeApp() {
|
||||
try {
|
||||
// 初始化行为
|
||||
// await fetchInitialConfig(); // 示例:获取初始配置
|
||||
|
||||
// 异步操作完成后,渲染React应用
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<GlobalProvider>
|
||||
<App />
|
||||
</GlobalProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Initialization failed:', error);
|
||||
// 处理初始化失败的情况,比如渲染一个错误界面
|
||||
}
|
||||
}
|
||||
|
||||
// 执行初始化
|
||||
initializeApp();
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
// start-vite.js// start-vite.js
|
||||
import { exec } from 'child_process';
|
||||
|
||||
const viteProcess = exec('pnpm run build');
|
||||
|
||||
viteProcess.stdout.on('data', (data) => {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
viteProcess.stderr.on('data', (data) => {
|
||||
console.error(data.toString());
|
||||
});
|
||||
|
||||
viteProcess.on('close', (code) => {
|
||||
console.log(`Vite process exited with code ${code}`);
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@core/*": ["../core/src/*"],
|
||||
"@common/*": ["../common/src/*"],
|
||||
"@market/*": ["../market/src/*"],
|
||||
"@dashboard/*": ["../dashboard/src/*"],
|
||||
"@openApi/*": ["../openApi/src/*"],
|
||||
"@systemRunning/*": ["../systemRunning/src/*"],
|
||||
"@businessEntry/*": ["./src/*"],
|
||||
},
|
||||
},
|
||||
"include": ["src", "public/iconpark_eolink.js", "public/iconpark_apinto.js", "../common/src/component/aoplatform/EditableTableWithModal.tsx", "../common/src/components/aoplatform/TreeWithMore.tsx", "../common/src/components/aoplatform/DatePicker.tsx", "../common/src/components/aoplatform/TimeRangeSelector.tsx", "../common/src/components/aoplatform/TimePicker.tsx", "../common/src/components/aoplatform/MemberTransfer.tsx", "../common/src/components/aoplatform/Navigation.tsx", "../common/src/components/aoplatform/PageList.tsx", "../common/src/components/aoplatform/ErrorBoundary.tsx", "../common/src/components/aoplatform/ScrollableSection.tsx", "../common/src/utils/postcat.tsx", "../common/src/utils/curl.ts", "../common/src/components/aoplatform/ResetPsw.tsx", "../common/src/components/aoplatform/SubscribeApprovalModalContent.tsx", "src/components/aoplatform/RenderRoutes.tsx", "../common/src/components/aoplatform/PublishApprovalModalContent.tsx", "../common/src/components/aoplatform/InsidePage.tsx", "../common/src/const/type.ts", "../common/src/components/aoplatform/intelligent-plugin", "../common/src/const/domain"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import path from 'path'
|
||||
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: './node_modules/.vite',
|
||||
build:{
|
||||
outDir:'../../dist',
|
||||
sourcemap: false,
|
||||
chunkSizeWarningLimit: 50000,
|
||||
cacheDir: './node_modules/.vite',
|
||||
output: {
|
||||
manualChunks(id) {
|
||||
if (id.includes('node_modules')) {
|
||||
return id.toString().split('node_modules/')[1].split('/')[0].toString();
|
||||
}
|
||||
// 针对 pnpm 和 Monorepo 特殊处理
|
||||
if (id.includes('.pnpm')) {
|
||||
const segments = id.split(path.sep);
|
||||
const packageName = segments[segments.indexOf('.pnpm') + 1].split('@')[0];
|
||||
return packageName;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
tailwindcss(path.resolve(__dirname, '../common/tailwind.config.js')),
|
||||
autoprefixer
|
||||
],
|
||||
},
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
modules:{
|
||||
localsConvention:"camelCase",
|
||||
generateScopedName:"[local]_[hash:base64:2]"
|
||||
}
|
||||
},
|
||||
plugins: [react(),
|
||||
dynamicImportVars({
|
||||
include:["src"],
|
||||
exclude:[],
|
||||
warnOnError:false
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
{ find: /^~/, replacement: '' },
|
||||
{ find: '@common', replacement: path.resolve(__dirname, '../common/src') },
|
||||
{ find: '@market', replacement: path.resolve(__dirname, '../market/src') },
|
||||
{ find: '@core', replacement: path.resolve(__dirname, '../core/src') },
|
||||
{ find: '@dashboard', replacement: path.resolve(__dirname, '../dashboard/src') },
|
||||
{ find: '@openApi', replacement: path.resolve(__dirname, '../openApi/src') },
|
||||
{ find: '@systemRunning', replacement: path.resolve(__dirname, '../systemRunning/src') },
|
||||
{ find: '@businessEntry', replacement: path.resolve(__dirname, './src') },
|
||||
]
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api/v1': {
|
||||
// target: 'http://uat.apikit.com:11204/mockApi/aoplatform/',
|
||||
target: 'http://172.18.166.219:8288/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/api2/v1': {
|
||||
// target: 'http://uat.apikit.com:11204/mockApi/aoplatform/',
|
||||
target: 'http://172.18.166.219:8288/',
|
||||
changeOrigin: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
logLevel:'info'
|
||||
})
|
||||
-85
File diff suppressed because one or more lines are too long
@@ -8,18 +8,19 @@ import {
|
||||
import { Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import Logo from '@common/assets/layout-logo.png';
|
||||
import AvatarPic from '@common/assets/default-avatar.png'
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState} from "react";
|
||||
import { useGlobalContext } from '@common/contexts/GlobalStateContext.tsx';
|
||||
import { PERMISSION_DEFINITION } from '@common/const/permissions.ts';
|
||||
import { BasicResponse, RESPONSE_TIPS, routerKeyMap, STATUS_CODE } from '@common/const/const.tsx';
|
||||
import { UserInfoType } from '@common/const/type.ts';
|
||||
import { useFetch } from '@common/hooks/http.ts';
|
||||
import { ProjectFilled } from '@ant-design/icons';
|
||||
import { getNavItem } from '@common/utils/navigation';
|
||||
import { getNavItem, transformMenuData } from '@common/utils/navigation';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { $t } from '@common/locales';
|
||||
import { ProConfigProvider, ProLayout } from '@ant-design/pro-components';
|
||||
import LanguageSetting from './LanguageSetting';
|
||||
import { usePluginSlotHub } from '@common/contexts/PluginSlotHubContext';
|
||||
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
export type MenuItem = Required<MenuProps>['items'][number];
|
||||
@@ -35,48 +36,21 @@ const themeToken = {
|
||||
}
|
||||
}
|
||||
|
||||
function BasicLayout({ project = 'core' }: { project: string }) {
|
||||
const navigator = useNavigate()
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const { state, accessData, checkPermission, accessInit, dispatch, resetAccess, getGlobalAccessData } = useGlobalContext()
|
||||
const [pathname, setPathname] = useState(currentUrl); const mainPage = project === 'core' ? '/service/list' : '/serviceHub/list'
|
||||
|
||||
const TOTAL_MENU_ITEMS: MenuProps['items'] = useMemo(() => [
|
||||
getNavItem($t('工作空间'), 'workspace', '/guide/page', <Icon icon="ic:baseline-space-dashboard" width="18" height="18" />, [
|
||||
getNavItem(<a>{$t('首页')}</a>, 'guide', '/guide/page', <Icon icon="ic:baseline-home" width="18" height="18" />, undefined, undefined, 'all'),
|
||||
getNavItem(<a>{$t('服务')}</a>, 'service', '/service', <Icon icon="ic:baseline-blinds-closed" width="18" height="18" />, undefined, undefined, 'all'),
|
||||
getNavItem(<a>{$t('消费者')}</a>, 'consumer', '/consumer', <Icon icon="ic:baseline-apps" width="18" height="18" />, undefined, undefined, 'all'),
|
||||
getNavItem(<a>{$t('团队')}</a>, 'team', '/team', <Icon icon="ic:baseline-people-alt" width="18" height="18" />, undefined, undefined, 'all'),
|
||||
]),
|
||||
getNavItem($t('API 市场'), 'serviceHub', '/serviceHub', <Icon icon="ic:baseline-hub" width="18" height="18" />, undefined, undefined, 'system.api_portal.api_portal.view'),
|
||||
|
||||
getNavItem($t('仪表盘'), 'mainPage', APP_MODE === 'pro' ? '/analytics' : '/analytics/total', <Icon icon="ic:baseline-bar-chart" width="18" height="18" />, [
|
||||
getNavItem(<a >{$t('运行视图')}</a>, 'analytics', APP_MODE === 'pro' ? '/analytics' : '/analytics/total', <ProjectFilled />, undefined, undefined, 'system.analysis.run_view.view'),
|
||||
APP_MODE === 'pro' ? getNavItem(<a >{$t('系统拓扑图')}</a>, 'systemrunning', '/systemrunning', <ProjectFilled />, undefined, undefined, 'system.dashboard.systemrunning.view') : null,
|
||||
], undefined, 'system.analysis.run_view.view'),
|
||||
|
||||
getNavItem($t('系统设置'), 'operationCenter', '/commonsetting', <Icon icon="ic:baseline-settings" width="18" height="18" />, [
|
||||
getNavItem($t('系统'), 'serviceHubSetting', '/commonsetting', null, [
|
||||
getNavItem(<a>{$t('常规')}</a>, 'commonsetting', '/commonsetting', <Icon icon="ic:baseline-hub" width="18" height="18" />, undefined, undefined, 'system.api_market.service_classification.view'),
|
||||
getNavItem(<a>{$t('API 网关')}</a>, 'cluster', '/cluster', <Icon icon="ic:baseline-device-hub" width="18" height="18" />, undefined, undefined, 'system.settings.api_gateway.view'),
|
||||
getNavItem(<a>{$t('AI 模型')}</a>, 'aisetting', '/aisetting', <Icon icon="hugeicons:ai-network" width="18" height="18" />, undefined, undefined, 'system.settings.api_gateway.view'),
|
||||
], undefined, 'system.api_market.service_classification.view'),
|
||||
getNavItem($t('用户'), 'organization', '/member', null, [
|
||||
getNavItem(<a>{$t('账号')}</a>, 'member', '/member', <Icon icon="ic:baseline-people-alt" width="18" height="18" />, undefined, undefined, 'system.settings.account.view'),
|
||||
getNavItem(<a>{$t('角色')}</a>, 'role', '/role', <Icon icon="ic:baseline-verified-user" width="18" height="18" />, undefined, undefined, 'system.organization.role.view'),
|
||||
], undefined, ''),
|
||||
getNavItem($t('集成'), 'maintenanceCenter', '/datasourcing', null, [
|
||||
getNavItem(<a>{$t('数据源')}</a>, 'datasourcing', '/datasourcing', <Icon icon="ic:baseline-monitor-heart" width="18" height="18" />, undefined, undefined, 'system.settings.data_source.view'),
|
||||
getNavItem(<a>{$t('全局策略')}</a>, 'globalPolicy', '/globalPolicy', <Icon icon="uil:comment-shield" width="18" height="18" />, undefined, undefined, 'system.settings.data_source.view'),
|
||||
getNavItem(<a>{$t('证书')}</a>, 'cert', '/cert', <Icon icon="ic:baseline-security" width="18" height="18" />, undefined, undefined, 'system.settings.ssl_certificate.view'),
|
||||
getNavItem(<a>{$t('日志')}</a>, 'logsettings', '/logsettings', <Icon icon="ic:baseline-sticky-note-2" width="18" height="18" />, undefined, undefined, 'system.settings.log_configuration.view'),
|
||||
APP_MODE === 'pro' ? getNavItem(<a>{$t('资源')}</a>, 'resourcesettings', '/resourcesettings', null, undefined, undefined, 'system.partition.self.view') : null,
|
||||
APP_MODE === 'pro' ? getNavItem(<a>{$t('Open API')}</a>, 'openapi', '/openapi', null, undefined, undefined, 'system.openapi.self.view') : null,
|
||||
]),
|
||||
]),
|
||||
], [state.language, accessInit])
|
||||
function BasicLayout({project = 'core'}:{project:string}){
|
||||
const navigator = useNavigate()
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const { state,accessData,checkPermission,accessInit,dispatch,resetAccess,getGlobalAccessData, menuList} = useGlobalContext()
|
||||
const [pathname, setPathname] = useState(currentUrl);
|
||||
const mainPage = project === 'core' ?'/service/list':'/serviceHub/list'
|
||||
const [menuItems, setMenuItems] = useState<MenuProps['items']>();
|
||||
const pluginSlotHub = usePluginSlotHub()
|
||||
|
||||
useEffect(()=>{
|
||||
const newMenu = transformMenuData(menuList)
|
||||
setMenuItems(newMenu);
|
||||
},[menuList, state.language,accessInit])
|
||||
|
||||
useEffect(() => {
|
||||
if (currentUrl === '/') {
|
||||
@@ -101,32 +75,28 @@ function BasicLayout({ project = 'core' }: { project: string }) {
|
||||
if (filteredRoutes.length === 0) {
|
||||
return false
|
||||
}
|
||||
return { ...item, routes: filteredRoutes };
|
||||
return { ...item,routes: filteredRoutes,name:$t(item.name) };
|
||||
}
|
||||
// 处理没有 routes 的菜单项
|
||||
if (item.access) {
|
||||
return (item.access === 'all' || hasAccess(item.access)) ? item : null;
|
||||
return (item.access === 'all' || hasAccess(item.access)) ? {...item,name:$t(item.name)} : null;
|
||||
}
|
||||
|
||||
// 如果没有 access 和 routes,则保留
|
||||
return item;
|
||||
})
|
||||
.filter(x => x); // 过滤掉处理后为 null 的项
|
||||
};
|
||||
|
||||
// 初始过滤操作
|
||||
const res = [...TOTAL_MENU_ITEMS]!.filter(x => x).map((x: any) => (x.routes ? { ...x, routes: filterMenu(x.routes) } : x));
|
||||
// 返回处理后的数据
|
||||
return { path: '/', routes: res.map(x => ({ ...x, routes: x.routes?.filter(x => (x.access || x.routes?.length > 0)) })).filter(x => (x.access || x.routes?.length > 0)) };
|
||||
}, [accessData, state.language]);
|
||||
|
||||
|
||||
|
||||
|
||||
const { message } = App.useApp()
|
||||
const [userInfo, setUserInfo] = useState<UserInfoType>()
|
||||
const { fetchData } = useFetch()
|
||||
const navigate = useNavigate();
|
||||
// 如果没有 access 和 routes,则保留
|
||||
return {...item,name:$t(item.name) };
|
||||
})
|
||||
.filter(x => x); // 过滤掉处理后为 null 的项
|
||||
};
|
||||
|
||||
// 初始过滤操作
|
||||
const res = [...(menuItems || [])]!.filter(x => x).map((x: any) => (x.routes ? { ...x,name:$t(x.name), routes: filterMenu(x.routes) } : {...x,name:$t(x.name)}));
|
||||
// 返回处理后的数据
|
||||
return { path: '/', routes: res.map(x=> ({...x, routes: x.routes?.filter(x=> (x.access || x.routes?.length > 0))})).filter(x=> (x.access || x.routes?.length > 0)) };
|
||||
}, [accessData, state.language,menuItems]);
|
||||
|
||||
const { message } = App.useApp()
|
||||
const [userInfo,setUserInfo] = useState<UserInfoType>()
|
||||
const {fetchData} = useFetch()
|
||||
const navigate = useNavigate();
|
||||
|
||||
const getUserInfo = () => {
|
||||
fetchData<BasicResponse<{ profile: UserInfoType }>>('account/profile', { method: 'GET' })
|
||||
@@ -178,110 +148,115 @@ function BasicLayout({ project = 'core' }: { project: string }) {
|
||||
].filter(Boolean), [userInfo]);
|
||||
|
||||
|
||||
const actionRender =useMemo( ()=>{
|
||||
return [
|
||||
<LanguageSetting />,
|
||||
<Button className=" text-[#ffffffb3] hover:text-[#fff] border-none" type="default" ghost onClick={()=>{window.open('https://docs.apipark.com','_blank')}}>
|
||||
<span className='flex items-center gap-[8px]'> <Icon icon="ic:baseline-help" width="14" height="14"/>{$t('文档')}</span>
|
||||
</Button> ,
|
||||
...((pluginSlotHub.getSlot('basicLayoutAfterBtns') as unknown[] )||[] )
|
||||
]
|
||||
},[pluginSlotHub.getSlot('basicLayoutAfterBtns') ])
|
||||
|
||||
return (
|
||||
<div
|
||||
id="test-pro-layout"
|
||||
style={{
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<ProConfigProvider hashed={false}>
|
||||
<ConfigProvider
|
||||
getTargetContainer={() => {
|
||||
return document.getElementById('test-pro-layout') || document.body;
|
||||
}}
|
||||
|
||||
return(
|
||||
<div
|
||||
id="test-pro-layout"
|
||||
style={{
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<ProLayout
|
||||
prefixCls="apipark-layout"
|
||||
location={{
|
||||
pathname,
|
||||
}}
|
||||
siderWidth={220}
|
||||
breakpoint={'lg'}
|
||||
route={headerMenuData}
|
||||
token={themeToken}
|
||||
siderMenuType="group"
|
||||
menu={{
|
||||
type: 'group',
|
||||
collapsedShowGroupTitle: true,
|
||||
}}
|
||||
disableMobile={true}
|
||||
avatarProps={{
|
||||
src: AvatarPic || userInfo?.avatar,
|
||||
size: 'small',
|
||||
title: userInfo?.username || 'unknown',
|
||||
render: (props, dom) => {
|
||||
return (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items
|
||||
<ProConfigProvider hashed={false}>
|
||||
<ConfigProvider
|
||||
getTargetContainer={() => {
|
||||
return document.getElementById('test-pro-layout') || document.body;
|
||||
}}
|
||||
>
|
||||
<div className='avatar-dom'>{dom}
|
||||
>
|
||||
<ProLayout
|
||||
prefixCls="apipark-layout"
|
||||
location={{
|
||||
pathname,
|
||||
}}
|
||||
siderWidth={220}
|
||||
breakpoint={'lg'}
|
||||
route={headerMenuData}
|
||||
token={themeToken}
|
||||
siderMenuType="group"
|
||||
menu={{
|
||||
type: 'group',
|
||||
collapsedShowGroupTitle: true,
|
||||
}}
|
||||
disableMobile={true}
|
||||
avatarProps={{
|
||||
src: AvatarPic || userInfo?.avatar,
|
||||
size: 'small',
|
||||
title: userInfo?.username||'unknown',
|
||||
render: (props, dom) => {
|
||||
return (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items
|
||||
}}
|
||||
>
|
||||
<div className='avatar-dom'>{dom}
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
},
|
||||
}}
|
||||
actionsRender={(props) => {
|
||||
if (props.isMobile) return [];
|
||||
if (typeof window === 'undefined') return [];
|
||||
return actionRender;
|
||||
}}
|
||||
headerTitleRender={() => (
|
||||
<div className="w-[192px] flex items-center">
|
||||
<img
|
||||
className="h-[20px] cursor-pointer "
|
||||
src={Logo}
|
||||
onClick={()=> navigator(mainPage)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
logo={Logo}
|
||||
pageTitleRender={()=>$t('APIPark')}
|
||||
menuFooterRender={(props) => {
|
||||
if (props?.collapsed) return undefined;
|
||||
}}
|
||||
menuItemRender={(item, dom) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
// 同级目录点击无效
|
||||
if(item.key && routerKeyMap.get(item.key) && routerKeyMap.get(item.key).length > 0 && routerKeyMap.get(item.key)?.indexOf(pathname.split('/')[1]) !== -1){
|
||||
return
|
||||
}
|
||||
if(item.key === pathname.split('/')[1]){
|
||||
return
|
||||
}
|
||||
|
||||
if(item.path){
|
||||
navigator(item.path)
|
||||
}
|
||||
setPathname(item.path || '');
|
||||
}}
|
||||
>
|
||||
{dom}
|
||||
</div>
|
||||
)}
|
||||
fixSiderbar={true}
|
||||
layout='mix'
|
||||
splitMenus={true}
|
||||
collapsed={false}
|
||||
collapsedButtonRender={false}
|
||||
>
|
||||
<div className={`w-full h-calc-100vh-minus-navbar pl-PAGE_INSIDE_X pt-PAGE_INSIDE_T ${currentUrl.startsWith('/role/list') ? 'overflow-auto' : 'overflow-hidden' }`}>
|
||||
<Outlet />
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
},
|
||||
}}
|
||||
actionsRender={(props) => {
|
||||
if (props.isMobile) return [];
|
||||
if (typeof window === 'undefined') return [];
|
||||
return [
|
||||
<LanguageSetting />,
|
||||
<Button className=" text-[#ffffffb3] hover:text-[#fff] border-none" type="default" ghost onClick={() => { window.open('https://docs.apipark.com', '_blank') }}>
|
||||
<span className='flex items-center gap-[8px]'> <Icon icon="ic:baseline-help" width="14" height="14" />{$t('文档')}</span>
|
||||
</Button>
|
||||
];
|
||||
}}
|
||||
headerTitleRender={() => (
|
||||
<div className="w-[192px] flex items-center">
|
||||
<img
|
||||
className="h-[20px] cursor-pointer "
|
||||
src={Logo}
|
||||
onClick={() => navigator(mainPage)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
logo={Logo}
|
||||
pageTitleRender={() => $t('APIPark')}
|
||||
menuFooterRender={(props) => {
|
||||
if (props?.collapsed) return undefined;
|
||||
}}
|
||||
menuItemRender={(item, dom) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
// 同级目录点击无效
|
||||
if (item.key && routerKeyMap.get(item.key) && routerKeyMap.get(item.key).length > 0 && routerKeyMap.get(item.key)?.indexOf(pathname.split('/')[1]) !== -1) {
|
||||
return
|
||||
}
|
||||
if (item.key === pathname.split('/')[1]) {
|
||||
return
|
||||
}
|
||||
|
||||
if (item.path) {
|
||||
navigator(item.path)
|
||||
}
|
||||
setPathname(item.path || '');
|
||||
}}
|
||||
>
|
||||
{dom}
|
||||
</div>
|
||||
)}
|
||||
fixSiderbar={true}
|
||||
layout='mix'
|
||||
splitMenus={true}
|
||||
collapsed={false}
|
||||
collapsedButtonRender={false}
|
||||
>
|
||||
<div className={`w-full h-calc-100vh-minus-navbar pl-PAGE_INSIDE_X pt-PAGE_INSIDE_T ${currentUrl.startsWith('/role/list') ? 'overflow-auto' : 'overflow-hidden'}`}>
|
||||
<Outlet />
|
||||
</div>
|
||||
</ProLayout>
|
||||
</ConfigProvider>
|
||||
</ProConfigProvider>
|
||||
</div>
|
||||
)
|
||||
</ProLayout>
|
||||
</ConfigProvider>
|
||||
</ProConfigProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default BasicLayout
|
||||
@@ -37,13 +37,13 @@ const InsidePage:FC<InsidePageProps> = ({showBanner=true,pageTitle,tagList,showB
|
||||
// <div className="h-full flex flex-col flex-1 overflow-hidden bg-[#f7f8fa]">
|
||||
<div className={`h-full flex flex-col flex-1 overflow-hidden ${className}`}>
|
||||
{ showBanner && <div className={`border-[0px] mr-PAGE_INSIDE_X ${showBorder ? 'border-b-[1px] border-solid border-BORDER' : ''} ${headerClassName}`}>
|
||||
<div className="mb-[30px]">
|
||||
{!pageTitle && !description && !backUrl &&!customBtn ? <></>: <div className="mb-[30px]">
|
||||
{backUrl &&<div className="text-[18px] leading-[25px] mb-[12px]">
|
||||
<Button type="text" onClick={goBack}><ArrowLeftOutlined className="max-h-[14px]" />{$t('返回')}</Button>
|
||||
</div>}
|
||||
<div className="flex justify-between mb-[20px] items-center ">
|
||||
<div className="flex items-center gap-TAG_LEFT ">
|
||||
<p className="text-theme text-[26px] ">{pageTitle}</p>
|
||||
<div className="text-theme text-[26px] ">{pageTitle}</div>
|
||||
{tagList && tagList?.length > 0 && tagList?.map((tag)=>{
|
||||
return ( <Tag key={tag.label as string} bordered={false} >{tag.label}</Tag>)
|
||||
})}
|
||||
@@ -53,10 +53,10 @@ const InsidePage:FC<InsidePageProps> = ({showBanner=true,pageTitle,tagList,showB
|
||||
}}>{btnTitle}</Button></WithPermission>}
|
||||
{customBtn}
|
||||
</div>
|
||||
<p >
|
||||
<div >
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
</div>}
|
||||
<div className={`h-full ${scrollPage ? 'overflow-hidden' : 'overflow-auto'} ${contentClassName || ''}`}>{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Result, Skeleton } from 'antd';
|
||||
|
||||
const NotFound: React.FC = () => {
|
||||
const [showPage, setShowPage] = useState<boolean>(false)
|
||||
|
||||
useEffect(()=>{
|
||||
setTimeout(()=>setShowPage(true), 1000)
|
||||
},[])
|
||||
|
||||
return (
|
||||
<div className={`h-full w-full flex flex-1 align-middle ${showPage ? 'items-center' : ''}`}>
|
||||
{ showPage ? <Result
|
||||
className='w-full'
|
||||
status="404"
|
||||
title="404"
|
||||
subTitle="Sorry, the page you visited does not exist."
|
||||
/> : <Skeleton active /> }
|
||||
</div>
|
||||
)}
|
||||
|
||||
export default NotFound;
|
||||
@@ -0,0 +1,95 @@
|
||||
import {App, Form, Input, Row, Table} from "antd";
|
||||
import {forwardRef, useEffect, useImperativeHandle, useMemo} from "react";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import {BasicResponse, PLACEHOLDER, PolicyPublishColumns, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { $t } from "@common/locales";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { PolicyPublishModalHandle, PolicyPublishModalProps } from "@common/const/type";
|
||||
|
||||
|
||||
export const PolicyPublishModalContent = forwardRef<PolicyPublishModalHandle,PolicyPublishModalProps>((props, ref) => {
|
||||
const { message } = App.useApp()
|
||||
const { data} = props
|
||||
const [form] = Form.useForm();
|
||||
const {fetchData} = useFetch()
|
||||
const {state} = useGlobalContext()
|
||||
|
||||
const publish:()=>Promise<boolean | string | Record<string, unknown>> = ()=>{
|
||||
return new Promise((resolve, reject)=>{
|
||||
form.validateFields().then((value)=>{
|
||||
const body = {...value, source:data.source}
|
||||
fetchData<BasicResponse<null>>('strategy/global/data-masking/publish',{method: 'POST',eoBody:body,eoTransformKeys:['versionName']}).then(response=>{
|
||||
const {code,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
message.success(msg || $t(RESPONSE_TIPS.success))
|
||||
resolve(response)
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
reject(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).catch((errorInfo)=> reject(errorInfo))
|
||||
}).catch((errorInfo)=> reject(errorInfo))
|
||||
})
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, ()=>({
|
||||
publish,
|
||||
})
|
||||
)
|
||||
|
||||
useEffect(()=>{
|
||||
form.setFieldsValue(data)
|
||||
},[data])
|
||||
|
||||
const translatedPolicyColumns = useMemo(()=>PolicyPublishColumns.map((x)=>({
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title) : x.title,
|
||||
})),[state.language])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<WithPermission access=""><Form
|
||||
className=" mx-auto"
|
||||
form={form}
|
||||
labelAlign='left'
|
||||
layout='vertical'
|
||||
scrollToFirstError
|
||||
name="publishApprovalModalContent"
|
||||
// labelCol={{span: 3}}
|
||||
// wrapperCol={{span: 21}}
|
||||
autoComplete="off"
|
||||
>
|
||||
|
||||
<Form.Item
|
||||
label={$t("发布名称")}
|
||||
name='versionName'
|
||||
rules={[{required: true,whitespace:true }]}
|
||||
>
|
||||
<Input className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={$t("描述")}
|
||||
name="desc"
|
||||
>
|
||||
<Input.TextArea className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)} />
|
||||
</Form.Item>
|
||||
<Row className="mt-mbase pb-[8px] h-[32px] font-bold" ><span >{$t('策略列表')}:</span></Row>
|
||||
<Row className="mb-mbase ">
|
||||
<Table
|
||||
columns={translatedPolicyColumns}
|
||||
bordered={true}
|
||||
rowKey="name"
|
||||
size="small"
|
||||
dataSource={data.strategies || []}
|
||||
pagination={false}
|
||||
/>
|
||||
{!data?.isPublish&& data?.unpublishMsg&& <p className="text-status_fail mt-[4px]">{data.unpublishMsg}</p>}
|
||||
</Row>
|
||||
|
||||
</Form>
|
||||
</WithPermission>
|
||||
</>)
|
||||
})
|
||||
@@ -6,7 +6,7 @@ import {BasicResponse, FORM_ERROR_TIPS, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE,
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { SYSTEM_PUBLISH_ONLINE_COLUMNS } from "@core/const/system/const.tsx";
|
||||
import { $t } from "@common/locales";
|
||||
import { ApprovalRouteColumns, ApprovalStatusColorClass, ApprovalUpstreamColumns, ChangeTypeEnum } from "@common/const/approval/const";
|
||||
import { ApprovalPolicyColumns, ApprovalRouteColumns, ApprovalStatusColorClass, ApprovalUpstreamColumns, ChangeTypeEnum } from "@common/const/approval/const";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import { SystemInsidePublishOnlineItems } from "@core/pages/system/publish/SystemInsidePublishOnline";
|
||||
@@ -140,6 +140,22 @@ export const PublishApprovalModalContent = forwardRef<PublishApprovalModalHandle
|
||||
}
|
||||
}),[state.language])
|
||||
|
||||
|
||||
const translatedPolicyColumns = useMemo(()=>ApprovalPolicyColumns.map((x)=>{
|
||||
return {
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title) : x.title,
|
||||
...(x.dataIndex === 'status' ? {
|
||||
render:(_,entity)=> (
|
||||
<span className={`${ApprovalStatusColorClass[entity.change as keyof typeof ApprovalStatusColorClass]} truncate block`}>
|
||||
{$t(ChangeTypeEnum[entity.change as (keyof typeof ChangeTypeEnum)] || '-')}
|
||||
</span>
|
||||
)
|
||||
}:{})
|
||||
}
|
||||
}),[state.language])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{!insidePage && <>
|
||||
@@ -219,6 +235,16 @@ export const PublishApprovalModalContent = forwardRef<PublishApprovalModalHandle
|
||||
/></Row>
|
||||
</>
|
||||
}
|
||||
<Row className="mt-mbase pb-[8px] h-[32px] font-bold" ><span >{$t('策略列表')}:</span></Row>
|
||||
<Row className="mb-mbase ">
|
||||
<Table
|
||||
bordered={true}
|
||||
columns={translatedPolicyColumns}
|
||||
size="small"
|
||||
rowKey="id"
|
||||
dataSource={data.diffs?.strategies || []}
|
||||
pagination={false}
|
||||
/></Row>
|
||||
{/* <Form.Item
|
||||
label={$t("备注")}
|
||||
name="remark"
|
||||
|
||||
@@ -37,6 +37,8 @@ const TableIconName = {
|
||||
const TableBtnWithPermission = ({ btnTitle, access, tooltip, disabled, navigateTo, onClick, className, btnType }: TableBtnWithPermissionProps) => {
|
||||
|
||||
const [btnAccess, setBtnAccess] = useState<boolean>(false)
|
||||
const [btnStatus, setBtnStatus] = useState<boolean>(false)
|
||||
const [closeToolTip, setCloseToolTip] = useState<boolean>(false)
|
||||
const { accessData, checkPermission, accessInit } = useGlobalContext()
|
||||
const navigate = useNavigate()
|
||||
const lastAccess = useMemo(() => {
|
||||
@@ -52,16 +54,27 @@ const TableBtnWithPermission = ({ btnTitle, access, tooltip, disabled, navigateT
|
||||
|
||||
const handleClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
setTimeout(() => {
|
||||
setBtnStatus(false)
|
||||
setCloseToolTip(true)
|
||||
})
|
||||
|
||||
navigateTo ? navigate(navigateTo) : onClick?.()
|
||||
}, [navigateTo, navigate, onClick])
|
||||
|
||||
const changeTooltipStatus = (open: boolean) => {
|
||||
setBtnStatus(open)
|
||||
if (closeToolTip) {
|
||||
setBtnStatus(false)
|
||||
setCloseToolTip(false)
|
||||
}
|
||||
}
|
||||
return (<>{
|
||||
!btnAccess || (disabled && tooltip) ?
|
||||
<Tooltip placement="top" title={tooltip ?? $t('暂无(0)权限,请联系管理员分配。', [$t(btnTitle).toLowerCase()])}>
|
||||
<Button type="text" disabled={true} className={`h-[22px] border-none p-0 flex items-center bg-transparent ${className}`} key={btnType} icon={<Icon icon={TableIconName[btnType as keyof typeof TableIconName]} width="18" height="18" />} >{ }</Button>
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip placement="top" title={$t(btnTitle)}>
|
||||
<Tooltip placement="top" title={$t(btnTitle)} trigger='hover' open={btnStatus} onOpenChange={changeTooltipStatus}>
|
||||
<Button type="text" disabled={disabled} className={`h-[22px] border-none p-0 flex items-center bg-transparent ${className} `} key={btnType} icon={<Icon icon={TableIconName[btnType as keyof typeof TableIconName]} width="18" height="18" />} onClick={handleClick}>{ }</Button>
|
||||
</Tooltip>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Radio, DatePicker, GetProps, RadioChangeEvent } from 'antd';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
@@ -12,69 +12,80 @@ export type RangeValue = [Dayjs | null, Dayjs | null] | null;
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
export type TimeRange = {
|
||||
start:number|null
|
||||
end:number|null
|
||||
start: number | null
|
||||
end: number | null
|
||||
}
|
||||
|
||||
export type TimeRangeButton = ''| 'hour' | 'day' | 'threeDays' | 'sevenDays';
|
||||
export type TimeRangeButton = '' | 'hour' | 'day' | 'threeDays' | 'sevenDays';
|
||||
|
||||
type TimeRangeSelectorProps = {
|
||||
initialTimeButton?:TimeRangeButton,
|
||||
initialDatePickerValue?:RangeValue
|
||||
onTimeRangeChange?:(timeRange:TimeRange) =>void
|
||||
hideTitle?:boolean
|
||||
onTimeButtonChange:(time:TimeRangeButton) =>void
|
||||
labelSize?:'small'|'default'
|
||||
}
|
||||
const TimeRangeSelector = (props:TimeRangeSelectorProps) => {
|
||||
const {initialTimeButton,initialDatePickerValue,onTimeRangeChange,hideTitle,onTimeButtonChange,labelSize='default'} = props
|
||||
initialTimeButton?: TimeRangeButton,
|
||||
initialDatePickerValue?: RangeValue
|
||||
onTimeRangeChange?: (timeRange: TimeRange) => void
|
||||
hideTitle?: boolean
|
||||
onTimeButtonChange: (time: TimeRangeButton) => void
|
||||
labelSize?: 'small' | 'default'
|
||||
bindRef?: any
|
||||
hideBtns?: TimeRangeButton[]
|
||||
defaultTimeButton?: TimeRangeButton
|
||||
}
|
||||
const TimeRangeSelector = (props: TimeRangeSelectorProps) => {
|
||||
const { initialTimeButton, initialDatePickerValue, onTimeRangeChange, hideTitle, onTimeButtonChange, labelSize = 'default', bindRef, hideBtns = [], defaultTimeButton = 'hour' } = props
|
||||
const [timeButton, setTimeButton] = useState(initialTimeButton || '');
|
||||
const [datePickerValue, setDatePickerValue] = useState<RangeValue>(initialDatePickerValue || [null,null]);
|
||||
|
||||
const [datePickerValue, setDatePickerValue] = useState<RangeValue>(initialDatePickerValue || [null, null]);
|
||||
useEffect(() => {
|
||||
if (bindRef) {
|
||||
bindRef({ reset });
|
||||
}
|
||||
}, [bindRef])
|
||||
// 根据选择的时间范围计算开始和结束时间
|
||||
const calculateTimeRange = (curBtn:'hour'|'day'|'threeDays'|'sevenDays') => {
|
||||
const currentSecond = new Date().getTime() // 当前毫秒数时间戳
|
||||
const currentMin = currentSecond - (currentSecond % (60 * 1000)) // 当前分钟数时间戳
|
||||
let startMin = currentMin - 60 * 60 * 1000
|
||||
const calculateTimeRange = (curBtn: TimeRangeButton) => {
|
||||
const currentSecond = Math.floor(Date.now() / 1000); // 当前秒级时间戳
|
||||
let startMin = currentSecond - 60 * 60
|
||||
switch (curBtn) {
|
||||
case 'hour': {
|
||||
startMin = currentMin - 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'day': {
|
||||
startMin = currentMin - 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'threeDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
2 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'sevenDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
6 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'hour': {
|
||||
startMin = currentSecond - 60 * 60
|
||||
break
|
||||
}
|
||||
case 'day': {
|
||||
startMin = currentSecond - 24 * 60 * 60
|
||||
break
|
||||
}
|
||||
case 'threeDays': {
|
||||
startMin =
|
||||
Math.floor(new Date().setHours(0, 0, 0, 0) / 1000) -
|
||||
2 * 24 * 60 * 60
|
||||
break
|
||||
}
|
||||
case 'sevenDays': {
|
||||
startMin =
|
||||
Math.floor(new Date().setHours(0, 0, 0, 0) / 1000) -
|
||||
6 * 24 * 60 * 60
|
||||
break
|
||||
}
|
||||
}
|
||||
if (onTimeRangeChange) {
|
||||
onTimeRangeChange({ start: startMin / 1000, end: currentMin / 1000 });
|
||||
onTimeRangeChange({ start: startMin, end: currentSecond });
|
||||
}
|
||||
};
|
||||
|
||||
// 处理单选按钮的变化
|
||||
const handleRadioChange = (e:RadioChangeEvent) => {
|
||||
const handleRadioChange = (e: RadioChangeEvent) => {
|
||||
setTimeButton(e.target.value);
|
||||
onTimeButtonChange?.(e.target.value)
|
||||
setDatePickerValue(null)
|
||||
calculateTimeRange(e.target.value);
|
||||
};
|
||||
const reset = () => {
|
||||
setTimeButton(defaultTimeButton)
|
||||
calculateTimeRange(defaultTimeButton)
|
||||
setDatePickerValue(null)
|
||||
}
|
||||
|
||||
// 处理日期选择器的变化
|
||||
const handleDatePickerChange = (dates: RangeValue) => {
|
||||
setTimeButton(dates ? '' : 'hour')
|
||||
onTimeButtonChange?.(dates ? '' : 'hour')
|
||||
setTimeButton(dates ? '' : defaultTimeButton)
|
||||
onTimeButtonChange?.(dates ? '' : defaultTimeButton)
|
||||
setDatePickerValue(dates);
|
||||
if (dates && Array.isArray(dates) && dates.length === 2) {
|
||||
const [startDate, endDate] = dates;
|
||||
@@ -84,34 +95,37 @@ const TimeRangeSelector = (props:TimeRangeSelectorProps) => {
|
||||
onTimeRangeChange({ start, end });
|
||||
}
|
||||
}
|
||||
if (!dates) {
|
||||
calculateTimeRange(defaultTimeButton)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
||||
// Can not select days before today and today
|
||||
|
||||
|
||||
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
||||
// Can not select days before today and today
|
||||
return current && current.valueOf() > dayjs().startOf('day').valueOf();
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-nowrap items-center pt-btnybase mr-btnybase">
|
||||
{!hideTitle && <label className={`whitespace-nowrap `}>{$t('时间')}:</label>}
|
||||
<Radio.Group className="whitespace-nowrap" value={timeButton} onChange={handleRadioChange} buttonStyle="solid">
|
||||
<Radio.Button value="hour">{$t('近1小时')}</Radio.Button>
|
||||
<Radio.Button value="day">{$t('近24小时')}</Radio.Button>
|
||||
<Radio.Button value="threeDays">{$t('近3天')}</Radio.Button>
|
||||
<Radio.Button className="rounded-e-none" value="sevenDays">{$t('近7天')}</Radio.Button>
|
||||
</Radio.Group>
|
||||
{!hideTitle && <label className={`whitespace-nowrap `}>{$t('时间')}:</label>}
|
||||
<Radio.Group className="whitespace-nowrap" value={timeButton} onChange={handleRadioChange} buttonStyle="solid">
|
||||
{hideBtns?.length && hideBtns.includes('hour') ? null : <Radio.Button value="hour">{$t('近1小时')}</Radio.Button>}
|
||||
{hideBtns?.length && hideBtns.includes('day') ? null : <Radio.Button value="day">{$t('近24小时')}</Radio.Button>}
|
||||
{hideBtns?.length && hideBtns.includes('threeDays') ? null : <Radio.Button value="threeDays">{$t('近3天')}</Radio.Button>}
|
||||
{hideBtns?.length && hideBtns.includes('sevenDays') ? null : <Radio.Button className="rounded-e-none" value="sevenDays">{$t('近7天')}</Radio.Button>}
|
||||
</Radio.Group>
|
||||
<DatePicker.RangePicker
|
||||
value={datePickerValue}
|
||||
className="rounded-s-none ml-[-1px]"
|
||||
className="rounded-s-none ml-[-1px]"
|
||||
disabledDate={disabledDate}
|
||||
onChange={handleDatePickerChange}
|
||||
onOpenChange={(open)=>{
|
||||
if(!open && datePickerValue && datePickerValue.length > 2){
|
||||
setTimeButton('')
|
||||
onTimeButtonChange?.('')
|
||||
}
|
||||
onOpenChange={(open) => {
|
||||
if (!open && datePickerValue && datePickerValue.length > 2) {
|
||||
setTimeButton('')
|
||||
onTimeButtonChange?.('')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -163,6 +163,28 @@ export const TranslateWord = ()=>{
|
||||
{$t('优先级')}
|
||||
{$t('筛选条件')}
|
||||
{$t('处理数')}
|
||||
{$t('数据格式')}
|
||||
{$t('关键字')}
|
||||
{$t('正则表达式')}
|
||||
{$t('手机号')}
|
||||
{$t('身份证号')}
|
||||
{$t('银行卡号')}
|
||||
{$t('金额')}
|
||||
{$t('日期')}
|
||||
{$t('局部显示')}
|
||||
{$t('局部遮蔽')}
|
||||
{$t('截取')}
|
||||
{$t('替换')}
|
||||
{$t('乱序')}
|
||||
{$t('随机字符串')}
|
||||
{$t('自定义字符串')}
|
||||
{$t('请输入IP地址或CIDR范围,每条以换行分割')}
|
||||
{$t('待更新')}
|
||||
{$t('待删除')}
|
||||
{$t('内容')}
|
||||
{$t('调用地址')}
|
||||
{$t('消费者 IP')}
|
||||
{$t('鉴权名称')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { set } from 'lodash-es';
|
||||
import { ExoticComponent, JSXElementConstructor, ReactElement, useEffect, useState } from 'react';
|
||||
import { useBlocker, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { JSX } from 'react/jsx-runtime';
|
||||
|
||||
const withRouteGuard = (WrappedComponent: ExoticComponent<any> | JSXElementConstructor<any>, {
|
||||
canActivate,
|
||||
canLoad ,
|
||||
canDeactivate,
|
||||
deactivated,
|
||||
pathPrefix
|
||||
}: { pathPrefix?:string, canActivate?: () => Promise<boolean>; canLoad?: () => Promise<boolean>; canDeactivate?: () => Promise<boolean>; deactivated?: () => Promise<void>; } = {}) => {
|
||||
return function RouteGuard(props: JSX.IntrinsicAttributes) {
|
||||
const [isActivated, setIsActivated] = useState<boolean>(false);
|
||||
const location = useLocation();
|
||||
// check canActivate
|
||||
const startLifecycle = async ()=>{
|
||||
if(canActivate){
|
||||
const activateRes = await canActivate();
|
||||
setIsActivated(activateRes);
|
||||
}else{
|
||||
setIsActivated(true);
|
||||
}
|
||||
}
|
||||
|
||||
// check canDeactivate
|
||||
const handleBeforeUnload =async (event: { preventDefault: () => void; returnValue: string; }) => {
|
||||
const deactivateRes = canDeactivate? await canDeactivate():true;
|
||||
if (!deactivateRes) {
|
||||
event.preventDefault();
|
||||
event.returnValue = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 激活组件时的检查
|
||||
useEffect(() => {
|
||||
startLifecycle();
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
deactivated?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
const blocker = useBlocker((tx) => {
|
||||
const currentPath = location.pathname;
|
||||
const targetPath = tx.nextLocation.pathname;
|
||||
|
||||
if (pathPrefix && currentPath.startsWith(pathPrefix) && !targetPath.startsWith(pathPrefix) && canDeactivate) {
|
||||
canDeactivate().then((res) => {
|
||||
if(res){
|
||||
return false;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const checkCanLoad = async()=>{
|
||||
const loadRes = await canLoad!();
|
||||
!loadRes && setIsActivated(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (isActivated && canLoad) {
|
||||
checkCanLoad()
|
||||
}
|
||||
}, [isActivated]);
|
||||
|
||||
return isActivated ? <WrappedComponent {...props}/> : null;
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouteGuard;
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
UPDATE_DATASETS_EVENT_EMITTER,
|
||||
UPDATE_HISTORY_EVENT_EMITTER,
|
||||
} from './constants'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
export type PromptEditorProps = {
|
||||
instanceId?: string
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import { $splitNodeContainingQuery } from '../../utils'
|
||||
import { useOptions } from './hooks'
|
||||
import type { PickerBlockMenuOption } from './menu'
|
||||
// import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
type ComponentPickerProps = {
|
||||
triggerString: string
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { DELETE_CONTEXT_BLOCK_COMMAND } from './index'
|
||||
// PortalToFollowElemContent,
|
||||
// PortalToFollowElemTrigger,
|
||||
// } from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
import { $t } from '@common/locales'
|
||||
|
||||
type ContextBlockComponentProps = {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { DELETE_HISTORY_BLOCK_COMMAND } from './index'
|
||||
// PortalToFollowElemContent,
|
||||
// PortalToFollowElemTrigger,
|
||||
// } from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
import { $t } from '@common/locales'
|
||||
|
||||
type HistoryBlockComponentProps = {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
||||
import { textToEditorState } from '../utils'
|
||||
import { CustomTextNode } from './custom-text/node'
|
||||
import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'
|
||||
export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface CodeboxApiRef {
|
||||
formatCode: () => void
|
||||
}
|
||||
|
||||
export type codeBoxLanguagesType = 'html' | 'json' | 'xml' | 'javascript' | 'css' | 'plaintext'|'yaml'
|
||||
interface CodeboxProps {
|
||||
options?: MonacoEditor.IStandaloneEditorConstructionOptions
|
||||
value?: string
|
||||
@@ -22,7 +23,7 @@ interface CodeboxProps {
|
||||
height?: string | null
|
||||
readOnly?: boolean
|
||||
apiRef?: RefObject<CodeboxApiRef>
|
||||
language?: 'html' | 'json' | 'xml' | 'javascript' | 'css' | 'plaintext'|'yaml'
|
||||
language?: codeBoxLanguagesType
|
||||
extraContent?:React.ReactNode
|
||||
sx?:Record<string,unknown>
|
||||
editorTheme?:'vs' | 'vs-dark' | 'hc-black'
|
||||
|
||||
@@ -295,7 +295,7 @@ export interface IconParkIconElement extends HTMLElement {
|
||||
| 'apispace'
|
||||
| 'auto-generate-api'
|
||||
| 'compare-api'
|
||||
| 'multi-protocal'
|
||||
| 'multi-protocol'
|
||||
| 'read-good'
|
||||
| 'richdoc'
|
||||
| 'mockapi'
|
||||
|
||||
@@ -241,6 +241,26 @@ export const ApprovalRouteColumns = [
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
export const ApprovalPolicyColumns = [
|
||||
{
|
||||
title:('名称'),
|
||||
dataIndex:'name',
|
||||
ellipsis:true,
|
||||
},
|
||||
{
|
||||
title:('优先级'),
|
||||
dataIndex:'priority',
|
||||
ellipsis:true
|
||||
},
|
||||
{
|
||||
title:('状态'),
|
||||
dataIndex:'status',
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
export const ApprovalUpstreamColumns = [
|
||||
{
|
||||
title:('上游类型'),
|
||||
|
||||
@@ -67,6 +67,7 @@ export type PublishApprovalInfoType = {
|
||||
diffs:{
|
||||
apis:PublishApprovalApiItem[]
|
||||
upstreams:PublishApprovalUpstreamItem[]
|
||||
strategies:Array<{name:string, priority:number,statues:0|1}>
|
||||
}
|
||||
clusterPublishStatus?:SystemInsidePublishOnlineItems[],
|
||||
error:string
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { $t } from '@common/locales'
|
||||
import { StrategyStatusColorClass, StrategyStatusEnum } from './policy/consts'
|
||||
|
||||
export type BasicResponse<T> = {
|
||||
code:number
|
||||
@@ -5,7 +7,6 @@ export type BasicResponse<T> = {
|
||||
msg:string
|
||||
}
|
||||
|
||||
|
||||
export const STATUS_CODE = {
|
||||
SUCCESS:0,
|
||||
UNANTHORIZED:401,
|
||||
@@ -18,7 +19,7 @@ export const STATUS_COLOR = {
|
||||
}
|
||||
|
||||
|
||||
// avoid changing route within ths same category
|
||||
// TODO should be generated dynamically
|
||||
export const routerKeyMap = new Map<string, string[]|string>([
|
||||
['workspace',['consumer','service','team','guide']],
|
||||
['my',['consumer','service','team']],
|
||||
@@ -29,6 +30,7 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
['maintenanceCenter',['aisetting','datasourcing','cluster','cert','logsettings','resourcesettings','openapi']
|
||||
]])
|
||||
|
||||
|
||||
|
||||
export const COLUMNS_TITLE = {
|
||||
operate : ''
|
||||
@@ -45,6 +47,7 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
startWithAlphabet:('英文数字下划线任意一种,首字母必须为英文'),
|
||||
specialStartWithAlphabet:('支持字母开头、英文数字中横线下划线组合'),
|
||||
onlyAlphabet:('字符非法,仅支持英文'),
|
||||
ipAndCidr:'请输入IP地址或CIDR范围,每条以换行分割'
|
||||
}
|
||||
|
||||
export const FORM_ERROR_TIPS = {
|
||||
@@ -73,4 +76,33 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
export const DATA_SHOW_TYPE_OPTIONS = [
|
||||
{label:'列表', value:'list'},
|
||||
{label:'块', value:'block'},
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
export const PolicyPublishColumns = [
|
||||
|
||||
{
|
||||
title: ('策略名称'),
|
||||
dataIndex: 'name',
|
||||
ellipsis: true,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: ('优先级'),
|
||||
dataIndex: 'priority',
|
||||
width: 140,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('状态'),
|
||||
dataIndex: 'status',
|
||||
width: 140,
|
||||
render:(text:string)=> <span className={StrategyStatusColorClass[text as keyof typeof StrategyStatusColorClass]}>{$t(StrategyStatusEnum[text as keyof typeof StrategyStatusEnum])}</span>,
|
||||
},
|
||||
{
|
||||
title: ('更新时间'),
|
||||
dataIndex: 'optTime',
|
||||
width: 182,
|
||||
ellipsis: true,
|
||||
},
|
||||
]
|
||||
@@ -239,6 +239,31 @@ export const PERMISSION_DEFINITION = [
|
||||
"anyOf": [{ "backend": ["system.settings.log_configuration.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.view"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.publish": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.workspace.application.view_all": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.view_all"] }]
|
||||
@@ -429,6 +454,31 @@ export const PERMISSION_DEFINITION = [
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.team.service.manager","team.service.service.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.publish": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.view_all","team.consumer.subscription.view_subscribed_service"] }]
|
||||
@@ -436,17 +486,17 @@ export const PERMISSION_DEFINITION = [
|
||||
},
|
||||
"team.application.subscription.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.subscription.subscribe"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.subscription.subscribe"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.subscription.manager_subscribed_services"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.subscription.manager_subscribed_services"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.team.consumer.subscription.manager_subscribed_services"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.team.consumer.subscription.manager_subscribed_services"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.view": {
|
||||
@@ -456,47 +506,47 @@ export const PERMISSION_DEFINITION = [
|
||||
},
|
||||
"team.application.application.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.consumer.authorization.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","system.workspace.application.view_all","team.consumer.authorization.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","system.workspace.application.view_all","team.consumer.authorization.view"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.cancelSubApply": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.cancelSub": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.team.team.view": {
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
system:
|
||||
- name: organization
|
||||
cname: '组织管理'
|
||||
value: 'organization'
|
||||
children:
|
||||
- name: member
|
||||
cname: '成员'
|
||||
value: 'member'
|
||||
access:
|
||||
- system.settings.account.view
|
||||
- system.organization.member.add
|
||||
- system.organization.member.edit
|
||||
- system.organization.member.delete
|
||||
- system.organization.member.block
|
||||
- system.organization.member.department.add
|
||||
- system.organization.member.department.edit
|
||||
- system.organization.member.department.delete
|
||||
- name: team_manager
|
||||
cname: '团队管理'
|
||||
desc: '团队管理'
|
||||
- system.workspace.team.view_all
|
||||
- system.organization.team.add
|
||||
- system.organization.team.edit
|
||||
- system.organization.team.delete
|
||||
- system.organization.team.running
|
||||
- name: role_manager
|
||||
cname: '角色管理'
|
||||
desc: '角色管理'
|
||||
- system.organization.role.view
|
||||
- system.organization.role.system.view
|
||||
- system.organization.role.system.add
|
||||
- system.organization.role.system.edit
|
||||
- system.organization.role.system.delete
|
||||
- system.organization.role.team.view
|
||||
- system.organization.role.team.add
|
||||
- system.organization.role.team.edit
|
||||
- system.organization.role.team.delete
|
||||
- name: API Market
|
||||
cname: 'API市场'
|
||||
value: 'api_market'
|
||||
children:
|
||||
- name: service classification
|
||||
cname: '服务分类'
|
||||
value: 'service_classification'
|
||||
children:
|
||||
- system.api_market.service_classification.view
|
||||
- system.api_market.service_classification.add
|
||||
- system.api_market.service_classification.edit
|
||||
- system.api_market.service_classification.delete
|
||||
- name: devops
|
||||
cname: 运维
|
||||
value: 'devops'
|
||||
children:
|
||||
- name: cluster
|
||||
cname: 集群
|
||||
value: 'cluster'
|
||||
children:
|
||||
- system.settings.api_gateway.view
|
||||
- system.devops.cluster.add
|
||||
- system.devops.cluster.edit
|
||||
- system.devops.cluster.delete
|
||||
- name: ssl certificate
|
||||
cname: 证书
|
||||
value: 'ssl_certificate'
|
||||
children:
|
||||
- system.settings.ssl_certificate.view
|
||||
- system.devops.ssl_certificate.add
|
||||
- system.devops.ssl_certificate.edit
|
||||
- system.devops.ssl_certificate.delete
|
||||
- name: log configuration
|
||||
cname: 日志
|
||||
value: 'log_configuration'
|
||||
children:
|
||||
- system.settings.log_configuration.view
|
||||
- system.devops.log_configuration.add
|
||||
- system.devops.log_configuration.edit
|
||||
- system.devops.log_configuration.publish
|
||||
- system.devops.log_configuration.delete
|
||||
- name: workspace
|
||||
cname: 工作空间
|
||||
value: 'workspace'
|
||||
children:
|
||||
- name: application
|
||||
cname: 应用
|
||||
value: 'application'
|
||||
children:
|
||||
- system.workspace.application.view_all
|
||||
- name: service
|
||||
cname: 服务
|
||||
value: 'service'
|
||||
children:
|
||||
- system.workspace.service.view_all
|
||||
- name: team
|
||||
cname: 团队
|
||||
value: 'team'
|
||||
children:
|
||||
- system.workspace.team.view_all
|
||||
- name: api market
|
||||
cname: API市场
|
||||
value: 'api_market'
|
||||
children:
|
||||
- system.api_portal.api_portal.view
|
||||
team:
|
||||
- name: service
|
||||
cname: 服务
|
||||
value: 'service'
|
||||
children:
|
||||
- name: api
|
||||
cname: API
|
||||
value: 'api'
|
||||
children:
|
||||
- team.service.api_doc.view
|
||||
- team.service.api_doc.add
|
||||
- team.service.api_doc.edit
|
||||
- name: route
|
||||
cname: route
|
||||
value: 'route'
|
||||
children:
|
||||
- team.service.router.view
|
||||
- team.service.router.add
|
||||
- team.service.router.edit
|
||||
- team.service.router.delete
|
||||
- name: upstream
|
||||
cname: 上游
|
||||
value: 'upstream'
|
||||
children:
|
||||
- team.service.upstream.view
|
||||
- team.service.upstream.add
|
||||
- team.service.upstream.edit
|
||||
- team.service.upstream.delete
|
||||
- name: release
|
||||
cname: 发布
|
||||
value: 'release'
|
||||
children:
|
||||
- team.service.release.view
|
||||
- team.service.release.add
|
||||
- team.service.release.rollback
|
||||
- team.service.release.delete
|
||||
- team.service.release.approval
|
||||
- team.service.release.online
|
||||
- team.service.release.cancel
|
||||
- team.service.release.stop
|
||||
- name: subscription management
|
||||
cname: 订阅方管理
|
||||
value: 'subscription'
|
||||
children:
|
||||
- team.service.subscription.view
|
||||
- team.service.subscription.approval
|
||||
- team.service.subscription.add
|
||||
- team.service.subscription.delete
|
||||
- name: service
|
||||
cname: 服务管理
|
||||
value: 'service'
|
||||
children:
|
||||
- team.service.service.view
|
||||
- team.service.service.add
|
||||
- team.service.service.edit
|
||||
- team.service.service.delete
|
||||
- name: application
|
||||
cname: 应用
|
||||
value: 'application'
|
||||
children:
|
||||
- name: subscription Service
|
||||
cname: 订阅服务
|
||||
value: 'subscription'
|
||||
children:
|
||||
- team.application.subscription.view
|
||||
- team.application.subscription.add
|
||||
- team.application.subscription.edit
|
||||
- team.application.subscription.delete
|
||||
- name: authorization
|
||||
cname: 访问授权
|
||||
value: 'authorization'
|
||||
children:
|
||||
- team.consumer.authorization.view
|
||||
- team.consumer.authorization.manager
|
||||
- team.application.authorization.add
|
||||
- team.application.authorization.edit
|
||||
- team.application.authorization.delete
|
||||
- name: application
|
||||
cname: 应用
|
||||
value: 'application'
|
||||
children:
|
||||
- team.application.application.view
|
||||
- team.application.application.add
|
||||
- team.application.application.edit
|
||||
- team.application.application.delete
|
||||
- name: team
|
||||
cname: 团队
|
||||
value: 'team'
|
||||
children:
|
||||
- name: member
|
||||
cname: 成员
|
||||
value: 'member'
|
||||
children:
|
||||
- team.team.member.view
|
||||
- team.team.member.add
|
||||
- team.team.member.edit
|
||||
- name: team
|
||||
cname: 团队管理
|
||||
value: 'team'
|
||||
children:
|
||||
- team.team.team.view
|
||||
- team.team.team.edit
|
||||
@@ -0,0 +1,88 @@
|
||||
import { codeBoxLanguagesType } from "@common/components/postcat/api/Codebox";
|
||||
|
||||
export const MatchRules = [
|
||||
{ value: 'inner', label: '数据格式' },
|
||||
{ value: 'keyword', label: '关键字' },
|
||||
{ value: 'regex', label: '正则表达式' },
|
||||
{ value: 'json_path', label: 'JSON Path' }
|
||||
];
|
||||
|
||||
|
||||
export const DataFormatOptions = [
|
||||
{ label: '姓名', value: 'name' },
|
||||
{ label: '手机号', value: 'phone' },
|
||||
{ label: '身份证号', value: 'id-card' },
|
||||
{ label: '银行卡号', value: 'bank-card' },
|
||||
{ label: '日期', value: 'date' },
|
||||
{ label: '金额', value: 'amount' }
|
||||
];
|
||||
|
||||
|
||||
export const DataMaskBaseOptionOptions = [
|
||||
{ value: 'partial-display', label: '局部显示' },
|
||||
{ value: 'partial-masking', label: '局部遮蔽' },
|
||||
{ value: 'truncation', label: '截取' },
|
||||
{ value: 'replacement', label: '替换' },
|
||||
];
|
||||
|
||||
|
||||
export const DataMaskOrderOptions = [
|
||||
...DataMaskBaseOptionOptions,
|
||||
{ label: '乱序', value: 'shuffling' }
|
||||
]
|
||||
|
||||
|
||||
export const DataMaskReplaceStrOptions = [
|
||||
{ value: 'random', label: '随机字符串' },
|
||||
{ value: 'custom', label: '自定义字符串' }
|
||||
];
|
||||
|
||||
|
||||
export const PolicyOptions = [
|
||||
{label:'数据脱敏',value:'data-masking'},
|
||||
]
|
||||
|
||||
export const StrategyStatusEnum = {
|
||||
'update':'待更新',
|
||||
'online':'已发布',
|
||||
'offline':'未发布',
|
||||
"delete":'待删除',
|
||||
}
|
||||
|
||||
export const StrategyStatusColorClass = {
|
||||
"online":'text-status_success',
|
||||
"update":'text-status_pending',
|
||||
"offline":'text-status_fail',
|
||||
"delete":'text-status_offline',
|
||||
}
|
||||
|
||||
export const contentTypeToLanguageMap: Record<string, codeBoxLanguagesType> = {
|
||||
// JSON
|
||||
"application/json": "json",
|
||||
|
||||
// XML
|
||||
"application/xml": "xml",
|
||||
"text/xml": "xml",
|
||||
|
||||
// HTML
|
||||
"text/html": "html",
|
||||
|
||||
// Plain text
|
||||
"text/plain": "plaintext",
|
||||
|
||||
// JavaScript
|
||||
"application/javascript": "javascript",
|
||||
"text/javascript": "javascript",
|
||||
|
||||
// CSS
|
||||
"text/css": "css",
|
||||
|
||||
// YAML
|
||||
"application/x-yaml": "yaml",
|
||||
"text/yaml": "yaml",
|
||||
|
||||
// Others (fallback)
|
||||
"*/*": "plaintext", // 任意类型默认处理为普通文本
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import { DefaultOptionType } from "antd/es/select";
|
||||
import { StrategyStatusEnum } from "./consts";
|
||||
import { EntityItem } from "../type";
|
||||
|
||||
export type DataMaskRuleTableProps = {
|
||||
disabled?: boolean;
|
||||
value?: MaskRuleData[];
|
||||
onChange?: (value: MaskRuleData[]) => void;
|
||||
}
|
||||
|
||||
|
||||
export type MaskRuleData = {
|
||||
match: {
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
mask: {
|
||||
type: string;
|
||||
begin?: number;
|
||||
length?: number;
|
||||
replace?: {
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
};
|
||||
eoKey?: string;
|
||||
}
|
||||
|
||||
export type DataMaskRuleFormProps = {
|
||||
editData?: MaskRuleData;
|
||||
ruleList: MaskRuleData[];
|
||||
onSave: (ruleList: MaskRuleData[]) => void;
|
||||
onClose: () => void;
|
||||
modalVisible:boolean
|
||||
}
|
||||
|
||||
|
||||
export type DataMaskingConfigHandle = {
|
||||
save: (values: any) => void
|
||||
}
|
||||
|
||||
export type PolicyMatchType = {name:string, values:string[], label?:string, title?:string, type?:string}
|
||||
|
||||
export type DataMaskingRulesType = {}
|
||||
|
||||
export type DataMaskingConfigFieldType = {
|
||||
id:string
|
||||
name:string
|
||||
priority:number
|
||||
description:string
|
||||
filters:PolicyMatchType[]
|
||||
config:{
|
||||
rules:DataMaskingRulesType
|
||||
}
|
||||
}
|
||||
|
||||
export type DataMaskStrategyItem = {
|
||||
id:string
|
||||
name:string
|
||||
priority:number
|
||||
isStop:boolean
|
||||
isDelete:boolean
|
||||
publishStatus:keyof typeof StrategyStatusEnum
|
||||
filters:string
|
||||
conf:string
|
||||
updater:EntityItem
|
||||
updateTime:string
|
||||
}
|
||||
export type DataMaskLogItem = {
|
||||
id:string
|
||||
service: {
|
||||
id:string
|
||||
name:string
|
||||
}
|
||||
method:string
|
||||
url:string
|
||||
remote_ip:string
|
||||
consumer: {
|
||||
id:string
|
||||
name:string
|
||||
}
|
||||
authorization:string
|
||||
record_time:string
|
||||
}
|
||||
|
||||
|
||||
export type FilterFormField= {
|
||||
name: string;
|
||||
values:string[] |string;
|
||||
label:string
|
||||
title:string
|
||||
}
|
||||
|
||||
export type FilterOptionType = {
|
||||
name:string
|
||||
pattern:string
|
||||
title:string
|
||||
type:'remote'|'pattern'|'static'
|
||||
options:string[]
|
||||
}
|
||||
|
||||
|
||||
export type FilterTableProps = {
|
||||
disabled?: boolean;
|
||||
drawerTitle?: string;
|
||||
value?:FilterFormField[];
|
||||
onChange?:(val:FilterFormField[])=>void
|
||||
}
|
||||
|
||||
export type FilterFormType = {
|
||||
name:string
|
||||
values:unknown
|
||||
type?:string
|
||||
}
|
||||
|
||||
export type FilterFormProps = {
|
||||
filterForm: FilterFormType;
|
||||
filterOptions:DefaultOptionType[];
|
||||
selectedOptionNameSet: Set<string>;
|
||||
disabled: boolean;
|
||||
onFilterFormChange: (form: FilterFormType) => void;
|
||||
setFormCanSubmit:(canSubmit:boolean)=>void
|
||||
serviceId?:string
|
||||
teamId?:string
|
||||
}
|
||||
|
||||
export type FilterFormHandle = {
|
||||
clear:()=>void
|
||||
save:()=>Promise<FilterFormField>
|
||||
}
|
||||
|
||||
export type FilterFormItemProps = {
|
||||
value?: string[];
|
||||
onChange?: (value: string[]) => void;
|
||||
disabled:boolean
|
||||
option:unknown
|
||||
onShowValueChange?:(value:string)=>void
|
||||
serviceId?:string
|
||||
teamId?:string
|
||||
}
|
||||
|
||||
export type RemoteTitleType = {
|
||||
title:string
|
||||
field:string
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import { FC, ReactElement, ReactNode } from "react"
|
||||
import { PERMISSION_DEFINITION } from "./permissions"
|
||||
import { MatchPositionEnum, MatchTypeEnum } from "@core/const/system/const"
|
||||
import usePluginLoader from "@common/hooks/pluginLoader"
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext"
|
||||
import { StrategyStatusEnum } from "./policy/consts"
|
||||
|
||||
export type UserInfoType = {
|
||||
username: string
|
||||
@@ -8,7 +12,6 @@ export type UserInfoType = {
|
||||
phone: string
|
||||
avatar: string
|
||||
type:string
|
||||
|
||||
}
|
||||
|
||||
export type UserProfileProps = {
|
||||
@@ -100,4 +103,112 @@ export type SimpleMemberItem = {
|
||||
email:string
|
||||
department:string
|
||||
avatar:string
|
||||
}
|
||||
|
||||
|
||||
export type RouteConfig = {
|
||||
path:string
|
||||
pathPrefix?:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
data?:Record<string, string>
|
||||
lifecycle?:{
|
||||
canActivate?:()=>Promise<boolean>
|
||||
canLoad?:()=>Promise<boolean>
|
||||
canDeactivate?:()=>Promise<boolean>
|
||||
deactivated?:()=>Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
routeId:string
|
||||
policyId:string
|
||||
}
|
||||
|
||||
|
||||
export type PluginRouterConfig = {
|
||||
name:string
|
||||
path:string;
|
||||
type:string;
|
||||
expose?:string
|
||||
}
|
||||
|
||||
export type CoreObj = {
|
||||
routerConfig: RouteConfig[];
|
||||
setExecuteList: (param:unknown[])=>void;
|
||||
pluginLoader: {
|
||||
loadModule: (path: string, name: string, expose: string, pluginPath: string) => Promise<any>;
|
||||
};
|
||||
pluginProvider: ReturnType<typeof useGlobalContext>
|
||||
// pluginLifecycleGuard: PluginLifecycleGuard;
|
||||
builtInPluginLoader: (name: string) => any;
|
||||
}
|
||||
|
||||
export type PluginConfigType = {
|
||||
name: string;
|
||||
router: Array<PluginRouterConfig>;
|
||||
path?: string;
|
||||
driver:string
|
||||
}
|
||||
|
||||
|
||||
export type ApiparkPluginDriverType = {
|
||||
[key:string]:{[key:string]:(coreObj?:CoreObj, pluginConfig?:PluginConfigType)=>(CoreObj|undefined)}
|
||||
}
|
||||
|
||||
|
||||
export type RouterMapConfig = {
|
||||
type: 'component' | 'module',
|
||||
component: ReactElement,
|
||||
provider?: FC,
|
||||
lazy?: FC
|
||||
key?: string
|
||||
children?: RouteConfig[]
|
||||
data?:Record<string, string>
|
||||
pathMatch?:string
|
||||
}
|
||||
|
||||
|
||||
export type PolichPublishItemType = {
|
||||
name:string
|
||||
priority:number
|
||||
status:keyof typeof StrategyStatusEnum
|
||||
optTime:string
|
||||
}
|
||||
|
||||
// 发布详情(版本)
|
||||
export type PolicyPublishInfoType = {
|
||||
source:string
|
||||
strategies:Array<PolichPublishItemType>
|
||||
isPublish:boolean
|
||||
versionName:string
|
||||
unpublishMsg:string
|
||||
};
|
||||
|
||||
export type PolicyPublishModalProps = {
|
||||
data:PolicyPublishInfoType
|
||||
}
|
||||
|
||||
export type PolicyPublishModalHandle = {
|
||||
publish:()=>Promise<boolean|string|Record<string, unknown>>
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
import {createContext, Dispatch, FC, ReactNode, useContext, useReducer, useState} from "react";
|
||||
import {createContext, Dispatch, FC, ReactNode, useContext, useEffect, useReducer, useState} from "react";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { App } from "antd";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const";
|
||||
import { checkAccess } from "@common/utils/permission";
|
||||
import { PERMISSION_DEFINITION } from "@common/const/permissions";
|
||||
import { $t } from "@common/locales";
|
||||
|
||||
import { MenuItem } from "@common/utils/navigation";
|
||||
import { ErrorBoundary } from "@ant-design/pro-components";
|
||||
import NotFound from "@common/components/aoplatform/NotFound";
|
||||
import { RouteConfig } from "@common/const/type";
|
||||
import { ProtectedRoute } from "@core/components/aoplatform/RenderRoutes";
|
||||
import Login from "@core/pages/Login";
|
||||
import { useLocaleContext } from "./LocaleContext";
|
||||
import Root from "@core/pages/Root"
|
||||
import DataMaskingCompare from "@core/pages/policy/dataMasking/DataMaskingCompare";
|
||||
interface GlobalState {
|
||||
isAuthenticated: boolean;
|
||||
userData: UserData | null;
|
||||
@@ -14,6 +22,7 @@ interface GlobalState {
|
||||
powered:string;
|
||||
mainPage:string;
|
||||
language:string;
|
||||
pluginsLoaded:boolean
|
||||
}
|
||||
|
||||
interface UserData {
|
||||
@@ -29,8 +38,171 @@ export type GlobalAction =
|
||||
| { type: 'UPDATE_POWER'; powered: string }
|
||||
| { type: 'UPDATE_MAIN_PAGE'; mainPage: string }
|
||||
| { type: 'UPDATE_LANGUAGE'; language: string }
|
||||
| { type: 'SET_PLUGINS_LOADED'; pluginsLoaded: boolean }
|
||||
|
||||
|
||||
const mockData = [
|
||||
{
|
||||
"name": "工作空间",
|
||||
"key": "workspace",
|
||||
"path": "/guide",
|
||||
"icon": "ic:baseline-space-dashboard",
|
||||
"children": [
|
||||
{
|
||||
"name": "首页",
|
||||
"key": "guide",
|
||||
"path": "/guide",
|
||||
"icon": "ic:baseline-home",
|
||||
"access": "all"
|
||||
},
|
||||
{
|
||||
"name": "服务",
|
||||
"key": "service",
|
||||
"path": "/service",
|
||||
"icon": "ic:baseline-blinds-closed",
|
||||
"access": "all"
|
||||
},
|
||||
{
|
||||
"name": "消费者",
|
||||
"key": "consumer",
|
||||
"path": "/consumer",
|
||||
"icon": "ic:baseline-apps",
|
||||
"access": "all"
|
||||
},
|
||||
{
|
||||
"name": "团队",
|
||||
"key": "team",
|
||||
"path": "/team",
|
||||
"icon": "ic:baseline-people-alt",
|
||||
"access": "all"
|
||||
},
|
||||
// {
|
||||
// "name": "路由组件",
|
||||
// "key": "router",
|
||||
// "path": "/router1",
|
||||
// "icon": "ic:baseline-people-alt",
|
||||
// "access": "all"
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "API 市场",
|
||||
"key": "serviceHub",
|
||||
"path": "/serviceHub",
|
||||
"icon": "ic:baseline-hub",
|
||||
"access": "system.api_portal.api_portal.view"
|
||||
},
|
||||
{
|
||||
"name": "仪表盘",
|
||||
"key": "analytics",
|
||||
"path": "/analytics",
|
||||
"icon": "ic:baseline-bar-chart",
|
||||
"children": [
|
||||
{
|
||||
"name": "运行视图",
|
||||
"key": "analytics",
|
||||
"path": "/analytics",
|
||||
"icon": "ic:baseline-bar-chart",
|
||||
"access": "system.analysis.run_view.view"
|
||||
}
|
||||
],
|
||||
"access": "system.analysis.run_view.view"
|
||||
},
|
||||
{
|
||||
"name": "系统设置",
|
||||
"key": "operationCenter",
|
||||
"path": "/commonsetting",
|
||||
"icon": "ic:baseline-settings",
|
||||
"children": [
|
||||
{
|
||||
"name": "系统",
|
||||
"key": "serviceHubSetting",
|
||||
"path": "/commonsetting",
|
||||
"children": [
|
||||
{
|
||||
"name": "常规",
|
||||
"key": "commonsetting",
|
||||
"path": "/commonsetting",
|
||||
"icon": "ic:baseline-hub",
|
||||
"access": "system.api_market.service_classification.view"
|
||||
},
|
||||
{
|
||||
"name": "API 网关",
|
||||
"key": "cluster",
|
||||
"path": "/cluster",
|
||||
"icon": "ic:baseline-device-hub",
|
||||
"access": "system.settings.api_gateway.view"
|
||||
},
|
||||
{
|
||||
"name": "AI 模型",
|
||||
"key": "aisetting",
|
||||
"path": "/aisetting",
|
||||
"icon": "hugeicons:ai-network",
|
||||
"access": "system.settings.ai_provider.view"
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "用户",
|
||||
"key": "organization",
|
||||
"path": "/member",
|
||||
"children": [
|
||||
{
|
||||
"name": "账号",
|
||||
"key": "member",
|
||||
"path": "/member",
|
||||
"icon": "ic:baseline-people-alt",
|
||||
"access": "system.settings.account.view"
|
||||
},
|
||||
{
|
||||
"name": "角色",
|
||||
"key": "role",
|
||||
"path": "/role",
|
||||
"icon": "ic:baseline-verified-user",
|
||||
"access": "system.organization.role.view"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "集成",
|
||||
"key": "maintenanceCenter",
|
||||
"path": "/datasourcing",
|
||||
"children": [
|
||||
{
|
||||
"name": "数据源",
|
||||
"key": "datasourcing",
|
||||
"path": "/datasourcing",
|
||||
"icon": "ic:baseline-monitor-heart",
|
||||
"access": "system.settings.data_source.view"
|
||||
},
|
||||
{
|
||||
"name": "全局策略",
|
||||
"key": "globalpolicy",
|
||||
"path": "/globalpolicy",
|
||||
"icon": "icon-park-solid:exchange-three",
|
||||
"access": "system.settings.data_source.view"
|
||||
},
|
||||
{
|
||||
"name": "证书",
|
||||
"key": "cert",
|
||||
"path": "/cert",
|
||||
"icon": "ic:baseline-security",
|
||||
"access": "system.settings.ssl_certificate.view"
|
||||
},
|
||||
{
|
||||
"name": "日志",
|
||||
"key": "logsettings",
|
||||
"path": "/logsettings",
|
||||
"icon": "ic:baseline-sticky-note-2",
|
||||
"access": "system.settings.log_configuration.view"
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
/*
|
||||
存储用户登录、信息、权限等数据
|
||||
*/
|
||||
@@ -39,9 +211,11 @@ export const GlobalContext = createContext<{
|
||||
dispatch: Dispatch<GlobalAction>;
|
||||
accessData:Map<string,string[]>;
|
||||
pluginAccessDictionary:{[k:string]:string};
|
||||
menuList:MenuItem[];
|
||||
getGlobalAccessData:()=>Promise<{ access:string[]}>;
|
||||
getTeamAccessData:(teamId:string)=>void;
|
||||
getPluginAccessDictionary:(pluginData:{[k:string]:string})=>void
|
||||
getMenuList:()=>void
|
||||
resetAccess:()=>void
|
||||
cleanTeamAccessData:()=>void
|
||||
checkPermission:(access:keyof typeof PERMISSION_DEFINITION[0] | Array<keyof typeof PERMISSION_DEFINITION[0]>)=>boolean
|
||||
@@ -49,6 +223,11 @@ export const GlobalContext = createContext<{
|
||||
accessInit:boolean
|
||||
aiConfigFlushed:boolean
|
||||
setAiConfigFlushed:(flush:boolean)=>void
|
||||
routeConfig: RouteConfig[];
|
||||
setRouterConfig: (isRoot: boolean, config: RouteConfig) => void;
|
||||
addRouteConfig: (parentRoute: RouteConfig, config: RouteConfig) => void;
|
||||
fetchData: ReturnType<typeof useFetch>['fetchData'];
|
||||
$t: typeof $t;
|
||||
} | undefined>(undefined);
|
||||
|
||||
const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState => {
|
||||
@@ -94,23 +273,38 @@ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState =>
|
||||
...state,
|
||||
language: action.language,
|
||||
};
|
||||
case 'SET_PLUGINS_LOADED':
|
||||
return {
|
||||
...state,
|
||||
pluginsLoaded: action.pluginsLoaded,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const DefaultRouteConfig = [
|
||||
{ path: '/', pathMatch: 'full', component: <Root /> ,key:'root',},
|
||||
{ path: '/login', component: <Login /> ,key:'login'},
|
||||
{ path: '/dataMaskCompare/:logId/:serviceId?/:teamId?', component: <DataMaskingCompare /> ,key:'dataMaskCompare'},
|
||||
{ path: '/', pathMatch:'prefix',component:<ProtectedRoute /> ,key:'basciLayout',children:[
|
||||
{ path: '*', component: <ErrorBoundary><NotFound/></ErrorBoundary>, key: 'errorBoundary' }
|
||||
]}
|
||||
]
|
||||
// Create a context provider component
|
||||
export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const {fetchData} = useFetch()
|
||||
const { message } = App.useApp()
|
||||
const { setLocale } = useLocaleContext();
|
||||
const [state, dispatch] = useReducer(globalReducer, {
|
||||
isAuthenticated: true, //mock用
|
||||
isAuthenticated: false, //mock用
|
||||
userData: null,
|
||||
version: '1.0.0',
|
||||
updateDate: '2024-07-01',
|
||||
powered:'Powered by https://apipark.com',
|
||||
mainPage:'/guide/page',
|
||||
language:'en-US'
|
||||
language:'en-US',
|
||||
pluginsLoaded:false
|
||||
});
|
||||
const [accessData,setAccessData] = useState<Map<string,string[]>>(new Map())
|
||||
const [pluginAccessDictionary, setPluginAccessDictionary] = useState<{[k:string]:string}>({})
|
||||
@@ -118,6 +312,43 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const [accessInit, setAccessInit] = useState<boolean>(false)
|
||||
const [aiConfigFlushed, setAiConfigFlushed] = useState<boolean>(false)
|
||||
let getGlobalAccessPromise: Promise<BasicResponse<{ access:string[] }>> | null = null
|
||||
const [menuList, setMenuList] = useState<MenuItem[]>(mockData);
|
||||
const [routeConfig, setRouteConfigState] = useState<RouteConfig[]>(DefaultRouteConfig)
|
||||
|
||||
useEffect(() => {
|
||||
setLocale(state.language);
|
||||
}, [state.language, setLocale]);
|
||||
|
||||
const { fetchData } = useFetch();
|
||||
|
||||
const setRouterConfig = (isRoot: boolean, config: RouteConfig) => {
|
||||
setRouteConfigState(prevConfig => {
|
||||
if (isRoot) {
|
||||
return [config,...prevConfig];
|
||||
} else {
|
||||
const rootRoute = prevConfig.find(route => route.path === '/' && route?.pathMatch === 'prefix') ;
|
||||
if (rootRoute ) {
|
||||
rootRoute.children = rootRoute.children ? [config, ...rootRoute.children] : [config];
|
||||
}
|
||||
return [...prevConfig];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const addRouteConfig = (parentRoute: RouteConfig, config: RouteConfig) => {
|
||||
const addConfigToParent = (routes: RouteConfig[]): RouteConfig[] => {
|
||||
return routes.map(route => {
|
||||
if (route.key === parentRoute.key) {
|
||||
route.children = route.children ? [...route.children, config] : [config];
|
||||
} else if (route.children) {
|
||||
route.children = addConfigToParent(route.children);
|
||||
}
|
||||
return route;
|
||||
});
|
||||
};
|
||||
|
||||
setRouteConfigState(prevConfig => addConfigToParent(prevConfig));
|
||||
};
|
||||
|
||||
const getGlobalAccessData = ()=>{
|
||||
if(getGlobalAccessPromise){
|
||||
@@ -151,6 +382,18 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getMenuList = ()=>{
|
||||
// TODO 等待对接后端接口
|
||||
// fetchData<BasicResponse<{ access:string[]}>>('profile/permission/team',{method:'GET',eoParams:{team:teamId}},).then(response=>{
|
||||
// const {code,data,msg} = response
|
||||
// if(code === STATUS_CODE.SUCCESS){
|
||||
// setMenuList(data.menus)
|
||||
// }else{
|
||||
// message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
const cleanTeamAccessData = ()=>{
|
||||
setTeamDataFlushed(false)
|
||||
setAccessData(prevData => prevData.set('team',[]))
|
||||
@@ -176,15 +419,26 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
return revs
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={
|
||||
{ state, dispatch,accessData,pluginAccessDictionary,
|
||||
{ state, dispatch,
|
||||
accessData,
|
||||
pluginAccessDictionary,
|
||||
getGlobalAccessData,
|
||||
getPluginAccessDictionary,
|
||||
getTeamAccessData,teamDataFlushed,
|
||||
getTeamAccessData,teamDataFlushed,getMenuList,menuList,
|
||||
cleanTeamAccessData,
|
||||
resetAccess ,checkPermission,accessInit,
|
||||
aiConfigFlushed, setAiConfigFlushed}}>
|
||||
resetAccess ,checkPermission,
|
||||
accessInit,
|
||||
aiConfigFlushed,
|
||||
setAiConfigFlushed,
|
||||
routeConfig,
|
||||
setRouterConfig,
|
||||
addRouteConfig,
|
||||
fetchData,
|
||||
$t:$t,}}>
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
);
|
||||
@@ -194,7 +448,40 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
export const useGlobalContext = () => {
|
||||
const context = useContext(GlobalContext);
|
||||
if (!context) {
|
||||
throw new Error('useGlobalContext must be used within a GlobalProvider');
|
||||
|
||||
console.warn('useGlobalContext must be used within a GlobalProvider. Returning default context.');
|
||||
return {
|
||||
state: {
|
||||
isAuthenticated: false,
|
||||
userData: null,
|
||||
version: '1.0.0',
|
||||
updateDate: '',
|
||||
powered: '',
|
||||
mainPage: '',
|
||||
language: 'en-US',
|
||||
pluginsLoaded: false,
|
||||
},
|
||||
dispatch: () => {},
|
||||
accessData: new Map(),
|
||||
pluginAccessDictionary: {},
|
||||
menuList: [],
|
||||
getGlobalAccessData: async () => ({ access: [] }),
|
||||
getTeamAccessData: () => {},
|
||||
getPluginAccessDictionary: () => {},
|
||||
getMenuList: () => {},
|
||||
resetAccess: () => {},
|
||||
cleanTeamAccessData: () => {},
|
||||
checkPermission: () => false,
|
||||
teamDataFlushed: false,
|
||||
accessInit: false,
|
||||
aiConfigFlushed: false,
|
||||
setAiConfigFlushed: () => {},
|
||||
routeConfig: [],
|
||||
setRouterConfig: () => {},
|
||||
addRouteConfig: () => {},
|
||||
fetchData: async () => ({}),
|
||||
$t: (key: string) => key,
|
||||
};
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useMemo, FC, ReactNode } from 'react';
|
||||
import { ConfigProviderProps } from 'antd';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
import zhTW from 'antd/locale/zh_TW';
|
||||
import jaJP from 'antd/locale/ja_JP';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/zh-tw';
|
||||
import 'dayjs/locale/ja';
|
||||
|
||||
type Locale = ConfigProviderProps['locale'];
|
||||
|
||||
const languageMap: Record<string, Locale> = {
|
||||
'zh-CN': zhCN,
|
||||
'en-US': enUS,
|
||||
'zh-TW': zhTW,
|
||||
'ja-JP': jaJP,
|
||||
};
|
||||
|
||||
const LocaleContext = createContext<{
|
||||
locale: Locale;
|
||||
setLocale: (locale: string) => void;
|
||||
}|undefined>(undefined);
|
||||
|
||||
export const LocaleProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const [locale, setLocaleState] = useState<Locale>(zhCN);
|
||||
|
||||
const setLocale = (language: string) => {
|
||||
dayjs.locale(language);
|
||||
setLocaleState(languageMap[language]);
|
||||
};
|
||||
|
||||
return (
|
||||
<LocaleContext.Provider value={{ locale, setLocale }}>
|
||||
{children}
|
||||
</LocaleContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useLocaleContext = () => {
|
||||
const context = useContext(LocaleContext);
|
||||
if (!context) {
|
||||
throw new Error('useLocaleContext must be used within a LocaleContext');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
|
||||
|
||||
class EventEmitter {
|
||||
// 用来存放注册的事件与回调
|
||||
_events:any
|
||||
constructor () {
|
||||
this._events = {}
|
||||
}
|
||||
|
||||
on (eventName:string, callback:Function) {
|
||||
// 由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列
|
||||
const callbacks = this._events[eventName] || []
|
||||
callbacks.push(callback)
|
||||
this._events[eventName] = callbacks
|
||||
}
|
||||
|
||||
// 此处需要处理,emit时需要按顺序执行监听的函数,每个函数都会返回是否中止的参数,如果中止则不执行后续的函数
|
||||
// emit传入eventName 和 event, 返回 event
|
||||
emit (eventName:string, event:any) {
|
||||
return new Promise((resolve) => {
|
||||
const callbacks = this._events[eventName] || []
|
||||
for (const cb of callbacks) {
|
||||
const cbRes = cb(event.data)
|
||||
if (cbRes.continue === false) {
|
||||
resolve(cbRes)
|
||||
break
|
||||
} else {
|
||||
event = cbRes
|
||||
}
|
||||
}
|
||||
resolve(event.data)
|
||||
})
|
||||
}
|
||||
|
||||
// 取消订阅
|
||||
off (eventName:string, callback:Function) {
|
||||
const callbacks = this._events[eventName] || []
|
||||
const newCallbacks = callbacks.filter((fn:any) => fn !== callback && fn.initialCallback !== callback /* 用于once的取消订阅 */)
|
||||
this._events[eventName] = newCallbacks
|
||||
}
|
||||
|
||||
// 单次订阅,后台插件可以自行决定取消对事件的订阅
|
||||
once (eventName:string, callback:Function) {
|
||||
// 由于需要在回调函数执行后,取消订阅当前事件,所以需要对传入的回调函数做一层包装,然后绑定包装后的函数
|
||||
const one = (...args:any) => {
|
||||
callback(...args)
|
||||
this.off(eventName, one)
|
||||
}
|
||||
|
||||
// 由于:我们订阅事件的时候,修改了原回调函数的引用,所以,用户触发 off 的时候不能找到对应的回调函数
|
||||
// 所以,我们需要在当前函数与用户传入的回调函数做一个绑定,我们通过自定义属性来实现
|
||||
one.initialCallback = callback
|
||||
this.on(eventName, one)
|
||||
}
|
||||
}
|
||||
|
||||
export const PluginEventHubContext = createContext<EventEmitter | undefined>(undefined);
|
||||
|
||||
export const PluginEventHubProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [pluginEventHub] = useState<EventEmitter>(new EventEmitter());
|
||||
|
||||
return (
|
||||
<PluginEventHubContext.Provider value={pluginEventHub}>
|
||||
{children}
|
||||
</PluginEventHubContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePluginEventHub = () => {
|
||||
const context = useContext(PluginEventHubContext);
|
||||
if (!context) {
|
||||
throw new Error('usePluginEventHub must be used within a PluginEventHubProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
|
||||
export const PluginSlotHubContext = createContext<{
|
||||
addSlot: (name: string, content: unknown) => void;
|
||||
addSlotArr: (name: string, content: unknown[]) => void;
|
||||
removeSlot: (name: string) => void;
|
||||
getSlot: (name: string) => unknown;
|
||||
} | undefined>(undefined);
|
||||
|
||||
export const PluginSlotHubProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [pluginSlotHub] = useState<Map<string, unknown>>(new Map());
|
||||
|
||||
const pluginSlotHubService = {
|
||||
addSlot: (name: string, content: any) => {
|
||||
pluginSlotHub.set(name, pluginSlotHub.get(name) ? [...(pluginSlotHub.get(name) as Array<unknown>), content] : [content] ); },
|
||||
addSlotArr: (name: string, content: any[]) => { pluginSlotHub.get(name) ? pluginSlotHub.set(name, (pluginSlotHub.get(name) as Array<unknown>).push(content)) : pluginSlotHub.set(name, content); },
|
||||
removeSlot: (name: string) => { pluginSlotHub.delete(name); },
|
||||
getSlot: (name: string) => {
|
||||
|
||||
return pluginSlotHub.get(name) ; }
|
||||
};
|
||||
|
||||
return (
|
||||
<PluginSlotHubContext.Provider value={pluginSlotHubService}>
|
||||
{children}
|
||||
</PluginSlotHubContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePluginSlotHub = () => {
|
||||
const context = useContext(PluginSlotHubContext);
|
||||
if (!context) {
|
||||
throw new Error('usePluginSlotHub must be used within a PluginSlotHubProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
import { RESPONSE_TIPS } from '@common/const/const';
|
||||
import { message } from 'antd';
|
||||
import { $t } from "@common/locales"
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const useCopyToClipboard = () => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { STATUS_CODE } from "@common/const/const";
|
||||
import { BasicResponse, STATUS_CODE } from "@common/const/const";
|
||||
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
||||
import EventEmitter from "events";
|
||||
|
||||
const urlWhiteList = [/api.example.com\/users/, /api.example2.com\/products/]; // 正则白名单
|
||||
|
||||
@@ -137,7 +139,10 @@ type EoRequest = RequestInit & {eoParams?:{[k:string]:unknown},eoTransformKeys?:
|
||||
|
||||
type EoHeaders = Headers | {[k:string]:string}
|
||||
|
||||
export function useFetch(){
|
||||
export function useFetch() {
|
||||
// plugin cannot use usePluginEventHub directly, so we need to pass it as a parameter
|
||||
const pluginEventHub = usePluginEventHub()
|
||||
|
||||
function fetchData<T>(url:string, options: EoRequest ) {
|
||||
// 合并传入的headers与默认headers
|
||||
const headers = { ...(options.body ? {}:DEFAULT_HEADERS), ...options.headers };
|
||||
@@ -184,9 +189,11 @@ export function useFetch(){
|
||||
// 如果响应体为JSON且指定了转换键,则转换响应数据
|
||||
if ( isJsonHttp(response.headers)) {
|
||||
const data = await response.json();
|
||||
return shouldTransformKeys ? keysToCamel(data,options.eoTransformKeys as string[]) as T:data
|
||||
const newData = await pluginEventHub.emit('httpResponse', {data,continue:true}) as Response;
|
||||
return shouldTransformKeys ? keysToCamel(newData,options.eoTransformKeys as string[]) as T:data
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { DEFAULT_LOCAL_PLUGIN_PATH, generateRemoteModuleTemplate, loadRemoteModule, validateExportLifecycle } from "@common/utils/plugin.tsx";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { PluginConfigType, RouteConfig } from "@common/const/type.ts";
|
||||
import { ApiparkPluginDriverType ,RouterMapConfig} from "@common/const/type";
|
||||
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
||||
import { usePluginSlotHub } from "@common/contexts/PluginSlotHubContext";
|
||||
import { App } from "antd";
|
||||
|
||||
const mockData = {
|
||||
buildAt:'2024-09-13T03:51:25Z',
|
||||
build_user:'gitlab-runner',
|
||||
git_commint:'6438d5aaff146dc560ed0d8563788e64a49640a5',
|
||||
goversion:'go version go1.21.4 linux/amd64',
|
||||
guide:true,
|
||||
plugins:[
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'guide',
|
||||
router:[
|
||||
{
|
||||
path:'guide/*',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'team',
|
||||
router:[
|
||||
{
|
||||
path:'team',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'service',
|
||||
router:[
|
||||
{
|
||||
path:'service',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'datasourcing',
|
||||
router:[
|
||||
{
|
||||
path:'datasourcing',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'cluster',
|
||||
router:[
|
||||
{
|
||||
path:'cluster',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'aisetting',
|
||||
router:[
|
||||
{
|
||||
path:'aisetting',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'cert',
|
||||
router:[
|
||||
{
|
||||
path:'cert',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'serviceHub',
|
||||
router:[
|
||||
{
|
||||
path:'serviceHub',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'commonsetting',
|
||||
router:[
|
||||
{
|
||||
path:'commonsetting',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'consumer',
|
||||
router:[
|
||||
{
|
||||
path:'consumer',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'member',
|
||||
router:[
|
||||
{
|
||||
path:'member',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'role',
|
||||
router:[
|
||||
{
|
||||
path:'role',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'analytics',
|
||||
router:[
|
||||
{
|
||||
path:'analytics',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'template',
|
||||
router:[
|
||||
{
|
||||
path:'template/:moduleId',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'logsettings',
|
||||
router:[
|
||||
{
|
||||
path:'logsettings/*',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'resourcesettings',
|
||||
router:[
|
||||
{
|
||||
path:'resourcesettings/*',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'userProfile',
|
||||
router:[
|
||||
{
|
||||
path:'userProfile',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'globalPolicy',
|
||||
router:[
|
||||
{
|
||||
path:'globalPolicy',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// "driver": "apipark.remote.normal",
|
||||
// "name": "remote",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "remote",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.local.preload",
|
||||
// "name": "auth",
|
||||
// "router": [
|
||||
// {
|
||||
// "expose": "AppModule",
|
||||
// "path": "auth",
|
||||
// "type": "root"
|
||||
// },
|
||||
// {
|
||||
// "expose": "AuthInfoModule",
|
||||
// "path": "auth-info",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.builtIn.component",
|
||||
// "name": "email",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "system/email",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.builtIn.module",
|
||||
// "name": "open-api",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "system/ext-app",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.local.preload",
|
||||
// "name": "remote",
|
||||
// "router": [
|
||||
// {
|
||||
// "expose": "App",
|
||||
// "path": "router1/*",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.remote.normal",
|
||||
// "name": "apispace",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "remote/apispace",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
powered:'Powered by https://eolink.com',
|
||||
product:'apipark',
|
||||
version:'6438d5aa'
|
||||
}
|
||||
|
||||
export type ExecutePluginType = PluginConfigType & {
|
||||
expose:string,
|
||||
bootstrap:string
|
||||
}
|
||||
|
||||
const usePluginLoader = (apipark:ApiparkPluginDriverType,routerMap:Map<string, RouterMapConfig>) => {
|
||||
const [modules, setModules] = useState(new Map());
|
||||
const [executeList, setExecuteList] = useState<ExecutePluginType[]>([]);
|
||||
const [baseHref, setBaseHref] = useState('');
|
||||
const [pendingTasks, setPendingTasks] = useState(0);
|
||||
const {fetchData} = useFetch();
|
||||
const pluginProvider = useGlobalContext();
|
||||
const pluginEventHub = usePluginEventHub();
|
||||
const pluginSlotHub = usePluginSlotHub();
|
||||
const { getMenuList,dispatch} = pluginProvider
|
||||
const { modal,message } = App.useApp()
|
||||
const [startLoadExecutePlugin, setStartLoadExecutePlugin] = useState<boolean>(false)
|
||||
const messageService = message;
|
||||
const modalService = modal;
|
||||
let startInstallPlugin = false
|
||||
|
||||
useEffect(()=>{
|
||||
if (startLoadExecutePlugin && pendingTasks === 0 && executeList.length > 0) {
|
||||
loadExecutedPlugin();
|
||||
}
|
||||
},[pendingTasks, executeList])
|
||||
|
||||
|
||||
const getModule = (routerPrefix:string, specific = false) => {
|
||||
if (routerPrefix.startsWith('/')) {
|
||||
routerPrefix = routerPrefix.substring(1);
|
||||
}
|
||||
if (specific) {
|
||||
return modules.get(routerPrefix);
|
||||
}
|
||||
let matchedModule = null;
|
||||
let matchedLength = 0;
|
||||
|
||||
modules.forEach((value, key) => {
|
||||
if (routerPrefix.startsWith(key) && key.length > matchedLength) {
|
||||
matchedModule = value;
|
||||
matchedLength = key.length;
|
||||
}
|
||||
});
|
||||
return matchedModule;
|
||||
};
|
||||
|
||||
const loadModule = async (routerPrefix: string, pluginName: any, exposedModule: string , pluginPath: any) => {
|
||||
if (!modules.get(routerPrefix)) {
|
||||
try {
|
||||
const loadedModule = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, exposedModule, pluginPath));
|
||||
const Module = loadedModule.default ?? loadedModule
|
||||
let ModuleBootstrap;
|
||||
try {
|
||||
ModuleBootstrap = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, 'Bootstrap', pluginPath));
|
||||
} catch (error) {
|
||||
console.warn('Bootstrap module not found:', error);
|
||||
}
|
||||
setModules(prevModules => new Map(prevModules).set(routerPrefix,Module[exposedModule] ));
|
||||
if (!validateExportLifecycle(Module)) {
|
||||
console.error('需要导出插件生命周期函数');
|
||||
return;
|
||||
}
|
||||
await Module.bootstrap?.({
|
||||
pluginProvider,
|
||||
pluginEventHub,
|
||||
pluginSlotHub
|
||||
});
|
||||
return Module;
|
||||
} catch (error) {
|
||||
console.error('导入插件失败:', error);
|
||||
}
|
||||
}
|
||||
return getModule(routerPrefix, true);
|
||||
};
|
||||
|
||||
const loadExecutedPlugin = async () => {
|
||||
setStartLoadExecutePlugin(true)
|
||||
for (const plugin of executeList) {
|
||||
try {
|
||||
const Module = await loadRemoteModule(generateRemoteModuleTemplate(plugin.name, plugin?.expose || 'Bootstrap', plugin.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${plugin.name}/apipark.js`));
|
||||
const bootstrap = Module.bootstrap;
|
||||
if (!bootstrap) {
|
||||
console.warn('立即执行插件未导出Bootstrap模块或bootstrap函数');
|
||||
} else {
|
||||
await bootstrap({
|
||||
pluginEventHub,
|
||||
pluginSlotHub,
|
||||
pluginProvider,
|
||||
platformProvider:null,
|
||||
messageService,
|
||||
modalService,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('执行插件失败:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const loadPlugins = () => {
|
||||
return new Promise((resolve) => {
|
||||
if(startInstallPlugin) {
|
||||
return resolve(true)
|
||||
}
|
||||
startInstallPlugin = true
|
||||
installPlugin().then(async (res)=>{
|
||||
// reset route after loading executed plugins
|
||||
await loadExecutedPlugin();
|
||||
return resolve(res)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const installPlugin = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// fetchData('system/plugins',{method:'GET'}).then((resp) => {
|
||||
// if (resp.code === 0){
|
||||
const resp = {data:mockData}
|
||||
dispatch({type:'UPDATE_VERSION',version:resp.data.version})
|
||||
dispatch({type:'UPDATE_DATE',updateDate:resp.data.buildAt})
|
||||
dispatch({type:'UPDATE_POWER',powered:resp.data.powered})
|
||||
const driverMethod = { apipark: apipark };
|
||||
const pluginConfigList = resp.data.plugins;
|
||||
const pluginLoader = { loadModule };
|
||||
const pluginLifecycleGuard ={};
|
||||
const builtInPluginLoader = loadBuiltInModule;
|
||||
pluginSlotHub.addSlot('renewMenu', () => {
|
||||
getMenuList()
|
||||
});
|
||||
for (const plugin of pluginConfigList) {
|
||||
try {
|
||||
const driverName = plugin.driver;
|
||||
if (!driverName) {
|
||||
console.error('no driver name');
|
||||
continue;
|
||||
}
|
||||
const driver = driverName.split('.').reduce((driverMethod: { [x: string]: any; }, driverName: string | number) => driverMethod[driverName], driverMethod);
|
||||
if(driverName.split('.')[2] === 'preload'){
|
||||
setPendingTasks(prev => prev + 1);
|
||||
}
|
||||
;(driver as Function )?.({ setExecuteList:(callback:ExecutePluginType[]) => {
|
||||
setExecuteList(callback);
|
||||
setPendingTasks(prev => prev - 1);
|
||||
}, pluginLoader, pluginProvider, pluginLifecycleGuard, builtInPluginLoader }, plugin);
|
||||
} catch (err) {
|
||||
console.warn('安装插件出错:', err);
|
||||
}
|
||||
}
|
||||
resolve(true);
|
||||
// } else {
|
||||
// messageService.error(resp.msg || '获取插件配置列表失败,请重试!');
|
||||
// reject(new Error(resp.msg || '获取插件配置列表失败'));
|
||||
// }
|
||||
// });
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const loadBuiltInModule = (pluginName: any) => {
|
||||
try {
|
||||
const { module } = routerMap.get(pluginName)!;
|
||||
return module;
|
||||
} catch (err) {
|
||||
console.warn(`安装内置插件[${pluginName}]出错:`, err);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loadPlugins,
|
||||
loadModule,
|
||||
loadExecutedPlugin,
|
||||
setBaseHref,
|
||||
getModule
|
||||
};
|
||||
};
|
||||
|
||||
export default usePluginLoader;
|
||||
@@ -1,32 +1,8 @@
|
||||
{
|
||||
"工作空间": "Kc0e5ef9f",
|
||||
"首页": "K4de11e23",
|
||||
"服务": "Kb58e0c3f",
|
||||
"消费者": "K7acfcfad",
|
||||
"团队": "Kc9e489f5",
|
||||
"API 市场": "K61c89f5f",
|
||||
"仪表盘": "K16d71239",
|
||||
"运行视图": "K714c192d",
|
||||
"系统拓扑图": "Kd57dfe97",
|
||||
"系统设置": "K3fe97dcc",
|
||||
"系统": "Kecbb0e45",
|
||||
"常规": "Ka358e23d",
|
||||
"API 网关": "K449058e9",
|
||||
"AI 模型": "K99935e6f",
|
||||
"用户": "K1deaa2dd",
|
||||
"账号": "K80a560a1",
|
||||
"角色": "Kf644225f",
|
||||
"集成": "K4057391a",
|
||||
"数据源": "K8fa58214",
|
||||
"全局策略": "Ke8cbb878",
|
||||
"证书": "K481e8a05",
|
||||
"日志": "Kca53edd0",
|
||||
"资源": "Kb283e720",
|
||||
"Open API": "K631d646f",
|
||||
"账号设置": "K6535ff9c",
|
||||
"退出登录": "Kf15499b4",
|
||||
"文档": "Kabbd6e6",
|
||||
"APIPark - 企业API数据开放平台": "K1196b104",
|
||||
"APIPark": "K630c9e6d",
|
||||
"HTTP 状态码": "K1f42de3",
|
||||
"系统状态码": "K4770dff4",
|
||||
"描述": "Kf89e58f1",
|
||||
@@ -44,6 +20,8 @@
|
||||
"ID": "K11d3633a",
|
||||
"名称": "Kbff43de3",
|
||||
"Driver": "K16ca79ef",
|
||||
"资源": "Kb283e720",
|
||||
"日志": "Kca53edd0",
|
||||
"已发布": "K7a369eef",
|
||||
"下线": "Kcfa1a4d2",
|
||||
"上线": "K771dc3b7",
|
||||
@@ -51,6 +29,8 @@
|
||||
"删除": "Kecbd7449",
|
||||
"确认": "K1cbe2507",
|
||||
"搜索(0)名称": "K48325b6",
|
||||
"发布名称": "Ka3e9f580",
|
||||
"策略列表": "Kb2480682",
|
||||
"上下文": "Kc6340091",
|
||||
"查询内容": "K74ecb1fa",
|
||||
"会话历史": "K79f2e2f9",
|
||||
@@ -65,6 +45,8 @@
|
||||
"成功": "K43fcaf94",
|
||||
"上线失败": "Kc71c6a9",
|
||||
"失败": "K56c686f8",
|
||||
"正常": "Ke039b9b5",
|
||||
"无效": "K1da86266",
|
||||
"申请系统": "K1ff96ff",
|
||||
"所属团队": "K9bf855d6",
|
||||
"申请人": "K11b994ed",
|
||||
@@ -235,6 +217,28 @@
|
||||
"地址": "K78b1ca25",
|
||||
"新增": "K1644b775",
|
||||
"申请方消费者": "Kec91f0db",
|
||||
"策略名称": "K931615d7",
|
||||
"优先级": "K31faa2a1",
|
||||
"筛选条件": "Kbdec9fa",
|
||||
"处理数": "Kbcbb7391",
|
||||
"数据格式": "K118d8d74",
|
||||
"关键字": "Kfe7c7d2d",
|
||||
"正则表达式": "K2f57a694",
|
||||
"手机号": "K8953e0a6",
|
||||
"身份证号": "K6f86a038",
|
||||
"银行卡号": "K7954e7c8",
|
||||
"金额": "K320fdb17",
|
||||
"日期": "K7867acda",
|
||||
"局部显示": "K7d327ae8",
|
||||
"局部遮蔽": "Kfbf38e3c",
|
||||
"截取": "Kd8c1fbb0",
|
||||
"替换": "K89829921",
|
||||
"乱序": "K480a7165",
|
||||
"随机字符串": "Kea0d69df",
|
||||
"自定义字符串": "Ke7c84d1d",
|
||||
"请输入IP地址或CIDR范围,每条以换行分割": "K49731763",
|
||||
"待更新": "K3a34d49b",
|
||||
"待删除": "Kd2850420",
|
||||
"暂无操作权限,请联系管理员分配。": "K23fda291",
|
||||
"微信小程序": "K4618cb0a",
|
||||
"获取文件,需填路径": "Ka854f511",
|
||||
@@ -322,14 +326,18 @@
|
||||
"至": "K7e1ab4b0",
|
||||
"详情": "Kf1b166e7",
|
||||
"暂不支持带有双斜杠//的url": "K28555332",
|
||||
"输入的IP或CIDR不符合格式": "K83237c89",
|
||||
"请正确输入路径,如/usr/*或*/usr/*": "K5ae2c87a",
|
||||
"必填项": "K71661ee8",
|
||||
"不是有效邮箱地址": "Kcbee3f8",
|
||||
"最近一次更新者": "K617f34f1",
|
||||
"最近一次更新时间": "K6ebca204",
|
||||
"保存": "Kabfe9512",
|
||||
"服务": "Kb58e0c3f",
|
||||
"API 路由": "K51d1eb5d",
|
||||
"API 文档": "Ka2b6d281",
|
||||
"使用说明": "Kdefa9caa",
|
||||
"服务策略": "K52f72551",
|
||||
"发布": "K36856e71",
|
||||
"订阅管理": "K6382bbfd",
|
||||
"订阅审核": "K31af5b99",
|
||||
@@ -381,6 +389,8 @@
|
||||
"发布申请": "K56b4254f",
|
||||
"API 调用地址": "Kea2f9279",
|
||||
"API base URL 一般设置为API 网关的外部网络访问地址,或者是API网关绑定的域名。": "K7fc496a1",
|
||||
"集成地址": "K508d8bf4",
|
||||
"与外部平台集成时,获取 API 市场中文档信息的域名": "K67f4e9bb",
|
||||
"常规设置": "K8ab0fc95",
|
||||
"API 请求设置": "Kb66fec9d",
|
||||
"服务分类": "K4de0af74",
|
||||
@@ -402,11 +412,13 @@
|
||||
"现在你可以通过 Token 来调用这些 API。": "Kd6d7ca1f",
|
||||
"快速接入 REST API": "K86cf95f",
|
||||
"创建 REST 服务和 API": "K7a3a8417",
|
||||
"仪表盘": "K16d71239",
|
||||
"统计 API 调用情况": "K4a84214e",
|
||||
"仪表盘中提供了多种统计图表,帮助我们了解 API 的运行情况。": "K297d8563",
|
||||
"核心功能": "K2cdbb773",
|
||||
"账号与角色": "K3378c50d",
|
||||
"邀请你的团队成员加入 APIPark,共同管理和调用 API。": "Kda5bb930",
|
||||
"团队": "Kc9e489f5",
|
||||
"团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。": "Keee27105",
|
||||
"服务内包含一组 API,并且可以发布到 API 市场被其他团队使用。": "Kd5be0cd7",
|
||||
"权限管理": "K62e89ee7",
|
||||
@@ -414,6 +426,7 @@
|
||||
"如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。": "Kf2410413",
|
||||
"审核订阅申请": "K6c2e44b8",
|
||||
"提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的消费者才可发起 API 请求。": "Kaa717866",
|
||||
"集成": "K4057391a",
|
||||
"APIPark 提供详尽的 API 调用日志,帮助企业监控、分析和审计 API 的运行状况。": "K3453272",
|
||||
"Hello!欢迎使用 APIPark": "Kd518ba3e",
|
||||
"你能通过 APIPark 快速在企业内部构建 API 开放门户/市场,享受极致的转发性能、API 可观测、服务治理、多租户管理、订阅审核流程等诸多好处。": "K7e04ea16",
|
||||
@@ -425,6 +438,7 @@
|
||||
"了解更多功能": "K48f7e21f",
|
||||
"隐藏该教程": "K698296e2",
|
||||
"请输入账号": "Kf076f63c",
|
||||
"账号": "K80a560a1",
|
||||
"请输入密码": "K25c895d5",
|
||||
"密码": "K551b0348",
|
||||
"登录": "Kd2c1a316",
|
||||
@@ -456,7 +470,6 @@
|
||||
"添加部门": "K26c698bb",
|
||||
"添加子部门": "Kb9cf2a7d",
|
||||
"重命名": "Kc83551f5",
|
||||
"该数据删除后将无法找回,请确认是否删除?": "K5cfdd950",
|
||||
"成员": "K74aef1ad",
|
||||
"设置成员和对应的角色,成员只能够看到权限范围内的功能和数据。": "K3f1077c9",
|
||||
"搜索部门": "Kdce62a6",
|
||||
@@ -467,6 +480,7 @@
|
||||
"密钥": "K8ef69ee2",
|
||||
"上传密钥": "Kba3507d6",
|
||||
"密钥文件的后缀名一般为 .key 的文件内容": "K93ac0f23",
|
||||
"证书": "K481e8a05",
|
||||
"上传证书": "K7cdd1331",
|
||||
"证书文件的后缀名一般为 .crt 或 .pem 的文件内容": "K6d91905d",
|
||||
"添加证书": "Kd0f6ded7",
|
||||
@@ -476,7 +490,6 @@
|
||||
"集群": "Ke93d36ed",
|
||||
"修改配置": "K877985b7",
|
||||
"设置访问 API 的集群,让 API 在分布式环境中稳定运行,并且能够根据业务需求进行灵活扩展和优化。": "Kdf66a675",
|
||||
"正常": "Ke039b9b5",
|
||||
"异常": "K23a3bd72",
|
||||
"私有网络": "Ke1b1865",
|
||||
"公共网络": "K4786c57c",
|
||||
@@ -485,19 +498,39 @@
|
||||
"同步地址": "K2a49373f",
|
||||
"集群地址": "K5878440c",
|
||||
"下一步": "K5e9022f8",
|
||||
"数据源": "K8fa58214",
|
||||
"设置监控报表的数据来源,设置完成之后即可获得详细的API调用统计图表。": "Kdbafd6f9",
|
||||
"统计图表": "K1358acf",
|
||||
"地址(IP:端口)": "K62dabdf6",
|
||||
"组织(Organization)": "K2db12335",
|
||||
"添加策略": "K34d0d409",
|
||||
"输入名称、筛选条件查找": "Kbb4298ac",
|
||||
"策略名称": "K931615d7",
|
||||
"优先级": "K31faa2a1",
|
||||
"筛选条件": "Kbdec9fa",
|
||||
"处理数": "Kbcbb7391",
|
||||
"编辑策略": "Kc82b8374",
|
||||
"策略类型": "K4b34a5e5",
|
||||
"匹配条件": "K57f0fee8",
|
||||
"数据脱敏规则": "K10650c58",
|
||||
"配置脱敏规则": "K1b34a9ab",
|
||||
"匹配值": "K26d22405",
|
||||
"脱敏类型": "K1546e1fe",
|
||||
"起始位置": "K9b9b0629",
|
||||
"长度": "K52c84fe1",
|
||||
"替换类型": "Kde84409c",
|
||||
"替换值": "K338653b4",
|
||||
"JSON Path": "Kbaeed3b7",
|
||||
"脱敏规则": "K4cd91d61",
|
||||
"自定义字符串; 值:": "K8dcad979",
|
||||
"起始位置:(0)位;长度:(1)位": "K82e3f7b7",
|
||||
"编辑": "Kad207008",
|
||||
"已选择(0)项(1)数据": "K49dfc123",
|
||||
"所有(0)": "K8457ea34",
|
||||
"属性名称": "K7ca9a795",
|
||||
"属性值": "Kc4391744",
|
||||
"配置(0)": "K678e13fc",
|
||||
"数据脱敏": "Kabac9caf",
|
||||
"全局策略": "Ke8cbb878",
|
||||
"支持对系统全局进行统一的策略配置,从而简化管理并确保一致性。全局策略的优先级比服务策略略低。": "Kc975cd5a",
|
||||
"资源配置": "K8e7a0f80",
|
||||
"角色": "Kf644225f",
|
||||
"设置角色的权限范围。": "K95c3fd8b",
|
||||
"系统级别角色": "K138facd3",
|
||||
"添加角色": "K6eac768d",
|
||||
@@ -532,7 +565,6 @@
|
||||
"删除服务": "Kde6bae17",
|
||||
"删除操作不可恢复,请谨慎操作!": "K885ea699",
|
||||
"上游": "Kda8d5ea1",
|
||||
"服务策略": "K52f72551",
|
||||
"服务提供了高性能 API 网关,并且可以无缝接入多种大型 AI 模型,并将这些 AI 能力打包成 API 进行调用,从而大幅简化了 AI 模型的使用门槛。同时,我们的平台提供了完善的 API 管理功能,支持 API 的创建、监控、访问控制等,保障开发者可以高效、安全地开发和管理 API 服务。": "K12f58863",
|
||||
"添加服务": "K2d6658ed",
|
||||
"输入名称、ID、所属团队、负责人查找服务": "K7b8f623f",
|
||||
@@ -578,6 +610,7 @@
|
||||
"退出全屏": "Kaf70c3b",
|
||||
"(0)调用详情": "Kd22841a4",
|
||||
"消费者调用统计": "K61cca533",
|
||||
"消费者": "K7acfcfad",
|
||||
"请选择消费者": "Kdfff59d4",
|
||||
"调用趋势": "K8c7f2d2e",
|
||||
"(0)-(1)调用趋势": "K657c3452",
|
||||
@@ -610,6 +643,7 @@
|
||||
"暂无调用量统计数据": "Kcd125e4d",
|
||||
"暂无报文量统计数据": "Kaa114e8b",
|
||||
"报文量统计": "K3ad84406",
|
||||
"运行视图": "K714c192d",
|
||||
"集群配置并开启监控": "Kfa088d49",
|
||||
"监控功能用于辅助管理集群内信息,请配置集群、设置监控信息后查看当前集群监控情况;": "K3da3b9a0",
|
||||
"集群配置": "Kaddacfb",
|
||||
@@ -699,6 +733,7 @@
|
||||
"配置 Open Api": "K7829bb78",
|
||||
"Open Api": "Kcdf76005",
|
||||
"调用服务": "Ke2601944",
|
||||
"系统拓扑图": "Kd57dfe97",
|
||||
"放大": "K8504bca8",
|
||||
"缩小": "K693c1b41"
|
||||
}
|
||||
@@ -684,7 +684,7 @@
|
||||
"K35f23b64": "Follow these steps for integration:",
|
||||
"Kf5cd608b": "Step 1: Create a custom plugin on the Agent platform",
|
||||
"K4c81c7b6": "For details on the operations of different Agent platforms, refer to",
|
||||
"K275f7ffa": "the 'Agent Integration Manual'",
|
||||
"K275f7ffa": "the Agent Integration Manual",
|
||||
"K49b81d06": "Step 2: Import API documentation data",
|
||||
"K4a3b62be": "You can import API documentation data to the Agent platform via the following URL or by downloading the JSON file.",
|
||||
"K42697e11": "Copy URL",
|
||||
@@ -703,5 +703,65 @@
|
||||
"K31faa2a1": "Priority",
|
||||
"Kbdec9fa": "Filter Criteria",
|
||||
"Kbcbb7391": "Processed Count",
|
||||
"Kad207008": "Edit"
|
||||
"Kad207008": "Edit",
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "Release Name",
|
||||
"Kb2480682": "Policy List",
|
||||
"K118d8d74": "Data Format",
|
||||
"Kfe7c7d2d": "Keyword",
|
||||
"K2f57a694": "Regular Expression",
|
||||
"K8953e0a6": "Mobile Number",
|
||||
"K6f86a038": "ID Card Number",
|
||||
"K7954e7c8": "Bank Card Number",
|
||||
"K320fdb17": "Amount",
|
||||
"K7867acda": "Date",
|
||||
"K7d327ae8": "Partial Display",
|
||||
"Kfbf38e3c": "Partial Masking",
|
||||
"Kd8c1fbb0": "Truncate",
|
||||
"K89829921": "Replace",
|
||||
"K480a7165": "Shuffle",
|
||||
"Kea0d69df": "Random String",
|
||||
"Ke7c84d1d": "Custom String",
|
||||
"K49731763": "Please enter IP address or CIDR range, each separated by a newline.",
|
||||
"K83237c89": "The entered IP or CIDR does not meet the format.",
|
||||
"K5ae2c87a": "Please enter the correct path, such as /usr/* or */usr/*.",
|
||||
"Kc82b8374": "Edit Policy",
|
||||
"K4b34a5e5": "Policy Type",
|
||||
"K57f0fee8": "Match Conditions",
|
||||
"K10650c58": "Data Masking Rules",
|
||||
"K1b34a9ab": "Configure Masking Rules",
|
||||
"K26d22405": "Match Value",
|
||||
"K1546e1fe": "Masking Type",
|
||||
"K9b9b0629": "Starting Position",
|
||||
"K52c84fe1": "Length",
|
||||
"Kde84409c": "Replace Type",
|
||||
"K338653b4": "Replace Value",
|
||||
"Kbaeed3b7": "JSON Path",
|
||||
"K4cd91d61": "Masking Rules",
|
||||
"K8dcad979": "Custom String; Value:",
|
||||
"K82e3f7b7": "Starting Position: (0); Length: (1)",
|
||||
"K49dfc123": "Selected (0) items (1) data",
|
||||
"K8457ea34": "All (0)",
|
||||
"K7ca9a795": "Attribute Name",
|
||||
"Kc4391744": "Attribute Value",
|
||||
"K678e13fc": "Configure (0)",
|
||||
"K508d8bf4": "Integration Address",
|
||||
"K67f4e9bb": "The domain name for obtaining API market documentation information when integrating with external platforms",
|
||||
"K1da86266": "Invalid",
|
||||
"K3a34d49b": "Pending Update",
|
||||
"Kd2850420": "Pending Deletion",
|
||||
"K9ada4366": "Operation successful, the page will refresh shortly",
|
||||
"K9b332ab1": "Request prefix",
|
||||
"K3d78d483": "HTTP headers",
|
||||
"K17dc3a62": "Data logs",
|
||||
"Ke429194e": "Processing logs",
|
||||
"K84ffb1dd": "Enter the invocation address, consumer IP, and consumer condition to search",
|
||||
"Kb147fabc": "Create",
|
||||
"K40ca4f2": "Update",
|
||||
"K3e7aa0ad": "Content",
|
||||
"K2f5fdf5e": "Call Address",
|
||||
"K1bc5e0a3": "Consumer IP",
|
||||
"K6f39ea21": "Authentication Name",
|
||||
"K8c34c02f": "Before Masking",
|
||||
"K8e3d388d": "After Masking"
|
||||
}
|
||||
|
||||
@@ -725,5 +725,65 @@
|
||||
"K31faa2a1": "優先度",
|
||||
"Kbdec9fa": "フィルタ条件",
|
||||
"Kbcbb7391": "処理数",
|
||||
"Kad207008": "編集"
|
||||
"Kad207008": "編集",
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "リリース名",
|
||||
"Kb2480682": "ポリシーリスト",
|
||||
"K118d8d74": "データフォーマット",
|
||||
"Kfe7c7d2d": "キーワード",
|
||||
"K2f57a694": "正規表現",
|
||||
"K8953e0a6": "携帯番号",
|
||||
"K6f86a038": "IDカード番号",
|
||||
"K7954e7c8": "銀行カード番号",
|
||||
"K320fdb17": "金額",
|
||||
"K7867acda": "日付",
|
||||
"K7d327ae8": "部分表示",
|
||||
"Kfbf38e3c": "部分マスキング",
|
||||
"Kd8c1fbb0": "切り取り",
|
||||
"K89829921": "置換",
|
||||
"K480a7165": "シャッフル",
|
||||
"Kea0d69df": "ランダム文字列",
|
||||
"Ke7c84d1d": "カスタム文字列",
|
||||
"K49731763": "IPアドレスまたはCIDR範囲を入力してください。各行で改行してください。",
|
||||
"K83237c89": "入力されたIPまたはCIDRがフォーマットに一致しません。",
|
||||
"K5ae2c87a": "正しいパスを入力してください。例: /usr/* または */usr/*。",
|
||||
"Kc82b8374": "ポリシーを編集",
|
||||
"K4b34a5e5": "ポリシータイプ",
|
||||
"K57f0fee8": "一致条件",
|
||||
"K10650c58": "データマスキングルール",
|
||||
"K1b34a9ab": "マスキングルールを設定",
|
||||
"K26d22405": "一致値",
|
||||
"K1546e1fe": "マスキングタイプ",
|
||||
"K9b9b0629": "開始位置",
|
||||
"K52c84fe1": "長さ",
|
||||
"Kde84409c": "置換タイプ",
|
||||
"K338653b4": "置換値",
|
||||
"Kbaeed3b7": "JSON パス",
|
||||
"K4cd91d61": "マスキングルール",
|
||||
"K8dcad979": "カスタム文字列; 値:",
|
||||
"K82e3f7b7": "開始位置: (0); 長さ: (1)",
|
||||
"K49dfc123": "選択された (0) アイテム (1) データ",
|
||||
"K8457ea34": "すべて (0)",
|
||||
"K7ca9a795": "属性名",
|
||||
"Kc4391744": "属性値",
|
||||
"K678e13fc": "設定 (0)",
|
||||
"K508d8bf4": "統合アドレス",
|
||||
"K67f4e9bb": "外部プラットフォームと統合する際に、API市場のドキュメント情報を取得するためのドメイン名",
|
||||
"K1da86266": "無効",
|
||||
"K3a34d49b": "更新待ち",
|
||||
"Kd2850420": "削除待ち",
|
||||
"K9ada4366": "操作成功、ページを更新します",
|
||||
"K9b332ab1": "リクエストプレフィックス",
|
||||
"K3d78d483": "HTTPヘッダー",
|
||||
"K17dc3a62": "データログ",
|
||||
"Ke429194e": "ログの処理",
|
||||
"K84ffb1dd": "呼び出しアドレス、コンシューマーIP、条件を入力して検索",
|
||||
"Kb147fabc": "新規作成",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "内容",
|
||||
"K2f5fdf5e": "呼び出しアドレス",
|
||||
"K1bc5e0a3": "コンシューマー IP",
|
||||
"K6f39ea21": "認証名",
|
||||
"K8c34c02f": "マスキング前",
|
||||
"K8e3d388d": "マスキング後"
|
||||
}
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
{
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
{}
|
||||
@@ -1,3 +1 @@
|
||||
{
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
{}
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "发布名称",
|
||||
"Kb2480682": "策略列表",
|
||||
"K1da86266": "无效",
|
||||
"K76036e25": "HTTP 请求头",
|
||||
"K44607e3f": "全等匹配",
|
||||
"Kc287500a": "前缀匹配",
|
||||
@@ -21,7 +25,47 @@
|
||||
"K78b1ca25": "地址",
|
||||
"K1644b775": "新增",
|
||||
"Kec91f0db": "申请方消费者",
|
||||
"Kf5fd27ed": "输入名称查找用户",
|
||||
"Kc3b7bfa8": "暂无消费者描述",
|
||||
"K3a6f905d": "输入名称、ID 查找消费者"
|
||||
"K118d8d74": "数据格式",
|
||||
"Kfe7c7d2d": "关键字",
|
||||
"K2f57a694": "正则表达式",
|
||||
"K8953e0a6": "手机号",
|
||||
"K6f86a038": "身份证号",
|
||||
"K7954e7c8": "银行卡号",
|
||||
"K320fdb17": "金额",
|
||||
"K7867acda": "日期",
|
||||
"K7d327ae8": "局部显示",
|
||||
"Kfbf38e3c": "局部遮蔽",
|
||||
"Kd8c1fbb0": "截取",
|
||||
"K89829921": "替换",
|
||||
"K480a7165": "乱序",
|
||||
"Kea0d69df": "随机字符串",
|
||||
"Ke7c84d1d": "自定义字符串",
|
||||
"K49731763": "请输入IP地址或CIDR范围,每条以换行分割",
|
||||
"K3a34d49b": "待更新",
|
||||
"Kd2850420": "待删除",
|
||||
"K83237c89": "输入的IP或CIDR不符合格式",
|
||||
"K5ae2c87a": "请正确输入路径,如/usr/*或*/usr/*",
|
||||
"K508d8bf4": "集成地址",
|
||||
"K67f4e9bb": "与外部平台集成时,获取 API 市场中文档信息的域名",
|
||||
"Kc82b8374": "编辑策略",
|
||||
"K4b34a5e5": "策略类型",
|
||||
"K57f0fee8": "匹配条件",
|
||||
"K10650c58": "数据脱敏规则",
|
||||
"K1b34a9ab": "配置脱敏规则",
|
||||
"K26d22405": "匹配值",
|
||||
"K1546e1fe": "脱敏类型",
|
||||
"K9b9b0629": "起始位置",
|
||||
"K52c84fe1": "长度",
|
||||
"Kde84409c": "替换类型",
|
||||
"K338653b4": "替换值",
|
||||
"Kbaeed3b7": "JSON Path",
|
||||
"K4cd91d61": "脱敏规则",
|
||||
"K8dcad979": "自定义字符串; 值:",
|
||||
"K82e3f7b7": "起始位置:(0)位;长度:(1)位",
|
||||
"K49dfc123": "已选择(0)项(1)数据",
|
||||
"K8457ea34": "所有(0)",
|
||||
"K7ca9a795": "属性名称",
|
||||
"Kc4391744": "属性值",
|
||||
"K678e13fc": "配置(0)",
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
@@ -1,3 +1 @@
|
||||
{
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
{}
|
||||
@@ -1,4 +1,16 @@
|
||||
{
|
||||
"Kc0e5ef9f": "Workspace",
|
||||
"K4de11e23": "Home",
|
||||
"K61c89f5f": "API Portal",
|
||||
"K3fe97dcc": "System Settings",
|
||||
"Kecbb0e45": "System",
|
||||
"Ka358e23d": "General",
|
||||
"K449058e9": "API Gateway",
|
||||
"K99935e6f": "AI Model",
|
||||
"K1deaa2dd": "User",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"K5cfdd950": "This data cannot be recovered after deletion. Are you sure you want to delete?",
|
||||
"Kb9052305": "Search Username, Email",
|
||||
"K40a89bd8": "Enter Name, ID to Search Member"
|
||||
}
|
||||
@@ -1,10 +1,22 @@
|
||||
{
|
||||
"Kc0e5ef9f": "Workspace",
|
||||
"K4de11e23": "Home",
|
||||
"Kfe93ef35": "Application",
|
||||
"K61c89f5f": "API Portal",
|
||||
"K3fe97dcc": "設定",
|
||||
"Kecbb0e45": "システム",
|
||||
"Ka358e23d": "一般",
|
||||
"K449058e9": "API ゲートウェイ",
|
||||
"K99935e6f": "AI モデル",
|
||||
"K1deaa2dd": "ユーザー",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"Kffd7e274": "無審査:すべてのアプリケーションがこのサービスにサブスクライブできます",
|
||||
"K8a8b13e4": "手動審査:承認されたアプリケーションのみがこのサービスにサブスクライブできます",
|
||||
"K9bdd8403": "API を安全に呼び出すためには、アプリケーションとトークンを作成する必要があります。",
|
||||
"Kc8239422": "チームにはユーザー、アプリケーション、サービスが含まれ、異なるチームのアプリケーションとサービスのデータは分離されています。企業内の部門/プロジェクトグループ/チームの管理に使用できます。",
|
||||
"Ka0a8840a": "他のアプリケーションのサブスクリプション申請をレビューし、承認後に API リクエストが発行できます。",
|
||||
"K5cfdd950": "このデータを削除すると、復元できません。削除しますか?",
|
||||
"Kb9052305": "ユーザー名またはメールを検索",
|
||||
"K5ece3bac": "チームとメンバーを設定してから、チーム内でサービスとアプリケーションを作成し、API をサブスクライブできます。メンバーは所属チーム内のサービスとアプリケーションのみを表示できます。",
|
||||
"K1512e983": "アプリケーション呼び出し統計",
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
{
|
||||
"Kc0e5ef9f": "工作空间",
|
||||
"K4de11e23": "首页",
|
||||
"Kfe93ef35": "消费者",
|
||||
"K61c89f5f": "API 门户",
|
||||
"K3fe97dcc": "系统设置",
|
||||
"Kecbb0e45": "系统",
|
||||
"Ka358e23d": "常规",
|
||||
"K449058e9": "API 网关",
|
||||
"K99935e6f": "AI 模型",
|
||||
"K1deaa2dd": "用户",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"Kffd7e274": "无审核:允许所有消费者订阅该服务",
|
||||
"K8a8b13e4": "人工审核:仅允许审核通过的消费者订阅该服务",
|
||||
"K9bdd8403": "为了安全地调用 API,你需要创建一个消费者以及Token。",
|
||||
"Kc8239422": "团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。",
|
||||
"Ka0a8840a": "审核其他消费者的订阅申请,审核通过后的才可发起 API 请求。",
|
||||
"K5cfdd950": "该数据删除后将无法找回,是否删除?",
|
||||
"Kb9052305": "搜索用户名、邮箱",
|
||||
"K5ece3bac": "设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。",
|
||||
"K1512e983": "消费者调用统计",
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
{
|
||||
"Kc0e5ef9f": "工作區",
|
||||
"K4de11e23": "主頁",
|
||||
"Kfe93ef35": "應用程式",
|
||||
"K61c89f5f": "API 門戶",
|
||||
"K3fe97dcc": "系統設置",
|
||||
"Kecbb0e45": "系統",
|
||||
"Ka358e23d": "常規",
|
||||
"K449058e9": "API 網關",
|
||||
"K99935e6f": "AI 模型",
|
||||
"K1deaa2dd": "用戶",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"Kffd7e274": "無審核:允許所有應用程式訂閱該服務",
|
||||
"K8a8b13e4": "人工審核:僅允許審核通過的應用程式訂閱該服務",
|
||||
"K9bdd8403": "為了安全地調用 API,你需要創建一個應用以及Token。",
|
||||
"Kc8239422": "團隊中包含了人員、應用程式和服務,不同團隊之間的應用程式和服務數據是隔離的,可用於管理企業內部不同的部門/項目組/團隊。",
|
||||
"Ka0a8840a": "審核其他應用程式的訂閱申請,審核通過後的才可發起 API 請求。",
|
||||
"K5cfdd950": "該數據刪除後將無法找回,是否刪除?",
|
||||
"Kb9052305": "搜索用戶名、電郵",
|
||||
"K5ece3bac": "設置團隊和成員,然後你可以在團隊內創建服務和應用程式、訂閱API,成員只能看到所屬團隊內的服務和應用程式。",
|
||||
"K1512e983": "應用程式調用統計",
|
||||
|
||||
@@ -702,5 +702,19 @@
|
||||
"K31faa2a1": "优先级",
|
||||
"Kbdec9fa": "筛选条件",
|
||||
"Kbcbb7391": "处理数",
|
||||
"Kad207008": "编辑"
|
||||
"Kad207008": "编辑",
|
||||
"K9ada4366": "操作成功,即将刷新页面",
|
||||
"K9b332ab1": "请求前缀",
|
||||
"K3d78d483": "HTTP 头部",
|
||||
"K17dc3a62": "数据日志",
|
||||
"Ke429194e": "处理日志",
|
||||
"K84ffb1dd": "输入调用地址、消费者IP和消费者条件查找",
|
||||
"Kb147fabc": "新建",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "内容",
|
||||
"K2f5fdf5e": "调用地址",
|
||||
"K1bc5e0a3": "消费者 IP",
|
||||
"K6f39ea21": "鉴权名称",
|
||||
"K8c34c02f": "脱敏前",
|
||||
"K8e3d388d": "脱敏后"
|
||||
}
|
||||
@@ -725,5 +725,65 @@
|
||||
"K31faa2a1": "優先級",
|
||||
"Kbdec9fa": "篩選條件",
|
||||
"Kbcbb7391": "處理數",
|
||||
"Kad207008": "編輯"
|
||||
"Kad207008": "編輯",
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "發布名稱",
|
||||
"Kb2480682": "策略列表",
|
||||
"K118d8d74": "數據格式",
|
||||
"Kfe7c7d2d": "關鍵字",
|
||||
"K2f57a694": "正則表達式",
|
||||
"K8953e0a6": "手機號碼",
|
||||
"K6f86a038": "身份證號碼",
|
||||
"K7954e7c8": "銀行卡號碼",
|
||||
"K320fdb17": "金額",
|
||||
"K7867acda": "日期",
|
||||
"K7d327ae8": "局部顯示",
|
||||
"Kfbf38e3c": "局部遮蔽",
|
||||
"Kd8c1fbb0": "截取",
|
||||
"K89829921": "替換",
|
||||
"K480a7165": "亂序",
|
||||
"Kea0d69df": "隨機字串",
|
||||
"Ke7c84d1d": "自訂字串",
|
||||
"K49731763": "請輸入IP地址或CIDR範圍,每行以換行符分隔",
|
||||
"K83237c89": "輸入的IP或CIDR格式不正確",
|
||||
"K5ae2c87a": "請正確輸入路徑,例如/usr/*或*/usr/*",
|
||||
"Kc82b8374": "編輯策略",
|
||||
"K4b34a5e5": "策略類型",
|
||||
"K57f0fee8": "匹配條件",
|
||||
"K10650c58": "數據脫敏規則",
|
||||
"K1b34a9ab": "配置脫敏規則",
|
||||
"K26d22405": "匹配值",
|
||||
"K1546e1fe": "脫敏類型",
|
||||
"K9b9b0629": "起始位置",
|
||||
"K52c84fe1": "長度",
|
||||
"Kde84409c": "替換類型",
|
||||
"K338653b4": "替換值",
|
||||
"Kbaeed3b7": "JSON路徑",
|
||||
"K4cd91d61": "脫敏規則",
|
||||
"K8dcad979": "自訂字串; 值:",
|
||||
"K82e3f7b7": "起始位置:(0)位;長度:(1)位",
|
||||
"K49dfc123": "已選擇(0)項(1)數據",
|
||||
"K8457ea34": "所有(0)",
|
||||
"K7ca9a795": "屬性名稱",
|
||||
"Kc4391744": "屬性值",
|
||||
"K678e13fc": "配置(0)",
|
||||
"K508d8bf4": "集成地址",
|
||||
"K67f4e9bb": "與外部平台集成時,用於獲取 API 市場文檔信息的域名",
|
||||
"K1da86266": "無效",
|
||||
"K3a34d49b": "待更新",
|
||||
"Kd2850420": "待刪除",
|
||||
"K9ada4366": "操作成功,即將刷新頁面",
|
||||
"K9b332ab1": "請求前綴",
|
||||
"K3d78d483": "HTTP 標頭",
|
||||
"K17dc3a62": "數據日誌",
|
||||
"Ke429194e": "處理日誌",
|
||||
"K84ffb1dd": "輸入調用地址、消費者 IP 和消費者條件進行查找",
|
||||
"Kb147fabc": "新建",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "內容",
|
||||
"K2f5fdf5e": "調用地址",
|
||||
"K1bc5e0a3": "消費者 IP",
|
||||
"K6f39ea21": "鑑權名稱",
|
||||
"K8c34c02f": "脫敏前",
|
||||
"K8e3d388d": "脫敏後"
|
||||
}
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { MenuProps } from "antd";
|
||||
|
||||
|
||||
export type MenuItem = Required<MenuProps>['items'][number];
|
||||
|
||||
export function getNavItem(
|
||||
label: React.ReactNode,
|
||||
key: React.Key,
|
||||
path:string,
|
||||
icon?: React.ReactNode,
|
||||
children?: MenuItem[],
|
||||
type?: 'group',
|
||||
access?:string[] | string
|
||||
): MenuItem {
|
||||
export function getNavItem({
|
||||
label,
|
||||
key,
|
||||
path,
|
||||
icon,
|
||||
children,
|
||||
type,
|
||||
access
|
||||
}: {
|
||||
label: React.ReactNode;
|
||||
key: React.Key;
|
||||
path?: string;
|
||||
icon?: React.ReactNode;
|
||||
children?: MenuItem[];
|
||||
type?: 'group';
|
||||
access?: string[] | string;
|
||||
}): MenuItem {
|
||||
return {
|
||||
key,
|
||||
icon :icon ,
|
||||
path,
|
||||
icon,
|
||||
routes:children,
|
||||
name:label,
|
||||
type,
|
||||
access
|
||||
access,
|
||||
path
|
||||
} as MenuItem;
|
||||
}
|
||||
|
||||
@@ -53,4 +62,19 @@ export function getItem(
|
||||
label,
|
||||
access
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function transformMenuData(data: any[]): MenuItem[] {
|
||||
return data.map(item => {
|
||||
const { name, key, path, icon, children, access } = item;
|
||||
return getNavItem({
|
||||
label:name,
|
||||
key,
|
||||
path,
|
||||
icon: icon ? <Icon icon={icon} width="18" height="18" /> : undefined,
|
||||
children:children ? transformMenuData(children) : undefined,
|
||||
access}
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import { CoreObj, PluginConfigType, PluginRouterConfig, RouteConfig, RouterMapConfig } from '@common/const/type';
|
||||
import { isFunction } from 'lodash-es'
|
||||
// @ts-expect-error module cannot find
|
||||
import { __federation_method_setRemote,__federation_method_getRemote,__federation_method_unwrapDefault } from 'virtual:__federation__';
|
||||
import { ApiparkPluginDriverType } from '@common/const/type';
|
||||
import React from 'react';
|
||||
|
||||
interface RemoteModuleConfig{
|
||||
type:string
|
||||
remoteEntry:string
|
||||
exposedModule:string
|
||||
remoteName:string
|
||||
}
|
||||
|
||||
export async function loadRemoteModule(remoteModuleConfig:RemoteModuleConfig){
|
||||
__federation_method_setRemote(remoteModuleConfig.remoteName, {
|
||||
url: () => Promise.resolve(remoteModuleConfig.remoteEntry),
|
||||
format: 'esm',
|
||||
from: 'vite',
|
||||
});
|
||||
return await __federation_method_getRemote(
|
||||
remoteModuleConfig.remoteName,
|
||||
`./${remoteModuleConfig.exposedModule}`
|
||||
)
|
||||
}
|
||||
|
||||
export function generateRemoteModuleTemplate(
|
||||
pluginName: string,
|
||||
exposedModule: string,
|
||||
pluginPath: string
|
||||
):RemoteModuleConfig {
|
||||
return {
|
||||
type: 'module',
|
||||
remoteEntry: pluginPath,
|
||||
exposedModule,
|
||||
remoteName: pluginName
|
||||
}
|
||||
}
|
||||
|
||||
/** check the lifecycle method of plugin */
|
||||
export function validateExportLifecycle(exports: unknown) {
|
||||
const { bootstrap, mount, unmount } = exports ?? {}
|
||||
return isFunction(bootstrap) && isFunction(mount) && isFunction(unmount)
|
||||
}
|
||||
|
||||
export const DEFAULT_LOCAL_PLUGIN_PATH = '/plugin-frontend/'
|
||||
|
||||
export const ApiparkPluginDriver = (routerMap: Map<string, RouterMapConfig>): ApiparkPluginDriverType => { return {
|
||||
builtIn: {
|
||||
component: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
routerMap.get(pluginConfig.name) && coreObj.pluginProvider.setRouterConfig(pluginRouter.type === 'root' , {
|
||||
...routerMap.get(pluginConfig.name)!,
|
||||
key:pluginConfig.name,
|
||||
path:pluginRouter.path})
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
remote: {
|
||||
normal: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
const routerToChanged:RouteConfig[] = coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
const remoteRouter:RouteConfig[] = routerToChanged.find((item:RouteConfig) => item?.data?.['type'] === 'remotePlugin') as RouteConfig[]
|
||||
if (!remoteRouter) {
|
||||
routerMap.get('remote') && coreObj.pluginProvider.setRouterConfig(false,{
|
||||
...routerMap.get('remote')!, key:'remote', path:'remote',type:'remotePlugin',children:[{
|
||||
path:':moduleName',
|
||||
component: routerMap.get('remote')!.component}
|
||||
]
|
||||
})
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
intelligent: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
normal: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
if(['logsettings','resourcesettings'].indexOf(pluginConfig.name) !== -1){
|
||||
const routerToChanged:RouteConfig[] = coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
const remoteRouter:RouteConfig[] = routerToChanged.find((item:RouteConfig) => item?.data?.['key'] === pluginConfig.name) as RouteConfig[]
|
||||
if(!remoteRouter){
|
||||
routerMap.get(pluginConfig.name) && routerToChanged.unshift({...routerMap.get(pluginConfig.name)!, key:pluginConfig.name, path:pluginConfig.path})
|
||||
}
|
||||
return
|
||||
}
|
||||
const remoteRouter = coreObj.routerConfig.find((item:RouteConfig) => item?.data?.['type'] === 'intelligentPlugin')
|
||||
if (!remoteRouter) {
|
||||
// coreObj.pluginProvider.setRouterConfig(false, {
|
||||
// path: 'template',
|
||||
// loadChildren: coreObj.builtInPluginLoader('intelligent'),
|
||||
// data: {
|
||||
// type: 'intelligentPlugin'
|
||||
// }
|
||||
// }, coreObj.routerConfig)
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
local: {
|
||||
router: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
if (pluginRouter.type === 'sub') {
|
||||
continue
|
||||
}
|
||||
updateRouterConfigWithPlugin(coreObj, pluginRouter, pluginConfig)
|
||||
}
|
||||
return coreObj
|
||||
},
|
||||
preload: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
coreObj.setExecuteList(prev=>[...prev,{ ...pluginConfig, expose: 'Bootstrap', bootstrap: 'BootstrapModule.bootstrap' }])
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
updateRouterConfigWithPlugin(coreObj, pluginRouter, pluginConfig)
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
// extender: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
async function updateRouterConfigWithPlugin (coreObj: CoreObj, pluginRouter: PluginRouterConfig, pluginConfig: PluginConfigType) {
|
||||
if (!pluginRouter.expose) {
|
||||
throw new Error('pluginRouter.expose is required')
|
||||
} else {
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
const loadedModule = await coreObj.pluginLoader.loadModule(
|
||||
pluginRouter.path,
|
||||
pluginConfig.name,
|
||||
pluginRouter.expose!,
|
||||
pluginConfig.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${pluginConfig.name}/apipark.js`
|
||||
)
|
||||
const loadedModulePage = loadedModule[pluginRouter.expose!]
|
||||
const LazyComponent = React.lazy(() => Promise.resolve({ default: loadedModulePage?.default || loadedModulePage }));
|
||||
|
||||
const newRouter: RouteConfig = {
|
||||
path: pluginRouter.path,
|
||||
key: pluginConfig.name,
|
||||
lazy: () => Promise.resolve({ default: (props: any) => <LazyComponent {...props} /> }),
|
||||
pathPrefix: pluginRouter.path.endsWith('/*') ? pluginRouter.path.slice(0, -2) : pluginRouter.path,
|
||||
lifecycle:{
|
||||
canActivate: loadedModule?.beforeMount,
|
||||
canLoad: loadedModule?.mount,
|
||||
canDeactivate: loadedModule?.beforeUnmount,
|
||||
deactivated: loadedModule?.unmount
|
||||
}
|
||||
};
|
||||
coreObj.pluginProvider.setRouterConfig(pluginRouter.type === 'root' , newRouter)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,38 @@ export const validateUrlSlash = (_, value) => {
|
||||
if (value && value.includes('//')) {
|
||||
return Promise.reject(new Error($t('暂不支持带有双斜杠//的url')));
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
export const validateIPorCIDR = (rule, value) => {
|
||||
if (!value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const lines = value.split('\n');
|
||||
const ipCidrRegex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/([0-9]|[1-2][0-9]|3[0-2]))?$/;
|
||||
|
||||
for (const line of lines) {
|
||||
if (line && !ipCidrRegex.test(line.trim())) {
|
||||
return Promise.reject($t('输入的IP或CIDR不符合格式'));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
|
||||
export const validateApiPath = (rule, value) => {
|
||||
if (!value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const invalidCharsRegex = /[^a-zA-Z0-9\-\/\*]/;
|
||||
const validPathRegex = /^(\/?\*?\/?[a-zA-Z0-9\-\/\*]*)$/;
|
||||
|
||||
if (value && (invalidCharsRegex.test(value.trim()) || !validPathRegex.test(value.trim()))) {
|
||||
return Promise.reject($t('请正确输入路径,如/usr/*或*/usr/*'));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
@@ -299,4 +299,11 @@ a{
|
||||
a[disabled]:hover {
|
||||
color: #BBB;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.ant-input-group-addon{
|
||||
height:32px !important;
|
||||
.ant-btn.ant-btn-default{
|
||||
height:32px !important;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,16 @@
|
||||
|
||||
import './App.css'
|
||||
import { ConfigProvider, ConfigProviderProps, Radio, RadioChangeEvent } from 'antd';
|
||||
import { ConfigProvider, App as AppAntd } from 'antd';
|
||||
import RenderRoutes from '@core/components/aoplatform/RenderRoutes';
|
||||
import {BreadcrumbProvider} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
import zhTW from 'antd/locale/zh_TW';
|
||||
import jaJP from 'antd/locale/ja_JP';
|
||||
import useInitializeMonaco from "@common/hooks/useInitializeMonaco";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/zh-tw';
|
||||
import 'dayjs/locale/ja';
|
||||
import dayjs from 'dayjs';
|
||||
import { useGlobalContext } from '@common/contexts/GlobalStateContext';
|
||||
import { useMemo } from 'react';
|
||||
import { GlobalProvider } from '@common/contexts/GlobalStateContext';
|
||||
import { $t } from '@common/locales';
|
||||
|
||||
type Locale = ConfigProviderProps['locale'];
|
||||
|
||||
const languageMap: Record<string, Locale> = {
|
||||
'zh-CN':zhCN,
|
||||
'en-US':enUS,
|
||||
'zh-TW':zhTW,
|
||||
'ja-JP':jaJP
|
||||
}
|
||||
import { PluginEventHubProvider } from '@common/contexts/PluginEventHubContext';
|
||||
import { PluginSlotHubProvider } from '@common/contexts/PluginSlotHubContext';
|
||||
import { useLocaleContext } from '@common/contexts/LocaleContext';
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
|
||||
|
||||
const antdComponentThemeToken = {
|
||||
@@ -150,33 +136,35 @@ const antdComponentThemeToken = {
|
||||
|
||||
|
||||
function App() {
|
||||
const [locale, setLocal] = useState<Locale>();
|
||||
const { locale } = useLocaleContext();
|
||||
useInitializeMonaco()
|
||||
const { state} = useGlobalContext()
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dayjs.locale(state.language);
|
||||
setLocal(languageMap[state.language]);
|
||||
},[state.language])
|
||||
|
||||
const validateMessages = useMemo(()=>({
|
||||
required: $t('必填项'),
|
||||
email:$t('不是有效邮箱地址')}
|
||||
),[state.language])
|
||||
),[locale])
|
||||
|
||||
return (
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={locale}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}
|
||||
form={{validateMessages }}>
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={locale}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}
|
||||
form={{validateMessages }}>
|
||||
<PluginEventHubProvider>
|
||||
<AppAntd className="h-full" message={{ maxCount: 1 }}>
|
||||
<PluginSlotHubProvider>
|
||||
<GlobalProvider>
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</GlobalProvider>
|
||||
</PluginSlotHubProvider>
|
||||
</AppAntd>
|
||||
</PluginEventHubProvider>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,582 +1,95 @@
|
||||
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from 'react-router-dom';
|
||||
import Login from "@core/pages/Login.tsx"
|
||||
import { Navigate, RouterProvider, createBrowserRouter, RouteObject } from 'react-router-dom';
|
||||
import BasicLayout from '@common/components/aoplatform/BasicLayout';
|
||||
import { createElement, ReactElement, ReactNode, Suspense } from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { App, Skeleton } from "antd";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx";
|
||||
import { FC, lazy } from 'react';
|
||||
import { TeamProvider } from '@core/contexts/TeamContext.tsx';
|
||||
import { TenantManagementProvider } from '@market/contexts/TenantManagementContext.tsx';
|
||||
import Guide from '@core/pages/guide/Guide';
|
||||
import { AiServiceProvider } from '@core/contexts/AiServiceContext';
|
||||
import AiServiceOutlet from '@core/pages/aiService/AiServiceOutlet';
|
||||
import SystemOutlet from '@core/pages/system/SystemOutlet';
|
||||
import { SystemProvider } from '@core/contexts/SystemContext';
|
||||
import {createElement,Suspense, useEffect, useState} from 'react';
|
||||
import {Skeleton, Spin} from "antd";
|
||||
import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx";
|
||||
import usePluginLoader from '@common/hooks/pluginLoader.ts';
|
||||
import { RouteConfig } from '@common/const/type.ts';
|
||||
import { ApiparkPluginDriver } from '@common/utils/plugin.tsx';
|
||||
import { routerMap } from '@core/const/const';
|
||||
import withRouteGuard from "@common/components/aoplatform/WithRouteGuard.tsx";
|
||||
import ErrorBoundary from "@common/components/aoplatform/ErrorBoundary";
|
||||
import React from 'react';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
|
||||
type RouteConfig = {
|
||||
path: string
|
||||
component?: ReactElement
|
||||
children?: (RouteConfig | false)[]
|
||||
key: string
|
||||
provider?: FC<{ children: ReactNode; }>
|
||||
lazy?: unknown
|
||||
}
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
const RenderRoutes = ()=> {
|
||||
const { loadPlugins,loadExecutedPlugin } = usePluginLoader(ApiparkPluginDriver(routerMap), routerMap)
|
||||
const { routeConfig,dispatch,state } = useGlobalContext();
|
||||
const [router, setRouter] = useState<unknown>(null);
|
||||
|
||||
useEffect(()=>{
|
||||
loadPlugins().then(()=>{
|
||||
loadExecutedPlugin()
|
||||
})
|
||||
},[])
|
||||
|
||||
export type RouterParams = {
|
||||
teamId: string
|
||||
apiId: string
|
||||
serviceId: string
|
||||
clusterId: string;
|
||||
memberGroupId: string
|
||||
userGroupId: string
|
||||
pluginName: string
|
||||
moduleId: string
|
||||
accessType: 'project' | 'team' | 'service'
|
||||
categoryId: string
|
||||
tagId: string
|
||||
dashboardType: string
|
||||
dashboardDetailId: string
|
||||
topologyId: string
|
||||
appId: string
|
||||
roleType: string
|
||||
roleId: string
|
||||
routeId: string
|
||||
}
|
||||
useEffect(() => {
|
||||
if (routeConfig && routeConfig.length > 0) {
|
||||
const routerInstance = createBrowserRouter(generateRoutes(routeConfig));
|
||||
setRouter(routerInstance);
|
||||
dispatch({ type: 'SET_PLUGINS_LOADED', pluginsLoaded: true });
|
||||
}
|
||||
}, [routeConfig]);
|
||||
|
||||
const PUBLIC_ROUTES: RouteConfig[] = [
|
||||
{
|
||||
path: '/',
|
||||
component: <Login />,
|
||||
key: uuidv4(),
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
component: <Login />,
|
||||
key: uuidv4()
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: <ProtectedRoute />,
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
// {
|
||||
// path:'approval/*',
|
||||
// component:<ApprovalPage />,
|
||||
// key:uuidv4()
|
||||
// },
|
||||
{
|
||||
path: 'guide/*',
|
||||
component: <Guide />,
|
||||
key: uuidv4()
|
||||
},
|
||||
{
|
||||
path: 'team',
|
||||
component: <Outlet />,
|
||||
key: uuidv4(),
|
||||
provider: TeamProvider,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamList.tsx'))
|
||||
},
|
||||
{
|
||||
path: 'inside/:teamId',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsidePage.tsx')),
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
{
|
||||
path: 'member',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsideMember.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'setting',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamConfig.tsx')),
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'service',
|
||||
key: uuidv4(),
|
||||
component: <SystemOutlet />,
|
||||
provider: SystemProvider,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'list/:teamId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path: ':teamId',
|
||||
component: <Outlet />,
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
{
|
||||
path: 'inside/:serviceId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsidePage.tsx')),
|
||||
children: [
|
||||
{
|
||||
path: 'api',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideApiDocument.tsx')),
|
||||
},
|
||||
{
|
||||
|
||||
path: 'route/create',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
|
||||
path: 'route/:routeId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
path: 'route',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
},
|
||||
{
|
||||
path: 'upstream',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/upstream/SystemInsideUpstreamContent.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'document',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'subscriber',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideSubscriber.tsx')),
|
||||
children: [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'approval',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApproval.tsx')),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'topology',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemTopology.tsx')),
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'publish',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublish.tsx')),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'setting',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
children: [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'servicePolicy',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy'))
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'aiInside/:serviceId',
|
||||
component: <AiServiceOutlet />,
|
||||
provider: AiServiceProvider,
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsidePage.tsx')),
|
||||
children: [
|
||||
{
|
||||
path: 'api',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideApiDocument')),
|
||||
},
|
||||
{
|
||||
|
||||
path: 'route/create',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
|
||||
path: 'route/:routeId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
path: 'route',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterList')),
|
||||
},
|
||||
{
|
||||
path: 'document',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'subscriber',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideSubscriber.tsx')),
|
||||
children: [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'approval',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApproval')),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'publish',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublish')),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'setting',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
children: [
|
||||
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'datasourcing',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideDashboardSetting.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'cluster',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCluster.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'aisetting',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiSetting/AiSettingList.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'cert',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCert.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'globalPolicy',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/globalPolicy')),
|
||||
},
|
||||
{
|
||||
path: 'serviceHub',
|
||||
component: <Outlet />,
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubList.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'detail/:serviceId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubDetail.tsx')),
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: 'commonsetting',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/common/CommonPage.tsx')),
|
||||
key: uuidv4(),
|
||||
},
|
||||
{
|
||||
path: 'consumer',
|
||||
component: <Outlet />,
|
||||
provider: TenantManagementProvider,
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path: ':teamId/inside/:appId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsidePage.tsx')),
|
||||
children: [
|
||||
{
|
||||
path: 'service',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideService.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'authorization',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideAuth.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'setting',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementAppSetting.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'list/:teamId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'member',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberPage.tsx')),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
},
|
||||
{
|
||||
path: 'list/:memberGroupId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'role',
|
||||
key: uuidv4(),
|
||||
component: <Outlet />,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleList.tsx')),
|
||||
}, {
|
||||
path: ':roleType/config/:roleId',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
}, {
|
||||
path: ':roleType/config',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'assets',
|
||||
component: <p>设计中</p>,
|
||||
key: uuidv4()
|
||||
},
|
||||
{
|
||||
path: 'analytics',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/Dashboard.tsx')),
|
||||
key: uuidv4(),
|
||||
children: [
|
||||
{
|
||||
path: 'total',
|
||||
key: uuidv4(),
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardTotal.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'template/:moduleId',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key: uuidv4()
|
||||
},
|
||||
{
|
||||
path: 'logsettings/*',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/logsettings/LogSettings.tsx')),
|
||||
key: uuidv4(),
|
||||
children: [{
|
||||
path: 'template/:moduleId',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key: uuidv4()
|
||||
}]
|
||||
|
||||
},
|
||||
APP_MODE === 'pro' && {
|
||||
path: 'resourcesettings/*',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/resourcesettings/ResourceSettings.tsx')),
|
||||
key: uuidv4(),
|
||||
children: [{
|
||||
path: 'template/:moduleId',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key: uuidv4()
|
||||
}]
|
||||
|
||||
},
|
||||
{
|
||||
path: 'userProfile/*',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')),
|
||||
key: uuidv4(),
|
||||
children: [{
|
||||
path: 'changepsw',
|
||||
lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')),
|
||||
key: uuidv4()
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
const RenderRoutes = () => {
|
||||
return (
|
||||
<App className="h-full" message={{ maxCount: 1 }}>
|
||||
<Router>
|
||||
<Routes>
|
||||
{generateRoutes(PUBLIC_ROUTES)}
|
||||
</Routes>
|
||||
</Router>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
const generateRoutes = (routerConfig: RouteConfig[]) => {
|
||||
return routerConfig?.map((route: RouteConfig) => {
|
||||
let routeElement;
|
||||
if (route.lazy) {
|
||||
const LazyComponent = route.lazy as React.ExoticComponent<unknown>;
|
||||
|
||||
routeElement = (
|
||||
<Suspense fallback={<div className=''><Skeleton className='m-btnbase w-calc-100vw-minus-padding-r' active /></div>}>
|
||||
{route.provider ? (
|
||||
createElement(route.provider, {}, <LazyComponent />)
|
||||
) : (
|
||||
<LazyComponent />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
} else {
|
||||
routeElement = route.provider ? (
|
||||
createElement(route.provider, {}, route.component)
|
||||
) : (
|
||||
route.component
|
||||
);
|
||||
if (!router || !state?.pluginsLoaded) {
|
||||
return <Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={true} className='w-full h-full flex items-center justify-center'></Spin>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Route
|
||||
key={route.key}
|
||||
path={route.path}
|
||||
element={routeElement}
|
||||
>
|
||||
{route.children && generateRoutes(route.children as RouteConfig[])}
|
||||
</Route>
|
||||
<RouterProvider router={router} />
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const generateRoutes = (routerConfig: RouteConfig[]):RouteObject[] => {
|
||||
return routerConfig?.map((route: RouteConfig) => {
|
||||
let routeElement;
|
||||
if (route.lazy) {
|
||||
let LazyComponent;
|
||||
if (typeof route.lazy === 'function') {
|
||||
const result = route.lazy();
|
||||
if (result instanceof Promise) {
|
||||
LazyComponent = React.lazy(() => result.then(module => ({ default: module.default || module })));
|
||||
} else {
|
||||
LazyComponent = result;
|
||||
}
|
||||
} else {
|
||||
LazyComponent = route.lazy;
|
||||
}
|
||||
const GuardedComponent = route.lifecycle ? withRouteGuard(LazyComponent, {pathPrefix:`/${route.pathPrefix ?? route.path}`, ...route.lifecycle}): LazyComponent
|
||||
routeElement = (
|
||||
<Suspense fallback={ <div className=''><Skeleton className='m-btnbase w-calc-100vw-minus-padding-r' active /></div>}>
|
||||
{route.provider ? (
|
||||
createElement(route.provider, {}, <GuardedComponent />)
|
||||
) : (
|
||||
<GuardedComponent />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
} else {
|
||||
routeElement = route.provider ? (
|
||||
createElement(route.provider, {}, route.component)
|
||||
) : (
|
||||
route.component
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
{
|
||||
path: route.path,
|
||||
element: <ErrorBoundary>{routeElement}</ErrorBoundary> ,
|
||||
children: route.children ? generateRoutes(route.children as RouteConfig[]) : undefined,
|
||||
exact:route?.pathMatch === 'full'
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 保护的路由组件
|
||||
function ProtectedRoute() {
|
||||
const { state } = useGlobalContext()
|
||||
return state.isAuthenticated ? <BasicLayout project="core" /> : <Navigate to="/login" />;
|
||||
}
|
||||
export function ProtectedRoute() {
|
||||
// return state.isAuthenticated? <BasicLayout project="core" /> : <Navigate to="/login" />;
|
||||
return <BasicLayout project="core" />
|
||||
}
|
||||
|
||||
export default RenderRoutes
|
||||
export default RenderRoutes
|
||||
|
||||
@@ -0,0 +1,533 @@
|
||||
import component from '@common/components/aoplatform/prompt-editor/plugins/workflow-variable-block/component';
|
||||
import { RouterMapConfig } from '@common/const/type';
|
||||
import { ProtectedRoute } from '@core/components/aoplatform/RenderRoutes';
|
||||
import { AiServiceProvider } from '@core/contexts/AiServiceContext';
|
||||
import { SystemProvider } from '@core/contexts/SystemContext';
|
||||
import { TeamProvider } from '@core/contexts/TeamContext';
|
||||
import AiServiceOutlet from '@core/pages/aiService/AiServiceOutlet';
|
||||
import Guide from '@core/pages/guide/Guide';
|
||||
import Login from '@core/pages/Login';
|
||||
import ServicePolicyLayout from '@core/pages/policy/ServicePolicyLayout';
|
||||
import SystemOutlet from '@core/pages/system/SystemOutlet';
|
||||
import { TenantManagementProvider } from '@market/contexts/TenantManagementContext';
|
||||
import { lazy } from 'react';
|
||||
import { Outlet, Navigate } from 'react-router-dom';
|
||||
|
||||
|
||||
// 内置插件与对应组件/模块
|
||||
export const routerMap:Map<string, RouterMapConfig> = new Map([
|
||||
['basicLayout', { type: 'component', component: <ProtectedRoute />}],
|
||||
['navHidden', { type: 'component', component: <ProtectedRoute /> }],
|
||||
['login', { type: 'component', component: <Login /> }],
|
||||
['guide',{
|
||||
type:'component',
|
||||
component:<Guide />
|
||||
}],
|
||||
['team', {type: 'module',
|
||||
component:<Outlet/>,
|
||||
key: 'team',
|
||||
provider: TeamProvider,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: 'teamList',
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key: 'teamList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamList.tsx'))
|
||||
},
|
||||
{
|
||||
path:'inside/:teamId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsidePage.tsx')),
|
||||
key: 'teamInside',
|
||||
children:[
|
||||
{
|
||||
path:'member',
|
||||
key: 'teamMember',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsideMember.tsx')),
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: 'teamSetting',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamConfig.tsx')),
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}],
|
||||
['service', {
|
||||
type: 'module',
|
||||
path:'service',
|
||||
component:<SystemOutlet />,
|
||||
key: 'service',
|
||||
provider: SystemProvider,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:'serviceList',
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key: 'serviceList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:teamId',
|
||||
key: 'serviceList3',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path:':teamId',
|
||||
component:<Outlet/>,
|
||||
key: 'serviceInside',
|
||||
children:[
|
||||
{
|
||||
path:'inside/:serviceId',
|
||||
key: 'restServiceInside',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'api',
|
||||
key: 'restServiceInsideApi',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideApiDocument.tsx')),
|
||||
},
|
||||
{
|
||||
|
||||
path:'route/create',
|
||||
key: 'restServiceInsideRouteCreate',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
|
||||
path:'route/:routeId',
|
||||
key: 'restServiceInsideRouteEdit',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
path:'route',
|
||||
key: 'restServiceInsideRoute',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
},
|
||||
{
|
||||
path:'upstream',
|
||||
key: 'restServiceInsideUpstream',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/upstream/SystemInsideUpstreamContent.tsx')),
|
||||
},
|
||||
{
|
||||
path:'document',
|
||||
key: 'restServiceInsideDocument',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path:'subscriber',
|
||||
key: 'restServiceInsideSubscriber',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideSubscriber.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'approval',
|
||||
key: 'restServiceInsideApproval',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApproval.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: 'restServiceInsideApprovalList',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: 'restServiceInsideApprovalList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'publish',
|
||||
key: 'systemPublish',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublish.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: 'systemPublishList',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: 'systemPublishList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: 'systemConfig',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'servicepolicy',
|
||||
key: 'servicepolicy',
|
||||
component:<ServicePolicyLayout />,
|
||||
children:[{
|
||||
path:'datamasking',
|
||||
component:<Outlet />,
|
||||
key:'dataMasking',
|
||||
children:[
|
||||
{
|
||||
path:'list',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy')),
|
||||
key:'dataMaskingList'
|
||||
},
|
||||
{
|
||||
path:'create',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')),
|
||||
key:'dataMaskingAdd'
|
||||
},
|
||||
{
|
||||
path:':policyId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')),
|
||||
key:'dataMaskingAdd'
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'aiInside/:serviceId',
|
||||
component:<AiServiceOutlet />,
|
||||
provider: AiServiceProvider,
|
||||
key: 'aiServiceInside',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'api',
|
||||
key: 'aiServiceInsideApi',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideApiDocument')),
|
||||
},
|
||||
{
|
||||
|
||||
path:'route/create',
|
||||
key: 'aiServiceInsideRouteCreate',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
|
||||
path:'route/:routeId',
|
||||
key: 'aiServiceInsideRouteEdit',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
path:'route',
|
||||
key: 'aiServiceInsideRouteList',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterList')),
|
||||
},
|
||||
{
|
||||
path:'document',
|
||||
key: 'aiServiceInsideDocument',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path:'subscriber',
|
||||
key: 'aiServiceInsideSubscriber',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideSubscriber.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'approval',
|
||||
key: 'aiServiceInsideApproval',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApproval')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: 'aiServiceInsideApprovalList',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: 'aiServiceInsideApprovalList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'publish',
|
||||
key: 'aiServiceInsidePublish',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublish')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: 'aiServiceInsidePublishList',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: 'aiServiceInsidePublishList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: 'aiServiceInsideSetting',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'servicepolicy',
|
||||
key: 'servicepolicy',
|
||||
component:<ServicePolicyLayout />,
|
||||
children:[{
|
||||
path:'datamasking',
|
||||
component:<Outlet />,
|
||||
key:'dataMasking',
|
||||
children:[
|
||||
{
|
||||
path:'list',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy')),
|
||||
key:'dataMaskingList'
|
||||
},
|
||||
{
|
||||
path:'create',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')),
|
||||
key:'dataMaskingAdd'
|
||||
},
|
||||
{
|
||||
path:':policyId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')),
|
||||
key:'dataMaskingAdd'
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}],
|
||||
['datasourcing', { type: 'component',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideDashboardSetting.tsx'))
|
||||
}],
|
||||
['cluster', { type: 'component',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCluster.tsx')),
|
||||
}],
|
||||
['aisetting', { type: 'component',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiSetting/AiSettingList.tsx')),
|
||||
}],
|
||||
['cert', { type: 'component',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCert.tsx')),
|
||||
}],
|
||||
|
||||
['serviceHub', {
|
||||
type: 'module',
|
||||
component:<Outlet />,
|
||||
key:'serviceHub',
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: 'serviceHubList',
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:'serviceHubList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'detail/:serviceId',
|
||||
key:'serviceHubDetail',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubDetail.tsx')),
|
||||
}]
|
||||
}],
|
||||
|
||||
['commonsetting', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/common/CommonPage.tsx')),
|
||||
}],
|
||||
|
||||
['consumer', { type: 'module',
|
||||
component:<Outlet />,
|
||||
provider:TenantManagementProvider,
|
||||
key:'consumer',
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:'consumerList',
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:':teamId/inside/:appId',
|
||||
key:'consumerInside',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'service',
|
||||
key:'consumerInsideService',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideService.tsx')),
|
||||
},
|
||||
{
|
||||
path:'authorization',
|
||||
key:'consumerInsideAuthorization',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideAuth.tsx')),
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key:'consumerSetting',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementAppSetting.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:'serviceHubManagementList',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:teamId',
|
||||
key:'serviceHubManagementList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
]}],
|
||||
['member', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberPage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:'memberList',
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:'memberList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:memberGroupId',
|
||||
key:'memberList3',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
}
|
||||
],
|
||||
}],
|
||||
['role', { type: 'module',
|
||||
component:<Outlet></Outlet>,
|
||||
children:[
|
||||
{
|
||||
path: '',
|
||||
key: 'roleList',
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:'roleList2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleList.tsx')),
|
||||
},
|
||||
{
|
||||
path:':roleType/config/:roleId',
|
||||
key:'roleConfig',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
},
|
||||
{
|
||||
path:':roleType/config',
|
||||
key:'roleConfig2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
}
|
||||
]
|
||||
}],
|
||||
['analytics', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/Dashboard.tsx')),
|
||||
key:'analytics',
|
||||
children:[
|
||||
{
|
||||
path:'total',
|
||||
key:'analytics2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardTotal.tsx')),
|
||||
},
|
||||
{
|
||||
path:':dashboardType',
|
||||
key:'analytics3',
|
||||
component:<Outlet />,
|
||||
children:[
|
||||
{
|
||||
path:'list',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardList.tsx')),
|
||||
key:'analyticsList'
|
||||
},
|
||||
{
|
||||
path:'detail/:dashboardDetailId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardDetail.tsx')),
|
||||
key:'analyticsDetail'
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}],
|
||||
['template', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
}],
|
||||
['logsettings', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/logsettings/LogSettings.tsx')),
|
||||
key:'logsettings',
|
||||
children:[
|
||||
{
|
||||
path:'template/:moduleId',
|
||||
key:'logSettings2',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
},
|
||||
]
|
||||
}],
|
||||
['resourcesettings', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/resourcesettings/ResourceSettings.tsx')),
|
||||
key:'resourcesettings',
|
||||
children:[
|
||||
{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:'resourceSettings2'
|
||||
},
|
||||
]
|
||||
}],
|
||||
['userProfile', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')),
|
||||
key:'userProfile',
|
||||
children:[{
|
||||
path:'changepsw',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')),
|
||||
key:'changePsw'
|
||||
}]}],
|
||||
['globalPolicy', { type: 'module',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/GlobalPolicyLayout')),
|
||||
key:'globalPolicy',
|
||||
children:[{
|
||||
path:'datamasking',
|
||||
component:<Outlet />,
|
||||
key:'dataMasking',
|
||||
children:[
|
||||
{
|
||||
path:'list',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/globalPolicy')),
|
||||
key:'dataMaskingList'
|
||||
},
|
||||
{
|
||||
path:'create',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')),
|
||||
key:'dataMaskingAdd'
|
||||
},
|
||||
{
|
||||
path:':policyId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')),
|
||||
key:'dataMaskingAdd'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
])
|
||||
@@ -1,115 +1,157 @@
|
||||
|
||||
import { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { COLUMNS_TITLE } from "@common/const/const";
|
||||
import { EntityItem } from "@common/const/type";
|
||||
|
||||
export type PartitionConfigFieldType = {
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
prefix?:string
|
||||
url?:string
|
||||
managerAddress?:string
|
||||
canDelete?:boolean
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
prefix?: string
|
||||
url?: string
|
||||
managerAddress?: string
|
||||
canDelete?: boolean
|
||||
};
|
||||
|
||||
export type PartitionCertTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
domains:string[];
|
||||
notAfter:string;
|
||||
notBefore:string;
|
||||
updater:EntityItem;
|
||||
updateTime:string;
|
||||
id: string;
|
||||
name: string;
|
||||
domains: string[];
|
||||
notAfter: string;
|
||||
notBefore: string;
|
||||
updater: EntityItem;
|
||||
updateTime: string;
|
||||
};
|
||||
|
||||
export type PartitionCertConfigFieldType = {
|
||||
id?:string
|
||||
key:string
|
||||
pem:string
|
||||
id?: string
|
||||
key: string
|
||||
pem: string
|
||||
};
|
||||
|
||||
export type PartitionCertConfigProps = {
|
||||
type:'add'|'edit'
|
||||
entity?:PartitionCertConfigFieldType
|
||||
type: 'add' | 'edit'
|
||||
entity?: PartitionCertConfigFieldType
|
||||
}
|
||||
|
||||
export type PartitionCertConfigHandle = {
|
||||
save:()=>Promise<boolean|string>
|
||||
save: () => Promise<boolean | string>
|
||||
}
|
||||
|
||||
export type PartitionClusterFieldType = {
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
address?:string;
|
||||
protocol?:'http'|'https'
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
address?: string;
|
||||
protocol?: 'http' | 'https'
|
||||
};
|
||||
|
||||
export type ClusterConfigProps = {
|
||||
mode:'config' | 'retry' | 'result' | 'edit',
|
||||
clusterId?:string
|
||||
initFormValue?:{[k:string]:string|number}
|
||||
mode: 'config' | 'retry' | 'result' | 'edit',
|
||||
clusterId?: string
|
||||
initFormValue?: { [k: string]: string | number }
|
||||
}
|
||||
|
||||
export type ClusterConfigHandle = {
|
||||
save:()=>Promise<boolean|string>
|
||||
check:()=>Promise<boolean>
|
||||
save: () => Promise<boolean | string>
|
||||
check: () => Promise<boolean>
|
||||
}
|
||||
|
||||
export type PartitionClusterTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
status:0|1;
|
||||
description:string;
|
||||
id: string;
|
||||
name: string;
|
||||
status: 0 | 1;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type PartitionClusterNodeTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
managerAddress:string[];
|
||||
serviceAddress:string[];
|
||||
peerAddress:string[];
|
||||
status:0|1;
|
||||
id: string;
|
||||
name: string;
|
||||
managerAddress: string[];
|
||||
serviceAddress: string[];
|
||||
peerAddress: string[];
|
||||
status: 0 | 1;
|
||||
};
|
||||
|
||||
export type PartitionClusterNodeModalTableListItem = {
|
||||
id: string,
|
||||
name: string,
|
||||
managerAddress: [],
|
||||
serviceAddress: [],
|
||||
peerAddress: string,
|
||||
status: string
|
||||
id: string,
|
||||
name: string,
|
||||
managerAddress: [],
|
||||
serviceAddress: [],
|
||||
peerAddress: string,
|
||||
status: string
|
||||
}
|
||||
|
||||
export type NodeModalFieldType = {
|
||||
address:string
|
||||
address: string
|
||||
}
|
||||
|
||||
|
||||
export type NodeModalHandle = {
|
||||
save:()=>void
|
||||
save: () => void
|
||||
}
|
||||
export type NodeModalPropsType = {
|
||||
changeStatus:(status:ClusterPageShowStatus)=>void
|
||||
getClusterInfo:()=>void
|
||||
status:ClusterPageShowStatus
|
||||
changeStatus: (status: ClusterPageShowStatus) => void
|
||||
getClusterInfo: () => void
|
||||
status: ClusterPageShowStatus
|
||||
}
|
||||
|
||||
export type ClusterPageShowStatus = 'view'|'preview'|'edit'
|
||||
export type ClusterPageShowStatus = 'view' | 'preview' | 'edit'
|
||||
export type PartitionTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
clusterNum:number;
|
||||
updater:EntityItem;
|
||||
updateTime:string;
|
||||
id: string;
|
||||
name: string;
|
||||
clusterNum: number;
|
||||
updater: EntityItem;
|
||||
updateTime: string;
|
||||
};
|
||||
|
||||
export type SimplePartition = EntityItem & { clusters: (EntityItem & {description:string})[] }
|
||||
export type SimplePartition = EntityItem & { clusters: (EntityItem & { description: string })[] }
|
||||
|
||||
export type PartitionDashboardConfigFieldType = {
|
||||
driver:string
|
||||
config:{
|
||||
org:string
|
||||
token:string
|
||||
addr:string
|
||||
driver: string
|
||||
config: {
|
||||
org: string
|
||||
token: string
|
||||
addr: string
|
||||
}
|
||||
}
|
||||
export type PartitionDataLogHeaderListFieldType = {
|
||||
key: string
|
||||
value: string
|
||||
|
||||
}
|
||||
export type PartitionDataLogConfigFieldType = {
|
||||
headers: PartitionDataLogHeaderListFieldType[]
|
||||
url: string
|
||||
}
|
||||
|
||||
export const PARTITION_DATA_LOG_CONFIG_TABLE_COLUMNS: PageProColumns<PartitionDataLogConfigFieldType & { _id: string }>[] = [
|
||||
{
|
||||
title: ('标签'),
|
||||
dataIndex: 'key',
|
||||
formItemProps: {
|
||||
className: 'p-0 bg-transparent border-none',
|
||||
rootClassName: 'test',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
whitespace: true
|
||||
},
|
||||
],
|
||||
},
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('内容'),
|
||||
dataIndex: 'value',
|
||||
formItemProps: {
|
||||
className: 'p-0 bg-transparent border-none'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: COLUMNS_TITLE.operate,
|
||||
valueType: 'option',
|
||||
btnNums: 2,
|
||||
render: () => null
|
||||
},
|
||||
];
|
||||
@@ -3,9 +3,10 @@ import { Input, TabsProps } from "antd";
|
||||
import { MatchItem } from "@common/const/type";
|
||||
import { ConfigField } from "@common/components/aoplatform/EditableTableWithModal";
|
||||
import { frontendTimeSorter } from "@common/utils/dataTransfer";
|
||||
import { COLUMNS_TITLE } from "@common/const/const";
|
||||
import { COLUMNS_TITLE, PLACEHOLDER } from "@common/const/const";
|
||||
|
||||
import { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { $t } from "@common/locales";
|
||||
|
||||
export enum SubscribeEnum{
|
||||
Rejected = 0,
|
||||
@@ -222,7 +223,7 @@ export const MATCH_CONFIG:ConfigField<MatchItem>[] = [
|
||||
}, {
|
||||
title:('参数名'),
|
||||
key: 'key',
|
||||
component: <Input className="w-INPUT_NORMAL" />,
|
||||
component: <Input className="w-INPUT_NORMAL"/>,
|
||||
renderText: (value: unknown) => value,
|
||||
required: true
|
||||
}, {
|
||||
@@ -236,7 +237,7 @@ export const MATCH_CONFIG:ConfigField<MatchItem>[] = [
|
||||
title:('参数值'),
|
||||
key: 'pattern',
|
||||
unRender:(formValue)=>{return formValue?.matchType === 'NULL' || formValue?.matchType==='EXIST' || formValue?.matchType === 'UNEXIST'},
|
||||
component: <Input className="w-INPUT_NORMAL"/>,
|
||||
component: <Input className="w-INPUT_NORMAL" />,
|
||||
renderText: (value: string) => {
|
||||
return value
|
||||
},
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
import {FC, createContext, useContext, useState, ReactNode } from 'react';
|
||||
import { PartitionConfigFieldType } from '../const/partitions/types.ts';
|
||||
|
||||
interface PartitionContextProps {
|
||||
partitionInfo:PartitionConfigFieldType|undefined
|
||||
setPartitionInfo:React.Dispatch<React.SetStateAction<PartitionConfigFieldType|undefined>>;
|
||||
}
|
||||
|
||||
const PartitionContext = createContext<PartitionContextProps | undefined>(undefined);
|
||||
|
||||
export const usePartitionContext = () => {
|
||||
const context = useContext(PartitionContext);
|
||||
if (!context) {
|
||||
throw new Error('useArray must be used within a ArrayProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const PartitionProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [partitionInfo, setPartitionInfo] = useState<PartitionConfigFieldType>()
|
||||
return <PartitionContext.Provider value={{ partitionInfo, setPartitionInfo }}>{children}</PartitionContext.Provider>;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
import { createContext, useContext, useState, ReactNode, FC } from 'react';
|
||||
import { MyServiceFieldType } from '../const/system/type.ts';
|
||||
|
||||
interface SystemMyServiceContextProps {
|
||||
serviceInfo:MyServiceFieldType|undefined
|
||||
setServiceInfo:React.Dispatch<React.SetStateAction<MyServiceFieldType|undefined>>;
|
||||
}
|
||||
|
||||
const SystemMyServiceContext = createContext<SystemMyServiceContextProps | undefined>(undefined);
|
||||
|
||||
export const useSystemMyServiceContext = () => {
|
||||
const context = useContext(SystemMyServiceContext);
|
||||
if (!context) {
|
||||
throw new Error('useArray must be used within a ArrayProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const SystemMyServiceProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [serviceInfo, setServiceInfo] = useState<MyServiceFieldType>()
|
||||
return <SystemMyServiceContext.Provider value={{ serviceInfo, setServiceInfo }}>{children}</SystemMyServiceContext.Provider>;
|
||||
};
|
||||
@@ -321,6 +321,11 @@ p{
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
scrollbar-width: auto;
|
||||
scrollbar-color: auto;
|
||||
}
|
||||
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
@@ -664,7 +669,7 @@ p{
|
||||
.ant-pro-table-list-toolbar-setting-items{
|
||||
position:absolute;
|
||||
top:18px;
|
||||
right:16px;
|
||||
right:22px;
|
||||
z-index:9;
|
||||
.ant-pro-table-list-toolbar-setting-item{
|
||||
font-size:14px;
|
||||
@@ -970,7 +975,7 @@ p{
|
||||
.ant-drawer-content-wrapper{
|
||||
min-width: 820px !important;
|
||||
.ant-table:not(.ant-table-bordered){
|
||||
border:1px solid var(--border-color) !important;
|
||||
/* border:1px solid var(--border-color) !important; */
|
||||
border-top:0px !important;
|
||||
}
|
||||
.ant-table:not(.ant-table-borderer){
|
||||
@@ -996,7 +1001,7 @@ p{
|
||||
.ant-modal-wrap:not(.height-fixed-modal){
|
||||
.ant-modal-body{
|
||||
.ant-table:not(.ant-table-bordered){
|
||||
border:1px solid var(--border-color) !important;
|
||||
/* border:1px solid var(--border-color) !important; */
|
||||
border-top:0px !important;
|
||||
}
|
||||
.ant-table:not(.ant-table-borderer){
|
||||
|
||||
@@ -3,8 +3,7 @@ import {StrictMode} from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
import {GlobalProvider} from "@common/contexts/GlobalStateContext.tsx";
|
||||
|
||||
import { LocaleProvider } from '@common/contexts/LocaleContext.tsx';
|
||||
async function initializeApp() {
|
||||
try {
|
||||
// 初始化行为
|
||||
@@ -13,9 +12,9 @@ async function initializeApp() {
|
||||
// 异步操作完成后,渲染React消费者
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<GlobalProvider>
|
||||
<LocaleProvider>
|
||||
<App />
|
||||
</GlobalProvider>
|
||||
</LocaleProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useCallback, useEffect, useRef, useState} from "react";
|
||||
import {App, Button, Divider, Form, FormInstance, Input, Tooltip} from "antd";
|
||||
import {App, Button, Divider, Form, FormInstance, Input, Spin, Tooltip} from "antd";
|
||||
import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import {BasicResponse, STATUS_CODE} from "@common/const/const.tsx";
|
||||
@@ -9,6 +9,7 @@ import Logo from '@common/assets/layout-logo.png'
|
||||
import { $t } from "@common/locales";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import LanguageSetting from "@common/components/aoplatform/LanguageSetting";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
|
||||
const Login:FC = ()=> {
|
||||
const {state, dispatch} = useGlobalContext()
|
||||
@@ -17,20 +18,21 @@ const Login:FC = ()=> {
|
||||
const navigate = useNavigate();
|
||||
const formRef = useRef<FormInstance>(null);
|
||||
const [loading,setLoading] = useState<boolean>()
|
||||
// const { encryptByEnAES } = useCrypto();
|
||||
const [allowGuest, setAllowGuest] = useState<boolean>(false)
|
||||
const [spinning,setSpinning] = useState<boolean>(false)
|
||||
|
||||
|
||||
const check = useCallback(()=>{
|
||||
state.isAuthenticated &&setSpinning(true)
|
||||
fetchData<BasicResponse<{channel:Array<{name:string}>, status:string}>>('account/login',{method:'GET'}).then(response=>{
|
||||
const {code,data} = response
|
||||
|
||||
if(code === STATUS_CODE.SUCCESS && data.status !== 'anonymous'){
|
||||
dispatch({type:'LOGIN'})
|
||||
navigate(state.mainPage)
|
||||
navigate(state.mainPage,{replace:true})
|
||||
}else{
|
||||
dispatch({type:'LOGOUT'})
|
||||
setAllowGuest(data.channel.filter(x=>x.name === 'guest_access').length > 0)
|
||||
setSpinning(false)
|
||||
}
|
||||
})
|
||||
},[])
|
||||
@@ -100,6 +102,8 @@ const Login:FC = ()=> {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
spinning?
|
||||
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={spinning} className='w-full h-full flex items-center justify-center'></Spin> :
|
||||
<div className="h-full w-full flex flex-col items-center overflow-auto min-h-[490px] bg-[#0d1117]">
|
||||
<div id="glow-background" className="background-container">
|
||||
<svg className="background-pattern" aria-hidden="true">
|
||||
@@ -206,7 +210,7 @@ const Login:FC = ()=> {
|
||||
|
||||
<section className="flex flex-col items-center mt-[46px] text-SECOND_TEXT">
|
||||
<p className="leading-[28px]">
|
||||
{$t('Version (0)-(1)',[state.version,state.updateDate])}, {$t(state.powered)}
|
||||
{$t('Version (0)-(1)',[state?.version,state?.updateDate])}, {$t(state?.powered || '-')}
|
||||
</p>
|
||||
<LanguageSetting mode="light"/>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext"
|
||||
import { Navigate, useLocation } from "react-router-dom"
|
||||
|
||||
export default function Root() {
|
||||
const { state } = useGlobalContext()
|
||||
const location = useLocation()
|
||||
return (<>
|
||||
{
|
||||
state?.isAuthenticated && !location?.pathname
|
||||
?<Navigate to={location?.pathname ?? state?.mainPage} />:<Navigate to="/login" />
|
||||
}</>
|
||||
)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
|
||||
const AiServiceInsidePage:FC = ()=> {
|
||||
const { message } = App.useApp()
|
||||
const { teamId,serviceId,apiId, routeId } = useParams<RouterParams>();
|
||||
const { teamId,serviceId,apiId, routeId,policyId } = useParams<RouterParams>();
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const {fetchData} = useFetch()
|
||||
@@ -42,7 +42,6 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
|
||||
|
||||
const getApiDefine = ()=>{
|
||||
console.log('@@@@@@@')
|
||||
setApiPrefix('')
|
||||
setPrefixForce(false)
|
||||
fetchData<BasicResponse<{ prefix:string, force:boolean }>>('service/router/define',{method:'GET',eoParams:{service:serviceId,team:teamId}}).then(response=>{
|
||||
@@ -64,6 +63,7 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
getItem(<Link to="./route">{$t('API 路由')}</Link>, 'route',undefined,undefined,undefined,'team.service.router.view'),
|
||||
getItem(<Link to="./api">{$t('API 文档')}</Link>, 'api',undefined,undefined,undefined,'team.service.api_doc.view'),
|
||||
getItem(<Link to="./document">{$t('使用说明')}</Link>, 'document',undefined,undefined,undefined,'team.service.service_intro.view'),
|
||||
getItem(<Link to="./servicepolicy">{$t('服务策略')}</Link>, 'servicepolicy', undefined, undefined, undefined, 'team.service.policy.view'),
|
||||
getItem(<Link to="./publish">{$t('发布')}</Link>, 'publish',undefined,undefined,undefined,'team.service.release.view'),
|
||||
],
|
||||
'group'),
|
||||
@@ -109,10 +109,14 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setShowMenu(!routeId && !currentUrl.includes('route/create'))
|
||||
// route edit and policy edit page don't need to show menu
|
||||
setShowMenu(!routeId && !currentUrl.includes('route/create') && !policyId &&!currentUrl.includes('servicepolicy/datamasking/create'))
|
||||
|
||||
if(apiId !== undefined){
|
||||
setActiveMenu('api')
|
||||
}else if(serviceId !== currentUrl.split('/')[currentUrl.split('/').length - 1]){
|
||||
} else if(currentUrl.includes('servicepolicy')){
|
||||
setActiveMenu('servicepolicy')
|
||||
} else if(serviceId !== currentUrl.split('/')[currentUrl.split('/').length - 1]){
|
||||
setActiveMenu(currentUrl.split('/')[currentUrl.split('/').length - 1])
|
||||
}else{
|
||||
setActiveMenu('route')
|
||||
|
||||
@@ -239,7 +239,7 @@ export const AiServiceSubscriberConfig = forwardRef<AiServiceSubscriberConfigHan
|
||||
getAiServiceList()
|
||||
}, [serviceId]);
|
||||
|
||||
return (<WithPermission access="team.service.subscription.add">
|
||||
return (<WithPermission access="">
|
||||
<Form
|
||||
layout='vertical'
|
||||
labelAlign='left'
|
||||
|
||||
@@ -106,9 +106,9 @@ const AiSettingList = ()=>{
|
||||
</a>
|
||||
<div>
|
||||
<CancelBtn/>
|
||||
<WithPermission access="system.devops.ai_provider.edit" showDisabled={false}>
|
||||
<OkBtn/>
|
||||
</WithPermission>
|
||||
{
|
||||
checkAccess('system.devops.ai_provider.edit', accessData) ? <OkBtn/> : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user