diff --git a/api/init.go b/api/init.go index 50bed18b..dfc444b2 100644 --- a/api/init.go +++ b/api/init.go @@ -38,21 +38,22 @@ func Init(cfg *config.AppConfig) { ui.HandleUIMethod(api.POST, path.Join(pathPrefix, "index/:index"), handler.HandleCreateIndexAction) //new api - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/overview", alerting.GetAlertOverview) - ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/destinations/email_accounts", alerting.CreateEmailAccount) - ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/email_accounts/:emailAccountId", alerting.UpdateEmailAccount) - ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/email_accounts/:emailAccountId", alerting.DeleteEmailAccount) - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/destinations/email_accounts", alerting.GetEmailAccounts) - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/email_accounts/:emailAccountId", alerting.GetEmailAccount) - ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/destinations/email_groups", alerting.CreateEmailGroup) - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/destinations/email_groups", alerting.GetEmailGroups) - ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/email_groups/:emailGroupId", alerting.DeleteEmailGroup) - ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/email_groups/:emailGroupId", alerting.UpdateEmailGroup) - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/email_groups/:emailGroupId", alerting.GetEmailGroup) - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/destinations", alerting.GetDestinations) - ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/destinations", alerting.CreateDestination) - ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/destinations/:destinationId", alerting.UpdateDestination) - ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/destinations/:destinationId", alerting.DeleteDestination) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "alerting/overview"), alerting.GetAlertOverview) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "alerting/overview/alerts"), alerting.GetAlerts) + ui.HandleUIMethod(api.POST, path.Join(pathPrefix,"alerting/destinations/email_accounts"), alerting.CreateEmailAccount) + ui.HandleUIMethod(api.PUT, path.Join(pathPrefix, "alerting/email_accounts/:emailAccountId"), alerting.UpdateEmailAccount) + ui.HandleUIMethod(api.DELETE, path.Join(pathPrefix,"alerting/email_accounts/:emailAccountId"), alerting.DeleteEmailAccount) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix,"alerting/destinations/email_accounts"), alerting.GetEmailAccounts) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix,"alerting/email_accounts/:emailAccountId"), alerting.GetEmailAccount) + ui.HandleUIMethod(api.POST, path.Join(pathPrefix,"alerting/destinations/email_groups"), alerting.CreateEmailGroup) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix,"alerting/destinations/email_groups"), alerting.GetEmailGroups) + ui.HandleUIMethod(api.DELETE, path.Join(pathPrefix,"alerting/email_groups/:emailGroupId"), alerting.DeleteEmailGroup) + ui.HandleUIMethod(api.PUT, path.Join(pathPrefix,"alerting/email_groups/:emailGroupId"), alerting.UpdateEmailGroup) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix,"alerting/email_groups/:emailGroupId"), alerting.GetEmailGroup) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "alerting/destinations"), alerting.GetDestinations) + ui.HandleUIMethod(api.POST, path.Join(pathPrefix,"alerting/destinations"), alerting.CreateDestination) + ui.HandleUIMethod(api.PUT, path.Join(pathPrefix,"alerting/destinations/:destinationId"), alerting.UpdateDestination) + ui.HandleUIMethod(api.DELETE, path.Join(pathPrefix, "alerting/destinations/:destinationId"), alerting.DeleteDestination) ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/monitors/:monitorID", alerting.GetMonitor) ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/monitors/:monitorID", alerting.UpdateMonitor) ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/monitors", alerting.GetMonitors) @@ -60,11 +61,11 @@ func Init(cfg *config.AppConfig) { ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/monitors/_execute", alerting.ExecuteMonitor) ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/monitors/:monitorID", alerting.DeleteMonitor) - ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/_settings", alerting.GetSettings) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix,"alerting/_settings"), alerting.GetSettings) ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/_indices", alerting.GetIndices) ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/_aliases", alerting.GetAliases) ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/_mappings", alerting.GetMappings) - ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/monitors/_search", alerting.Search) + ui.HandleUIMethod(api.POST, path.Join(pathPrefix, "alerting/_search"), alerting.Search) ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/alerts", alerting.GetAlerts) ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/_monitors/:monitorID/_acknowledge/alerts", alerting.AcknowledgeAlerts) diff --git a/service/alerting/action/email.go b/service/alerting/action/email.go index a7d88bd7..b622ed40 100644 --- a/service/alerting/action/email.go +++ b/service/alerting/action/email.go @@ -18,7 +18,6 @@ type EmailAction struct { func (act *EmailAction) Execute() ([]byte, error){ from := act.Sender.Email - //Todo add password input in frontend? act.Sender.Host = strings.TrimSpace(act.Sender.Host) addr := fmt.Sprintf("%s:%d", act.Sender.Host, act.Sender.Port) msg := fmt.Sprintf("To: %s\r\nSubject: %s\r\n%s\r\n", strings.Join(act.Receiver, ","), act.Subject, act.Message) @@ -41,6 +40,10 @@ func SendEmailOverTLS(addr string, auth smtp.Auth, from string, to []string, msg } conn, err := tls.Dial("tcp", addr, tlsConfig) + //dialer := &net.Dialer{ + // Timeout: time.Second * 15, + //} + //conn, err := tls.DialWithDialer(dialer, "tcp", addr, tlsConfig) if err != nil { return err } diff --git a/service/alerting/alert.go b/service/alerting/alert.go index 6c2f9882..29c72b41 100644 --- a/service/alerting/alert.go +++ b/service/alerting/alert.go @@ -75,7 +75,7 @@ func GetAlerts (w http.ResponseWriter, req *http.Request, ps httprouter.Params){ } must := []IfaceMap{ } - if id != "_all" { + if id != "" { must = append(must, IfaceMap{ "match": IfaceMap{ "cluster_id": id, diff --git a/service/alerting/destination.go b/service/alerting/destination.go index 08040a7d..1bac20bc 100644 --- a/service/alerting/destination.go +++ b/service/alerting/destination.go @@ -9,19 +9,12 @@ import ( "infini.sh/framework/core/util" "infini.sh/search-center/model/alerting" "net/http" - "runtime/debug" "strings" "time" ) func GetDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - + conf := getDefaultConfig() dstID := ps.ByName("destID") reqUrl := fmt.Sprintf("%s/%s/_doc/%s", conf.Endpoint, orm.GetIndexName(alerting.Config{}), dstID) res, err := doRequest(reqUrl, http.MethodGet, nil, nil) @@ -45,12 +38,6 @@ func GetDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Para } func GetDestinations(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } var ( from = getQueryParam(req, "from", "0") size = getQueryParam(req, "size", "20") @@ -153,13 +140,6 @@ func GetDestinations(w http.ResponseWriter, req *http.Request, ps httprouter.Par } func CreateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - config := getDefaultConfig() destId := util.GetUUID() reqUrl := fmt.Sprintf("%s/%s/_doc/%s", config.Endpoint, orm.GetIndexName(alerting.Config{}), destId) @@ -189,7 +169,6 @@ func CreateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.P res, err := doRequest(reqUrl, http.MethodPost, map[string]string{ "refresh": "wait_for", }, IfaceMap{ - "cluster_id": id, DESTINATION_FIELD: toSaveDest, }) if err != nil { @@ -217,13 +196,6 @@ func CreateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.P } func UpdateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - destinationId := ps.ByName("destinationId") config := getDefaultConfig() @@ -254,7 +226,6 @@ func UpdateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.P res, err := doRequest(reqUrl, http.MethodPut, map[string]string{ "refresh": "wait_for", }, IfaceMap{ - "cluster_id": id, DESTINATION_FIELD: toSaveDest, }) if err != nil { @@ -278,13 +249,6 @@ func UpdateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.P } func DeleteDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - destinationId := ps.ByName("destinationId") config := getDefaultConfig() @@ -337,17 +301,6 @@ func getDefaultConfig() *elastic.ElasticsearchConfig { //} func CreateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - defer func() { - if err := recover(); err != nil { - debug.PrintStack() - } - }() - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } config := getDefaultConfig() reqUrl := fmt.Sprintf("%s/%s/_doc", config.Endpoint, orm.GetIndexName(alerting.Config{})) @@ -363,7 +316,6 @@ func CreateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter. "refresh": "wait_for", }, IfaceMap{ EMAIL_ACCOUNT_FIELD: emailAccount, - "cluster_id": id, }) if err != nil { writeError(w, err) @@ -403,13 +355,6 @@ func CreateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter. } func UpdateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - emailAccountId := ps.ByName("emailAccountId") config := getDefaultConfig() @@ -424,7 +369,6 @@ func UpdateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter. res, err := doRequest(reqUrl, http.MethodPut, map[string]string{ "refresh": "wait_for", }, IfaceMap{ - "cluster_id": id, EMAIL_ACCOUNT_FIELD: emailAccount, }) if err != nil { @@ -448,13 +392,6 @@ func UpdateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter. } func DeleteEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - emailAccountId := ps.ByName("emailAccountId") config := getDefaultConfig() @@ -487,12 +424,6 @@ func DeleteEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter. } func GetEmailAccounts(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } var ( from = getQueryParam(req, "from", "0") size = getQueryParam(req, "size", "20") @@ -577,13 +508,6 @@ func GetEmailAccounts(w http.ResponseWriter, req *http.Request, ps httprouter.Pa } func GetEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - emailAccountId := ps.ByName("emailAccountId") config := getDefaultConfig() @@ -621,13 +545,6 @@ func GetEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Par // --- email group func CreateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - config := getDefaultConfig() reqUrl := fmt.Sprintf("%s/%s/_doc", config.Endpoint, orm.GetIndexName(alerting.Config{})) var emailGroup = &alerting.EmailGroup{} @@ -639,7 +556,6 @@ func CreateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Pa res, err := doRequest(reqUrl, http.MethodPost, map[string]string{ "refresh": "wait_for", }, IfaceMap{ - "cluster_id": id, EMAIL_GROUP_FIELD: emailGroup, }) if err != nil { @@ -670,13 +586,6 @@ func CreateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Pa } func UpdateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - emailGroupId := ps.ByName("emailGroupId") config := getDefaultConfig() reqUrl := fmt.Sprintf("%s/%s/_doc/%s", config.Endpoint, orm.GetIndexName(alerting.Config{}), emailGroupId) @@ -689,7 +598,6 @@ func UpdateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Pa res, err := doRequest(reqUrl, http.MethodPut, map[string]string{ "refresh": "wait_for", }, IfaceMap{ - "cluster_id": id, EMAIL_GROUP_FIELD: emailGroup, }) if err != nil { @@ -712,13 +620,6 @@ func UpdateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Pa } func DeleteEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - emailGroupId := ps.ByName("emailGroupId") config := getDefaultConfig() reqUrl := fmt.Sprintf("%s/%s/_doc/%s", config.Endpoint, orm.GetIndexName(alerting.Config{}), emailGroupId) @@ -749,12 +650,6 @@ func DeleteEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Pa } func GetEmailGroups(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } var ( from = getQueryParam(req, "from", "0") size = getQueryParam(req, "size", "20") @@ -838,13 +733,6 @@ func GetEmailGroups(w http.ResponseWriter, req *http.Request, ps httprouter.Para } func GetEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - conf := elastic.GetConfig(id) - if conf == nil { - writeError(w, errors.New("cluster not found")) - return - } - emailGroupId := ps.ByName("emailGroupId") config := getDefaultConfig() diff --git a/service/alerting/elasticsearch.go b/service/alerting/elasticsearch.go index c2002366..73d6a844 100644 --- a/service/alerting/elasticsearch.go +++ b/service/alerting/elasticsearch.go @@ -17,12 +17,6 @@ type SearchBody struct { } func Search(w http.ResponseWriter, req *http.Request, ps httprouter.Params){ - id := ps.ByName("id") - meta := elastic.GetMetadata(id) - if meta == nil { - writeError(w, errors.New("cluster not found")) - return - } var body = SearchBody{} err := decodeJSON(req.Body, &body) if err != nil { @@ -175,15 +169,10 @@ func GetMappings(w http.ResponseWriter, req *http.Request, ps httprouter.Params) } func GetSettings(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - id := ps.ByName("id") - meta := elastic.GetMetadata(id) - if meta == nil { - writeError(w, errors.New("cluster not found")) - return - } // /_cluster/settings?include_defaults=true - reqUrl := fmt.Sprintf("%s/_cluster/settings", meta.GetActiveEndpoint()) + config := getDefaultConfig() + reqUrl := fmt.Sprintf("%s/_cluster/settings", config.Endpoint) res, err := doRequest(reqUrl, http.MethodGet, map[string]string{ "include_defaults": "true", }, nil) diff --git a/service/alerting/monitor.go b/service/alerting/monitor.go index 49d33a3c..13ec49cc 100644 --- a/service/alerting/monitor.go +++ b/service/alerting/monitor.go @@ -695,7 +695,7 @@ func ExecuteMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Para } } - period := alertUtil.GetMonitorPeriod(&periodStart, &monitor.Schedule) + period := alertUtil.GetMonitorPeriod(periodStart, &monitor.Schedule) writeJSON(w, IfaceMap{ "ok": true, "resp": IfaceMap{ diff --git a/service/alerting/overview.go b/service/alerting/overview.go index 459ad5c3..0da72b64 100644 --- a/service/alerting/overview.go +++ b/service/alerting/overview.go @@ -3,6 +3,8 @@ package alerting import ( "fmt" httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/elastic" + "infini.sh/framework/core/orm" "net/http" ) @@ -127,13 +129,35 @@ func getTopTenAlertCluster()(interface{}, error){ } } } - //reqBody = IfaceMap{ - // "query": IfaceMap{ - // "terms": IfaceMap{ - // "_id": clusterIDs, - // }, - // }, - //} + reqBody = IfaceMap{ + "_source": "name", + "query": IfaceMap{ + "terms": IfaceMap{ + "_id": clusterIDs, + }, + }, + } + config := getDefaultConfig() + reqUrl := fmt.Sprintf("%s/%s/_search", config.Endpoint, orm.GetIndexName(elastic.ElasticsearchConfig{})) + res, err := doRequest(reqUrl, http.MethodGet, nil, reqBody) + if err != nil { + return nil, err + } + var resBody = &elastic.SearchResponse{} + err = decodeJSON(res.Body, resBody) + if err != nil { + return nil, err + } + res.Body.Close() + clusterMap := IfaceMap{} + for _, hit := range resBody.Hits.Hits { + clusterMap[hit.ID.(string)] = hit.Source["name"] + } + for _, d := range metricData { + if name, ok := clusterMap[d["x"].(string)]; ok { + d["x"] = name + } + } return metricData, nil } diff --git a/service/alerting/schedule.go b/service/alerting/schedule.go index 7d6aee09..bbe43b53 100644 --- a/service/alerting/schedule.go +++ b/service/alerting/schedule.go @@ -15,6 +15,7 @@ import ( "infini.sh/framework/core/orm" "infini.sh/search-center/model/alerting" "infini.sh/search-center/service/alerting/action" + "infini.sh/search-center/service/alerting/util" "io" "net/http" "strings" @@ -148,12 +149,17 @@ type MonitorJob func() func generateMonitorJob(smt *ScheduleMonitor) MonitorJob{ sm := *smt return func() { + startTime := time.Now() queryResult, err := getQueryResult(sm.ClusterID, &sm.Monitor.Inputs[0]) if err != nil { log.Error(err) } + periods := util.GetMonitorPeriod(startTime, &sm.Monitor.Schedule) for _, trigger := range sm.Monitor.Triggers { - monitorCtx, err := createMonitorContext(&trigger, queryResult, &sm, IfaceMap{}) + monitorCtx, err := createMonitorContext(&trigger, queryResult, &sm, IfaceMap{ + "periodStart": periods.Start, + "periodEnd": periods.End, + }) if err != nil { log.Error(err) continue @@ -496,17 +502,17 @@ func resolveMessage(messageTemplate IfaceMap, monitorCtx []byte ) ([]byte, error } func createMonitorContext(trigger *alerting.Trigger, result IfaceMap, smt *ScheduleMonitor, extra IfaceMap) ([]byte, error){ - ctx := IfaceMap{ - "_ctx": IfaceMap{ - "results": []interface{}{ - result, - }, - "trigger": trigger, - "monitor": smt.Monitor, - "cluster_id": smt.ClusterID, - "periodStart": "", - "periodEnd":"", + params := IfaceMap{ + "results": []interface{}{ + result, }, + "trigger": trigger, + "monitor": smt.Monitor, + "cluster_id": smt.ClusterID, + } + assignTo(params, extra) + ctx := IfaceMap{ + "_ctx": params, } return json.Marshal(ctx) } diff --git a/service/alerting/util/period.go b/service/alerting/util/period.go index cbc8a6ba..f24dd077 100644 --- a/service/alerting/util/period.go +++ b/service/alerting/util/period.go @@ -8,11 +8,11 @@ import ( ) type MonitorPeriod struct { - Start int64 - End int64 + Start time.Time + End time.Time } -func GetMonitorPeriod(currentTime *time.Time, schedule *alerting.Schedule) *MonitorPeriod{ +func GetMonitorPeriod(currentTime time.Time, schedule *alerting.Schedule) *MonitorPeriod{ if schedule.Period != nil { return transformPeriod(currentTime, schedule.Period) } @@ -23,7 +23,7 @@ func GetMonitorPeriod(currentTime *time.Time, schedule *alerting.Schedule) *Moni } -func transformCron(currentTime *time.Time, cron *alerting.Cron) *MonitorPeriod { +func transformCron(currentTime time.Time, cron *alerting.Cron) *MonitorPeriod { timezone := "" if cron.Timezone != "" { timezone = fmt.Sprintf("CRON_TZ=%s ", cron.Timezone) @@ -39,7 +39,7 @@ func transformCron(currentTime *time.Time, cron *alerting.Cron) *MonitorPeriod { if ssd.Hour == 1 { duration = time.Hour } - tempTime := *currentTime + tempTime := currentTime nextTime := sd.Next(tempTime) var preTime = tempTime for { @@ -49,18 +49,18 @@ func transformCron(currentTime *time.Time, cron *alerting.Cron) *MonitorPeriod { } } mp := &MonitorPeriod{ - Start: preTime.UnixNano()/1e6, - End: currentTime.UnixNano()/1e6, + Start: preTime, + End: currentTime, } return mp } -func transformPeriod(currentTime *time.Time, period *alerting.Period) *MonitorPeriod { +func transformPeriod(currentTime time.Time, period *alerting.Period) *MonitorPeriod { if period == nil { return nil } mp := &MonitorPeriod{ - End: currentTime.UnixNano()/1e6, + End: currentTime, } var duration time.Duration switch period.Unit { @@ -73,6 +73,6 @@ func transformPeriod(currentTime *time.Time, period *alerting.Period) *MonitorPe default: return nil } - mp.Start = currentTime.Add(-duration * time.Duration(period.Interval)).UnixNano()/1e6 + mp.Start = currentTime.Add(-duration * time.Duration(period.Interval)) return mp } \ No newline at end of file diff --git a/web/config/config.js b/web/config/config.js index eef08c9d..0ac2a6e7 100644 --- a/web/config/config.js +++ b/web/config/config.js @@ -73,6 +73,11 @@ export default { changeOrigin: true, // pathRewrite: { '^/server': '' }, }, + '/_search-center/': { + target: 'http://localhost:9000', + changeOrigin: true, + // pathRewrite: { '^/server': '' }, + }, }, ignoreMomentLocale: true, lessLoaderOptions: { diff --git a/web/config/router.config.js b/web/config/router.config.js index 9cc69ad9..41da0947 100644 --- a/web/config/router.config.js +++ b/web/config/router.config.js @@ -106,13 +106,31 @@ export default [ //alerting { - routes:[ - { path: '/', redirect: '/' }, - ], path: '/alerting', name: 'alerting', icon: 'alert', - component: './Alerting/index', + routes: [{ + routes:[ + { path: '/', redirect: '/' }, + ], + path: '/alerting/overview', + component: './Alerting/pages/Overview/Overview', + name: 'overview' + },{ + routes:[ + { path: '/', redirect: '/' }, + ], + path: '/alerting/monitor', + component: './Alerting/index', + name: 'monitor' + },{ + routes:[ + { path: '/', redirect: '/' }, + ], + path: '/alerting/destination', + component: './Alerting/destination', + name: 'destination' + }] }, //data diff --git a/web/src/components/GlobalHeader/index.js b/web/src/components/GlobalHeader/index.js index cb856f74..d2f55a64 100644 --- a/web/src/components/GlobalHeader/index.js +++ b/web/src/components/GlobalHeader/index.js @@ -68,6 +68,7 @@ export default class GlobalHeader extends PureComponent { payload:{ history, pathname: history.location.pathname, + isChangedState: true, } }) }); diff --git a/web/src/locales/en-US.js b/web/src/locales/en-US.js index ccc92a72..4480aea0 100644 --- a/web/src/locales/en-US.js +++ b/web/src/locales/en-US.js @@ -68,6 +68,7 @@ export default { 'form.button.add': 'Add', 'form.button.edit': 'Edit', 'form.button.update': 'Update', + 'form.button.save': 'Save', 'form.button.delete': 'Delete', 'form.button.cancel': 'Cancel', 'form.button.collapse': 'Collapse', @@ -91,6 +92,9 @@ export default { 'menu.home': 'Home', 'menu.devtool': 'CONSOLE', 'menu.alerting': 'AERTING', + 'menu.alerting.overview': 'OVERVIEW', + 'menu.alerting.monitor': 'MONITORS', + 'menu.alerting.destination': 'DESTINATIONS', 'menu.cluster': 'CLUSTER', 'menu.cluster.overview': 'OVERVIEW', diff --git a/web/src/locales/en-US/alert.js b/web/src/locales/en-US/alert.js index 7697dd77..7f4e7bb3 100644 --- a/web/src/locales/en-US/alert.js +++ b/web/src/locales/en-US/alert.js @@ -1,4 +1,10 @@ export default { + 'alert.overview.metric.active': 'ACTIVE', + 'alert.overview.metric.acknowledged': 'ACKNOWLEDGED', + 'alert.overview.metric.error': 'ERROR', + 'alert.overview.alertlist.title': 'Open Alerts', + 'alert.overview.alertlist-history.title': 'History Alerts', + 'alert.button.acknowledge': 'Acknowledge', 'alert.button.create-monitor': 'Create monitor', 'alert.button.update-monitor': 'Update monitor', @@ -79,6 +85,20 @@ export default { 'alert.monitor.create.schedule.when-text': 'When do you want this monitor to run?', 'alert.monitor.create.schedule.advise-text': 'Define how often the monitor collects data and determines how often you may receive alerts. We recommend two times of detector interval to avoid missing anomaly results due to any potential delay of processing time.', + 'alert.monitor.overview.title': 'Overview', + 'alert.monitor.overview.header.state': 'State', + 'alert.monitor.overview.header.definition_type': 'Monitor definition type', + 'alert.monitor.overview.header.total_active_alerts': 'Total active alerts', + 'alert.monitor.overview.header.schedule': 'Schedule', + 'alert.monitor.overview.header.last_updated': 'Last updated', + 'alert.monitor.overview.header.monitor_id': 'Monitor ID', + 'alert.monitor.overview.header.version_number': 'Monitor version number', + 'alert.monitor.triggers.title': 'Triggers', + 'alert.monitor.triggers.table.header.name': 'Name', + 'alert.monitor.triggers.table.header.number_of_actions': 'Number of actions', + 'alert.monitor.triggers.table.header.severity': 'Severity', + 'alert.monitor.history.title': 'History', + 'alert.destination': 'Destinations', 'alert.destination.self': 'destination', 'alert.destination.self-upper': 'Destination', @@ -107,4 +127,43 @@ export default { 'alert.trigger': 'Triggers', 'alert.trigger.self': 'trigger', + 'alert.trigger.create.title': 'Create trigger', + 'alert.trigger.edit.title': 'Edit trigger', + 'alert.trigger.edit.define.title': 'Define trigger', + 'alert.trigger.edit.define.field.name': 'Trigger name', + 'alert.trigger.edit.define.field.severity': 'Severity level', + 'alert.trigger.edit.define.field.query_response': 'Extraction query response', + 'alert.trigger.edit.define.field.condition': 'Trigger condition', + 'alert.trigger.edit.define.field.condition.info.paragraph1': 'You have access to a "_ctx" variable in your yaml scripts', + 'alert.trigger.edit.define.field.condition.info.paragraph2': `Below shows a quick JSON example of what's available under the "_ctx" variable along withthe actual results (where possible) for you to reference.`, + 'alert.trigger.edit.define.field.condition_response': 'Trigger condition response', + 'alert.trigger.edit.define.field.name.help': 'Trigger names must be unique. Names can only contain letters, numbers, and special characters.', + 'alert.trigger.edit.define.field.severity.help': 'Severity levels help you organize your triggers and actions. A trigger with a high severity level might page a specific individual, whereas a trigger with a low severity level might email a list.', + 'alert.trigger.edit.define.button.run': 'Run', + 'alert.trigger.edit.action.title': 'Configure actions', + 'alert.trigger.edit.action.button.add_action': 'Add action', + 'alert.trigger.edit.action.field.name': 'Action name', + 'alert.trigger.edit.action.field.destination': 'Destination', + 'alert.trigger.edit.action.field.message': 'Message', + 'alert.trigger.edit.action.field.message_subject': 'Message subject', + 'alert.trigger.edit.action.field.message_preview': 'Message preview', + 'alert.trigger.edit.action.send_test_message': 'Send test message', + 'alert.trigger.edit.action.default_name': 'Notification', + 'alert.email.manage.title': 'Manage email senders', + 'alert.email.manage.button.remove': 'Remove sender', + 'alert.email.manage.button.add': 'Add sender', + 'alert.email.manage.field.name': 'Sender name', + 'alert.email.manage.field.name.help': 'A unique and descriptive name that is easy to search. Valid characters are upper and lowercase a-z, 0-9, and _ (underscore).', + 'alert.email.manage.field.address': 'Email address', + 'alert.email.manage.field.password': 'Email password', + 'alert.email.manage.field.host': 'Host', + 'alert.email.manage.field.port': 'Port', + 'alert.email.manage.field.method': 'Encryption method', + 'alert.emailgroup.manage.title': 'Manage email groups', + 'alert.emailgroup.manage.button.remove': 'Remove email group', + 'alert.emailgroup.manage.button.add': 'Add email group', + 'alert.emailgroup.manage.field.name': 'Email group name', + 'alert.emailgroup.manage.field.name.help': 'A unique and descriptive name that is easy to search. Valid characters are upper and lowercase a-z, 0-9, and _ (underscore).', + 'alert.emailgroup.manage.field.emails': 'Emails', + 'alert.emailgroup.manage.field.emails.help': 'Search for previously used email addresses or type in new ones.', }; diff --git a/web/src/locales/zh-CN.js b/web/src/locales/zh-CN.js index 39f78a5b..b5ada7b8 100644 --- a/web/src/locales/zh-CN.js +++ b/web/src/locales/zh-CN.js @@ -74,6 +74,7 @@ export default { 'form.button.add': '添加', 'form.button.edit': '编辑', 'form.button.update': '更新', + 'form.button.save': '保存', 'form.button.delete': '删除', 'form.button.cancel': '取消', 'form.button.collapse': '收起', @@ -98,6 +99,9 @@ export default { 'menu.home': '首页', 'menu.devtool': '开发工具', 'menu.alerting': '告警管理', + 'menu.alerting.overview': '概览', + 'menu.alerting.monitor': '监控管理', + 'menu.alerting.destination': '渠道管理', 'menu.cluster': '集群管理', 'menu.cluster.overview': '概览', diff --git a/web/src/locales/zh-CN/alert.js b/web/src/locales/zh-CN/alert.js index 2b5f4dd4..135868e0 100644 --- a/web/src/locales/zh-CN/alert.js +++ b/web/src/locales/zh-CN/alert.js @@ -1,4 +1,10 @@ export default { + 'alert.overview.metric.active': '激活告警', + 'alert.overview.metric.acknowledged': '已响应告警', + 'alert.overview.metric.error': '错误告警', + 'alert.overview.alertlist.title': '当前告警', + 'alert.overview.alertlist-history.title': '历史告警', + 'alert.button.acknowledge': '确认', 'alert.button.create-monitor': '创建监控项', 'alert.button.update-monitor': '更新监控项', @@ -79,6 +85,19 @@ export default { 'alert.monitor.create.schedule.when-text': '您希望此监视器何时运行?', 'alert.monitor.create.schedule.advise-text': '定义监视器收集数据的频率并确定您接收警报的频率。 我们建议两倍检测器间隔,以避免由于处理时间的任何潜在延迟而遗漏异常结果。', + 'alert.monitor.overview.title': '概览', + 'alert.monitor.overview.header.state': '状态', + 'alert.monitor.overview.header.definition_type': '监控定义类型', + 'alert.monitor.overview.header.total_active_alerts': '激活告警数', + 'alert.monitor.overview.header.schedule': '监控计划', + 'alert.monitor.overview.header.last_updated': '最近更新时间', + 'alert.monitor.overview.header.monitor_id': '监控编号', + 'alert.monitor.overview.header.version_number': '版本', + 'alert.monitor.triggers.title': '触发器', + 'alert.monitor.triggers.table.header.name': '名称', + 'alert.monitor.triggers.table.header.number_of_actions': '通知渠道', + 'alert.monitor.triggers.table.header.severity': '告警等级', + 'alert.monitor.history.title': '告警历史', 'alert.destination': '通知渠道', 'alert.destination.self': '通知渠道', @@ -107,4 +126,43 @@ export default { 'alert.destination.create.settings.attributes.label': '通过自定义属性 URL 定义端点', 'alert.trigger': '触发器', + 'alert.trigger.create.title': '创建触发器', + 'alert.trigger.edit.title': '修改触发器', + 'alert.trigger.edit.define.title': '定义触发器', + 'alert.trigger.edit.define.field.name': '名称', + 'alert.trigger.edit.define.field.severity': '告警等级', + 'alert.trigger.edit.define.field.query_response': '查询响应', + 'alert.trigger.edit.define.field.condition': '触发条件', + 'alert.trigger.edit.define.field.condition.info.paragraph1': '您可以在 yaml 脚本中访问 "_ctx" 变量', + 'alert.trigger.edit.define.field.condition.info.paragraph2': `以下是一个快速 JSON 示例,示例中列举了 "_ctx" 下的可访问变量 。`, + 'alert.trigger.edit.define.field.condition_response': '触发响应', + 'alert.trigger.edit.define.field.name.help': '名称必须唯一,只能包含字母,数字和特殊字符。', + 'alert.trigger.edit.define.field.severity.help':'告警等级帮助您管理触发器', + 'alert.trigger.edit.define.button.run': '运行', + 'alert.trigger.edit.action.title': '触发通知配置', + 'alert.trigger.edit.action.button.add_action': '添加通知', + 'alert.trigger.edit.action.field.name': '通知名称', + 'alert.trigger.edit.action.field.destination': '渠道选择', + 'alert.trigger.edit.action.field.message': '消息配置', + 'alert.trigger.edit.action.field.message_subject': '消息标题', + 'alert.trigger.edit.action.field.message_preview': '消息预览', + 'alert.trigger.edit.action.send_test_message': '发送测试消息', + 'alert.trigger.edit.action.default_name': '通知', + 'alert.email.manage.title': '管理邮件发送者', + 'alert.email.manage.button.remove': '删除', + 'alert.email.manage.button.add': '添加', + 'alert.email.manage.field.name': '名称', + 'alert.email.manage.field.name.help': '唯一的名称利于搜索,名称中只能包含大小写字母、数字和下划线', + 'alert.email.manage.field.address': '邮件地址', + 'alert.email.manage.field.password': '邮件密码', + 'alert.email.manage.field.host': '主机', + 'alert.email.manage.field.port': '端口', + 'alert.email.manage.field.method': '加密方式', + 'alert.emailgroup.manage.title': '管理邮件组', + 'alert.emailgroup.manage.button.remove': '删除', + 'alert.emailgroup.manage.button.add': '添加', + 'alert.emailgroup.manage.field.name': '名称', + 'alert.emailgroup.manage.field.name.help': '唯一的名称利于搜索,名称中只能包含大小写字母、数字和下划线', + 'alert.emailgroup.manage.field.emails': '邮件列表', + 'alert.emailgroup.manage.field.emails.help': '搜索先前用过的邮件或者输入新的邮件地址', }; diff --git a/web/src/models/global.js b/web/src/models/global.js index a7fcea33..bf19b45d 100644 --- a/web/src/models/global.js +++ b/web/src/models/global.js @@ -7,7 +7,6 @@ import router from "umi/router"; const MENU_COLLAPSED_KEY = "search-center:menu:collapsed"; -console.log(localStorage.getItem(MENU_COLLAPSED_KEY)) export default { namespace: 'global', @@ -22,7 +21,7 @@ export default { search:{ cluster: { } - } + }, }, effects: { @@ -130,7 +129,7 @@ export default { }); }, *rewriteURL({payload}, {select, put}){ - const {pathname, history, search} = payload; + const {pathname, history, search, isChangedState} = payload; const global = yield select(state=>state.global); if(pathname && global.selectedClusterID){ const newPart = `/elasticsearch/${global.selectedClusterID}/`; @@ -139,7 +138,11 @@ export default { }else{ const ms = pathname.match(/\/elasticsearch\/(\w+)\/?/); if(ms && ms.length>1 && ms[1] != global.selectedClusterID){ - console.log(ms[1]) + if(isChangedState){ + const newPath = pathname.replace(/\/elasticsearch\/(\w+)\/?/, newPart); + history.replace(newPath+(search || '')) + return + } yield put({ type: 'changeClusterById', payload:{ @@ -248,12 +251,21 @@ export default { // Subscribe history(url) change, trigger `load` action if pathname is `/` return history.listen(({ pathname, search }) => { let clusterVisible = true; - if(pathname.startsWith("/system")){ - clusterVisible = false; - }else if(pathname.startsWith("/cluster/overview")){ + const clusterHiddenPath = ["/system", "/cluster/overview", "/alerting/overview", "/alerting/monitor/monitors/", "/alerting/destination"]; + if(clusterHiddenPath.some(p=>pathname.startsWith(p))){ clusterVisible = false; + if(pathname.includes("elasticsearch")){ + dispatch({ + type: 'rewriteURL', + payload: { + pathname, + history, + search, + } + }); + } }else{ - if(!pathname.startsWith("/exception")){ + if(!pathname.startsWith("/exception") && pathname !="/alerting/monitor"){ dispatch({ type: 'rewriteURL', payload: { diff --git a/web/src/pages/Alerting/components/Flyout/flyouts/message.js b/web/src/pages/Alerting/components/Flyout/flyouts/message.js index 2eb537ee..ded35adc 100644 --- a/web/src/pages/Alerting/components/Flyout/flyouts/message.js +++ b/web/src/pages/Alerting/components/Flyout/flyouts/message.js @@ -34,16 +34,16 @@ const message = () => ({ body: (

- {`You have access to a "ctx" variable in your painless scripts and action mustache templates.`} + {`You have access to a "_ctx" variable in your yaml scripts and action quicktemplate templates.`}

-

Learn More

+ {/*

Learn More

+ */}
), }); diff --git a/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js b/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js index 6c5d1d1a..581e030d 100644 --- a/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js +++ b/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js @@ -15,6 +15,7 @@ import React from 'react'; import { EuiCodeBlock, EuiCodeEditor, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import {formatMessage} from 'umi/locale'; const CONTEXT_VARIABLES = JSON.stringify( { @@ -40,17 +41,16 @@ const triggerCondition = context => ({ header: (

- Trigger condition + {formatMessage({id:'alert.trigger.edit.define.field.condition'})}

), body: (
-

You have access to a "ctx" variable in your painless scripts

+

{formatMessage({id:'alert.trigger.edit.define.field.condition.info.paragraph1'})}

- Below shows a quick JSON example of what's available under the "ctx" variable along with - the actual results (where possible) for you to reference. + {formatMessage({id:'alert.trigger.edit.define.field.condition.info.paragraph2'})}

diff --git a/web/src/pages/Alerting/destination.js b/web/src/pages/Alerting/destination.js new file mode 100644 index 00000000..ae4bedfd --- /dev/null +++ b/web/src/pages/Alerting/destination.js @@ -0,0 +1,90 @@ +import React, { Component, useMemo } from 'react'; +import { Switch, Route, Router } from 'react-router-dom'; +import CreateDestination from './pages/Destinations/containers/CreateDestination'; +import DestinationsList from './pages/Destinations/containers/DestinationsList'; +import {Fetch} from '../../components/kibana/core/public/http/fetch'; +import {ScopedHistory} from '../../components/kibana/core/public/application/scoped_history'; +import {notification} from 'antd'; + +const Destination = ({httpClient, notifications, history})=> { + return ( +
+ + + ( + + )} + /> + ( + + )} + /> + { + return ( + + )}} + /> + + +
+ ); +} + + + + +const httpClient = new Fetch({ + basePath:{ + get: () => '', + prepend: (url) => url, + remove: (url) => url, + serverBasePath: '', + } +}); +const notifications = { + toasts: { + addDanger: ({title, text, toastLifeTimeMs})=>{ + notification.warning({ + message: title, + description: text, + duration: toastLifeTimeMs/1000, + }) + }, + addSuccess: (message) => { + notification.success({ + description: message, + }) + } + } +} + +export default (props)=>{ + const isDarkMode = false; + const history = useMemo(()=>{ + return new ScopedHistory(props.history, '/alerting/destination'); + }, [props.history]) + + return ( + + ) +} \ No newline at end of file diff --git a/web/src/pages/Alerting/index.js b/web/src/pages/Alerting/index.js index 0c170ac0..27b9a9cc 100644 --- a/web/src/pages/Alerting/index.js +++ b/web/src/pages/Alerting/index.js @@ -45,7 +45,7 @@ const AlertingUI = (props)=>{ }, [props.selectedCluster]); const isDarkMode = false; const history = useMemo(()=>{ - return new ScopedHistory(props.history, '/alerting'); + return new ScopedHistory(props.history, '/alerting/monitor'); }, [props.history]) return ( diff --git a/web/src/pages/Alerting/pages/CreateTrigger/components/Action/Action.js b/web/src/pages/Alerting/pages/CreateTrigger/components/Action/Action.js index f02beb8f..5a9c40c6 100644 --- a/web/src/pages/Alerting/pages/CreateTrigger/components/Action/Action.js +++ b/web/src/pages/Alerting/pages/CreateTrigger/components/Action/Action.js @@ -21,6 +21,7 @@ import { isInvalid, hasError, validateActionName } from '../../../../utils/valid import { ActionsMap } from './utils/constants'; import { validateDestination } from './utils/validate'; import { DEFAULT_ACTION_TYPE } from '../../utils/constants'; +import {formatMessage} from 'umi/locale'; const Action = ({ action, @@ -44,12 +45,12 @@ const Action = ({ className="accordion-action" buttonContent={ !_.get(selectedDestination, '0.type', undefined) - ? 'Notification' + ? formatMessage({id:'alert.trigger.edit.action.default_name'}) : `${actionLabel}: ${name}` } extraAction={
- Delete + {formatMessage({id:'form.button.delete'})}
} > @@ -58,9 +59,9 @@ const Action = ({ ( - + {/* Embed variables in your message using Mustache templates.{' '} Learn more about Mustache - + */} @@ -56,7 +57,7 @@ const messageHelpText = (index, sendTestMessage) => ( sendTestMessage(index); }} > - Send test message + {formatMessage({id:'alert.trigger.edit.action.send_test_message'})} @@ -76,7 +77,7 @@ const Message = ({ preview = Mustache.render(action.message_template.source, context); } catch (err) { preview = err.message; - console.error('There was an error rendering mustache template', err); + console.error('There was an error rendering template', err); } return (
@@ -86,7 +87,7 @@ const Message = ({ formRow fieldProps={{ validate: required }} rowProps={{ - label: 'Message subject', + label: formatMessage({id:'alert.trigger.edit.action.field.message_subject'}), isInvalid, error: hasError, }} @@ -100,7 +101,7 @@ const Message = ({ rowProps={{ label: (
- Message + {formatMessage({id:'alert.trigger.edit.action.field.message'})} { @@ -117,15 +118,15 @@ const Message = ({ error: hasError, }} inputProps={{ - placeholder: 'Can use mustache templates', + placeholder: 'Can use templates', fullWidth: true, isInvalid, }} /> - + - + {/* - + */}
); }; diff --git a/web/src/pages/Alerting/pages/CreateTrigger/components/ActionEmptyPrompt/ActionEmptyPrompt.js b/web/src/pages/Alerting/pages/CreateTrigger/components/ActionEmptyPrompt/ActionEmptyPrompt.js index ed1e8622..6d4991a9 100644 --- a/web/src/pages/Alerting/pages/CreateTrigger/components/ActionEmptyPrompt/ActionEmptyPrompt.js +++ b/web/src/pages/Alerting/pages/CreateTrigger/components/ActionEmptyPrompt/ActionEmptyPrompt.js @@ -22,7 +22,7 @@ const actionEmptyText = 'Add an action to perform when this trigger is triggered const destinationEmptyText = 'There are no existing destinations. Add a destinations to create an action'; const createDestinationButton = ( - + Add destination ); diff --git a/web/src/pages/Alerting/pages/CreateTrigger/components/AddActionButton/AddActionButton.js b/web/src/pages/Alerting/pages/CreateTrigger/components/AddActionButton/AddActionButton.js index d3d0d058..2b04f65c 100644 --- a/web/src/pages/Alerting/pages/CreateTrigger/components/AddActionButton/AddActionButton.js +++ b/web/src/pages/Alerting/pages/CreateTrigger/components/AddActionButton/AddActionButton.js @@ -18,10 +18,11 @@ import _ from 'lodash'; import { EuiButton } from '@elastic/eui'; import { FORMIK_INITIAL_ACTION_VALUES } from '../../utils/constants'; +import {formatMessage} from 'umi/locale'; const AddActionButton = ({ arrayHelpers, type = 'slack' }) => ( arrayHelpers.unshift(_.cloneDeep(FORMIK_INITIAL_ACTION_VALUES))}> - Add action + {formatMessage({id:'alert.trigger.edit.action.button.add_action'})} ); diff --git a/web/src/pages/Alerting/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js b/web/src/pages/Alerting/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js index f7399ab0..e664ade1 100644 --- a/web/src/pages/Alerting/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js +++ b/web/src/pages/Alerting/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js @@ -30,6 +30,7 @@ import 'brace/mode/plain_text'; import 'brace/snippets/javascript'; import 'brace/ext/language_tools'; import { formikToTrigger } from '../../containers/CreateTrigger/utils/formikToTrigger'; +import {formatMessage} from 'umi/locale'; export const getExecuteMessage = (response) => { if (!response) return 'No response'; @@ -59,7 +60,7 @@ const TriggerQuery = ({
- + - Trigger condition + {formatMessage({id:'alert.trigger.edit.define.field.condition'})} { @@ -108,7 +109,7 @@ const TriggerQuery = ({ - + - onRun([trigger])}>Run + onRun([trigger])}>{formatMessage({id:'alert.trigger.edit.define.button.run'})}
diff --git a/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js b/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js index 74befca3..349e6133 100644 --- a/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js +++ b/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js @@ -24,9 +24,11 @@ import { DESTINATION_OPTIONS } from '../../../Destinations/utils/constants'; import { getAllowList } from '../../../Destinations/utils/helpers'; import { MAX_QUERY_RESULT_SIZE } from '../../../../utils/constants'; import { backendErrorNotification } from '../../../../utils/helpers'; +import {pathPrefix} from '@/services/common' +import {formatMessage} from 'umi/locale'; const createActionContext = (context, action) => ({ - ctx: { + _ctx: { ...context, action, }, @@ -62,8 +64,9 @@ class ConfigureActions extends React.Component { return destination.type; }; try { - const response = await httpClient.get('/alerting/destinations', { + const response = await httpClient.get(pathPrefix +'/alerting/destinations', { query: { search: searchText, size: MAX_QUERY_RESULT_SIZE }, + prependBasePath: false, }); if (response.ok) { const destinations = response.destinations @@ -143,7 +146,7 @@ class ConfigureActions extends React.Component { //TODO:: Handle loading Destinations inside the Action which will be more intuitive for customers. return ( ( -

{edit ? 'Edit' : 'Create'} trigger

+

{edit ? formatMessage({id:'alert.trigger.edit.title'}):formatMessage({id:'alert.trigger.create.title'})}

- Cancel + {formatMessage({id:'form.button.cancel'})} - {edit ? 'Update' : 'Create'} + {edit ? formatMessage({id:'form.button.update'}) : formatMessage({id:'form.button.create'})} diff --git a/web/src/pages/Alerting/pages/CreateTrigger/containers/DefineTrigger/DefineTrigger.js b/web/src/pages/Alerting/pages/CreateTrigger/containers/DefineTrigger/DefineTrigger.js index 43cecc67..79c65c39 100644 --- a/web/src/pages/Alerting/pages/CreateTrigger/containers/DefineTrigger/DefineTrigger.js +++ b/web/src/pages/Alerting/pages/CreateTrigger/containers/DefineTrigger/DefineTrigger.js @@ -26,10 +26,11 @@ import { validateTriggerName } from './utils/validation'; import { SEARCH_TYPE } from '../../../../utils/constants'; import { AnomalyDetectorTrigger } from './AnomalyDetectorTrigger'; import { TRIGGER_TYPE } from '../CreateTrigger/utils/constants'; +import {formatMessage} from 'umi/locale'; const defaultRowProps = { - label: 'Trigger name', - helpText: `Trigger names must be unique. Names can only contain letters, numbers, and special characters.`, + label: formatMessage({id:"alert.trigger.edit.define.field.name"}), + helpText: formatMessage({id:"alert.trigger.edit.define.field.name.help"}), style: { paddingLeft: '10px' }, isInvalid, error: hasError, @@ -38,8 +39,8 @@ const defaultInputProps = { isInvalid }; const selectFieldProps = { validate: () => {} }; const selectRowProps = { - label: 'Severity level', - helpText: `Severity levels help you organize your triggers and actions. A trigger with a high severity level might page a specific individual, whereas a trigger with a low severity level might email a list.`, + label: formatMessage({id:"alert.trigger.edit.define.field.severity"}), + helpText: formatMessage({id:'alert.trigger.edit.define.field.severity.help'}), style: { paddingLeft: '10px', marginTop: '0px' }, isInvalid, error: hasError, @@ -119,7 +120,7 @@ const DefineTrigger = ({ } return ( - + void + onItemClick: (item: AlertRecord)=>void; + legendItems?: LegendItem[]; } export const AlertList = ({ @@ -14,13 +16,22 @@ export const AlertList = ({ pagination, title, onItemClick, + legendItems }: AlertListProps)=>{ return (
-
- {title} - ({pagination?.total}) -
+
+
+ {title} + ({pagination?.total}) +
+ { + legendItems ? (
+ +
):null + } + +
{ + return ( +
+ {(items || []).map(item=>{ + return
+ + {item.title} +
+ })} +
+ ) + +} \ No newline at end of file diff --git a/web/src/pages/Alerting/pages/Dashboard/components/AlertList/alertlist.scss b/web/src/pages/Alerting/pages/Dashboard/components/AlertList/alertlist.scss index e6e3dfe4..4e16523e 100644 --- a/web/src/pages/Alerting/pages/Dashboard/components/AlertList/alertlist.scss +++ b/web/src/pages/Alerting/pages/Dashboard/components/AlertList/alertlist.scss @@ -1,14 +1,21 @@ .alert-list{ background: #f0f2f5; padding: 10px 5px; - .title{ - color: #333; - font-weight:600; - padding-bottom: 6px; - .total{ - color: #999; - margin-left: 15px; - font-size: 12px; + .header{ + display: flex; + .title{ + color: #333; + font-weight:600; + padding-bottom: 6px; + .total{ + color: #999; + margin-left: 15px; + font-size: 12px; + } + } + .legend{ + margin-left: auto; } } + } \ No newline at end of file diff --git a/web/src/pages/Alerting/pages/Dashboard/components/AlertList/legend.scss b/web/src/pages/Alerting/pages/Dashboard/components/AlertList/legend.scss new file mode 100644 index 00000000..73b70da8 --- /dev/null +++ b/web/src/pages/Alerting/pages/Dashboard/components/AlertList/legend.scss @@ -0,0 +1,18 @@ +.legend-list{ + display: flex; + align-items: center; + justify-content: center; + >.legend-item{ + margin-left: 10px; + .shape{ + width: 10px; + height: 10px; + display: inline-block; + } + .text{ + font-size: 12px; + font-weight: 500; + margin-left: 3px; + } + } +} diff --git a/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx b/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx index d71fce18..79f64142 100644 --- a/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx +++ b/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx @@ -2,6 +2,7 @@ import {AlertList} from '../components/AlertList/AlertList'; import _ from 'lodash'; import {useState, useEffect} from 'react'; import './alertoverview.scss'; +import { formatMessage } from 'umi/locale'; export const AlertOverview = (props: any)=>{ const {httpClient, history} = props; @@ -10,8 +11,13 @@ export const AlertOverview = (props: any)=>{ totalAlerts: 0, }); + const [historyData, setHistoryData] = useState({ + alerts: [], + totalAlerts: 0, + }); + const getAlerts = _.debounce( - (from, size, search, sortField, sortDirection, severityLevel, alertState, monitorIds) => { + (from, size, search, sortField, sortDirection, severityLevel, alertState, monitorIds, type) => { let params = { from, size, @@ -20,15 +26,21 @@ export const AlertOverview = (props: any)=>{ sortDirection, severityLevel, alertState, + type, }; if(monitorIds){ params["monitorIds"]= monitorIds; } - // const queryParamsString = queryString.stringify(params); - // history.replace({ ...this.props.location, search: queryParamsString }); httpClient.get('/alerting/alerts', { query: params }).then((resp:any) => { if (resp.ok) { const { alerts, totalAlerts } = resp; + if(type == 'ALERT_HISTORY'){ + setHistoryData({ + alerts, + totalAlerts, + }); + return; + } setData({ alerts, totalAlerts, @@ -44,13 +56,17 @@ export const AlertOverview = (props: any)=>{ const pageSize = 10; useEffect(()=>{ - getAlerts(0, pageSize, "", "start_time", "desc", "ALL", "ALL","") + getAlerts(0, pageSize, "", "start_time", "desc", "ALL", "ALL","", "ALERT"); + getAlerts(0, pageSize, "", "start_time", "desc", "ALL", "ALL","", "ALERT_HISTORY") },[]) - const onPageChange = (pageIndex: number)=>{ - const from = (pageIndex - 1) * pageSize; - getAlerts(from, pageSize, "", "start_time", "desc", "ALL", "ALL","") + const onPageChangeGen = (type:string) => { + return (pageIndex: number)=>{ + const from = (pageIndex - 1) * pageSize; + getAlerts(from, pageSize, "", "start_time", "desc", "ALL", "ALL","", type) + } } + const onItemClick = (item: any)=>{ history.push(`/monitors/${item.monitor_id}`) @@ -60,17 +76,25 @@ export const AlertOverview = (props: any)=>{
+
-
+ {/*
提示
-
+
*/}
) } \ No newline at end of file diff --git a/web/src/pages/Alerting/pages/Destinations/components/DestinationsList/DestinationsActions/DestinationsActions.js b/web/src/pages/Alerting/pages/Destinations/components/DestinationsList/DestinationsActions/DestinationsActions.js index 806e5389..fd91d77a 100644 --- a/web/src/pages/Alerting/pages/Destinations/components/DestinationsList/DestinationsActions/DestinationsActions.js +++ b/web/src/pages/Alerting/pages/Destinations/components/DestinationsList/DestinationsActions/DestinationsActions.js @@ -87,7 +87,7 @@ export default class DestinationsActions extends Component { ) : null} - + {formatMessage({ id: 'alert.button.add-destination' })} diff --git a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddEmailGroupButton/AddEmailGroupButton.js b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddEmailGroupButton/AddEmailGroupButton.js index d24352cb..43a759e2 100644 --- a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddEmailGroupButton/AddEmailGroupButton.js +++ b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddEmailGroupButton/AddEmailGroupButton.js @@ -18,10 +18,11 @@ import _ from 'lodash'; import { EuiButton } from '@elastic/eui'; import { FORMIK_INITIAL_EMAIL_GROUP_VALUES } from '../Email/utils/constants'; +import {formatMessage} from 'umi/locale'; const AddEmailGroupButton = ({ arrayHelpers }) => ( arrayHelpers.unshift(_.cloneDeep(FORMIK_INITIAL_EMAIL_GROUP_VALUES))}> - Add email group + {formatMessage({id:'alert.emailgroup.manage.button.add'})} ); diff --git a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddSenderButton/AddSenderButton.js b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddSenderButton/AddSenderButton.js index 8219412e..cbcf6710 100644 --- a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddSenderButton/AddSenderButton.js +++ b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/AddSenderButton/AddSenderButton.js @@ -18,10 +18,11 @@ import _ from 'lodash'; import { EuiButton } from '@elastic/eui'; import { FORMIK_INITIAL_SENDER_VALUES } from '../Email/utils/constants'; +import {formatMessage} from 'umi/locale'; const AddSenderButton = ({ arrayHelpers }) => ( arrayHelpers.unshift(_.cloneDeep(FORMIK_INITIAL_SENDER_VALUES))}> - Add sender + {formatMessage({id:'alert.email.manage.button.add'})} ); diff --git a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/EmailGroup.js b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/EmailGroup.js index d92ea360..cb566968 100644 --- a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/EmailGroup.js +++ b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/EmailGroup.js @@ -19,6 +19,7 @@ import { FormikComboBox, FormikFieldText } from '../../../../../components/FormC import { isInvalid, hasError } from '../../../../../utils/validate'; import { validateEmailGroupEmails, validateEmailGroupName } from './utils/validate'; import { STATE } from './utils/constants'; +import {formatMessage} from 'umi/locale'; const onEmailGroupChange = (index, emailGroup, arrayHelpers) => { // Checking for id here since new email groups should not be marked as updated @@ -49,7 +50,7 @@ const EmailGroup = ({ emailGroup, emailOptions, arrayHelpers, context, index, on paddingSize="l" extraAction={ - Remove email group + {formatMessage({id:'alert.emailgroup.manage.button.remove'})} } > @@ -58,10 +59,8 @@ const EmailGroup = ({ emailGroup, emailOptions, arrayHelpers, context, index, on formRow fieldProps={{ validate: validateEmailGroupName(context.ctx.emailGroups) }} rowProps={{ - label: 'Email group name', - helpText: - 'A unique and descriptive name that is easy to search. ' + - 'Valid characters are upper and lowercase a-z, 0-9, _ (underscore) and - (hyphen).', + label: formatMessage({id:'alert.emailgroup.manage.field.name'}), + helpText:formatMessage({id:'alert.emailgroup.manage.field.name.help'}), style: { padding: '10px 0px' }, isInvalid, error: hasError, @@ -79,8 +78,8 @@ const EmailGroup = ({ emailGroup, emailOptions, arrayHelpers, context, index, on formRow fieldProps={{ validate: validateEmailGroupEmails }} rowProps={{ - label: 'Emails', - helpText: 'Search for previously used email addresses or type in new ones.', + label: formatMessage({id:'alert.emailgroup.manage.field.emails'}), + helpText: formatMessage({id:'alert.emailgroup.manage.field.emails.help'}), isInvalid, error: hasError, }} diff --git a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/Sender.js b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/Sender.js index 19178cab..0ba76566 100644 --- a/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/Sender.js +++ b/web/src/pages/Alerting/pages/Destinations/components/createDestinations/Email/Sender.js @@ -24,6 +24,7 @@ import { import { isInvalid, hasError } from '../../../../../utils/validate'; import { validateEmail, validateHost, validatePort, validateSenderName } from './utils/validate'; import { METHOD_TYPE, STATE } from './utils/constants'; +import {formatMessage} from 'umi/locale'; const methodOptions = [ { value: METHOD_TYPE.NONE, text: 'None' }, @@ -51,7 +52,7 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { paddingSize="l" extraAction={ - Remove sender + {formatMessage({id:'alert.email.manage.button.remove'})} } > @@ -60,10 +61,8 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { formRow fieldProps={{ validate: validateSenderName(context.ctx.senders) }} rowProps={{ - label: 'Sender name', - helpText: - 'A unique and descriptive name that is easy to search. ' + - 'Valid characters are upper and lowercase a-z, 0-9, and _ (underscore).', + label: formatMessage({id:'alert.email.manage.field.name'}), + helpText:formatMessage({id:'alert.email.manage.field.name.help'}), style: { padding: '10px 0px' }, isInvalid, error: hasError, @@ -88,7 +87,7 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { formRow fieldProps={{ validate: validateEmail }} rowProps={{ - label: 'Email address', + label: formatMessage({id:'alert.email.manage.field.address'}), isInvalid, error: hasError, }} @@ -108,7 +107,7 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { formRow // fieldProps={{ validate: validateEmail }} rowProps={{ - label: 'Email password', + label: formatMessage({id:'alert.email.manage.field.password'}), isInvalid, error: hasError, }} @@ -130,7 +129,7 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { formRow fieldProps={{ validate: validateHost }} rowProps={{ - label: 'Host', + label: formatMessage({id:'alert.email.manage.field.host'}), isInvalid, error: hasError, }} @@ -150,7 +149,7 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { formRow fieldProps={{ validate: validatePort }} rowProps={{ - label: 'Port', + label: formatMessage({id:'alert.email.manage.field.port'}), isInvalid, error: hasError, }} @@ -169,11 +168,11 @@ const Sender = ({ sender, arrayHelpers, context, index, onDelete }) => { name={`senders.${index}.method`} formRow rowProps={{ - label: 'Encryption method', - helpText: `SSL or TLS is recommended for security. - SSL and TLS requires validation by adding the following fields to the Elasticsearch keystore: - opendistro.alerting.destination.email.${!name ? '[sender name]' : name}.username - opendistro.alerting.destination.email.${!name ? '[sender name]' : name}.password`, + label: formatMessage({id:'alert.email.manage.field.method'}), + // helpText: `SSL or TLS is recommended for security. + // SSL and TLS requires validation by adding the following fields to the Elasticsearch keystore: + // opendistro.alerting.destination.email.${!name ? '[sender name]' : name}.username + // opendistro.alerting.destination.email.${!name ? '[sender name]' : name}.password`, style: { padding: '10px 0px' }, }} inputProps={{ diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js index b8d28a30..4ed4f0df 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js @@ -39,6 +39,7 @@ import { SubmitErrorHandler } from '../../../../utils/SubmitErrorHandler'; import { getAllowList } from '../../utils/helpers'; import { backendErrorNotification } from '../../../../utils/helpers'; import { formatMessage } from 'umi/locale'; +import {pathPrefix} from '@/services/common'; const destinationType = { [DESTINATION_TYPE.SLACK]: (props) => , @@ -59,7 +60,7 @@ class CreateDestination extends React.Component { async componentDidMount() { const { httpClient, location, edit, history } = this.props; - const allowList = await getAllowList(httpClient); + const allowList = [DESTINATION_TYPE.EMAIL,DESTINATION_TYPE.CUSTOM_HOOK];//await getAllowList(httpClient); this.setState({ allowList }); let ifSeqNo, ifPrimaryTerm; @@ -90,7 +91,7 @@ class CreateDestination extends React.Component { getDestination = async (destinationId) => { const { httpClient, history, notifications } = this.props; try { - const resp = await httpClient.get(`/alerting/destinations/${destinationId}`); + const resp = await httpClient.get(pathPrefix + `/alerting/destinations/${destinationId}`); if (resp.ok) { const ifSeqNo = _.get(resp, 'ifSeqNo'); const ifPrimaryTerm = _.get(resp, 'ifPrimaryTerm'); @@ -101,7 +102,7 @@ class CreateDestination extends React.Component { } else { // Handle error, show message in case of 404 backendErrorNotification(notifications, 'get', 'destination', resp.resp); - history.push(`/destinations`); + history.push(`alerting/destination`); } } catch (e) { console.log('Unable to get the data'); @@ -119,7 +120,7 @@ class CreateDestination extends React.Component { } = this.props; const { ifSeqNo, ifPrimaryTerm } = this.state; try { - const resp = await httpClient.put(`/alerting/destinations/${destinationId}`, { + const resp = await httpClient.put(pathPrefix+`/alerting/destinations/${destinationId}`, { query: { ifSeqNo, ifPrimaryTerm }, body: JSON.stringify(requestData), }); @@ -140,7 +141,7 @@ class CreateDestination extends React.Component { handleCreate = async (requestData, { setSubmitting }) => { const { httpClient, history, notifications } = this.props; try { - const resp = await httpClient.post('/alerting/destinations', { + const resp = await httpClient.post(pathPrefix+'/alerting/destinations', { body: JSON.stringify(requestData), }); setSubmitting(false); diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/EmailRecipients.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/EmailRecipients.js index 7d97cad3..bee6bf88 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/EmailRecipients.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/EmailRecipients.js @@ -44,7 +44,7 @@ export default class EmailRecipients extends React.Component { async componentDidMount() { const { httpClient } = this.props; - const allowList = await getAllowList(httpClient); + const allowList = [DESTINATION_TYPE.EMAIL, DESTINATION_TYPE.CUSTOM_HOOK];//await getAllowList(httpClient); this.setState({ allowList }); this.loadData(); diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js index 12f9a157..fe3d51ee 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js @@ -14,10 +14,11 @@ */ import { MAX_QUERY_RESULT_SIZE } from '../../../../../../utils/constants'; +import {pathPrefix} from '@/services/common'; export default async function getEmailGroups(httpClient, searchText = '') { try { - const response = await httpClient.get('/alerting/destinations/email_groups', { + const response = await httpClient.get(pathPrefix+'/alerting/destinations/email_groups', { query: { search: searchText, size: MAX_QUERY_RESULT_SIZE }, }); if (response.ok) { diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/EmailSender.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/EmailSender.js index 83aa8fab..cb61a345 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/EmailSender.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/EmailSender.js @@ -43,7 +43,7 @@ export default class EmailSender extends React.Component { async componentDidMount() { const { httpClient } = this.props; - const allowList = await getAllowList(httpClient); + const allowList = [DESTINATION_TYPE.CUSTOM_HOOK, DESTINATION_TYPE.EMAIL];//await getAllowList(httpClient); this.setState({ allowList }); this.loadSenders(); diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js index a29d045a..498d119b 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js @@ -14,10 +14,11 @@ */ import { MAX_QUERY_RESULT_SIZE } from '../../../../../../utils/constants'; +import {pathPrefix} from '@/services/common'; export default async function getSenders(httpClient, searchText = '') { try { - const response = await httpClient.get('/alerting/destinations/email_accounts', { + const response = await httpClient.get(pathPrefix+'/alerting/destinations/email_accounts', { query: { search: searchText, size: MAX_QUERY_RESULT_SIZE }, }); if (response.ok) { diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js index 819034e7..aaaa37aa 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js @@ -39,6 +39,8 @@ import { emailGroupToFormik } from './utils/helpers'; import getEmailGroups from '../EmailRecipients/utils/helpers'; import { STATE } from '../../../components/createDestinations/Email/utils/constants'; import { ignoreEscape } from '../../../../../utils/helpers'; +import {pathPrefix} from '@/services/common'; +import {formatMessage} from 'umi/locale'; const createEmailGroupContext = (emailGroups) => ({ ctx: { @@ -119,7 +121,7 @@ export default class ManageEmailGroups extends React.Component { emails: emailGroup.emails.map((email) => ({ email: email.label })), }; try { - const response = await httpClient.post(`/alerting/destinations/email_groups`, { + const response = await httpClient.post(pathPrefix+`/alerting/destinations/email_groups`, { body: JSON.stringify(body), }); if (!response.ok) { @@ -147,7 +149,7 @@ export default class ManageEmailGroups extends React.Component { emails: updatedEmailGroup.emails.map((email) => ({ email: email.label })), }; try { - const response = await httpClient.put(`/alerting/email_groups/${id}`, { + const response = await httpClient.put(pathPrefix + `/alerting/email_groups/${id}`, { query: { ifSeqNo, ifPrimaryTerm }, body: JSON.stringify(body), }); @@ -172,7 +174,7 @@ export default class ManageEmailGroups extends React.Component { const { httpClient, notifications } = this.props; const { id } = emailGroup; try { - const response = await httpClient.delete(`/alerting/email_groups/${id}`); + const response = await httpClient.delete(pathPrefix + `/alerting/email_groups/${id}`); if (!response.ok) { this.setState({ failedEmailGroups: true }); notifications.toasts.addDanger({ @@ -276,7 +278,7 @@ export default class ManageEmailGroups extends React.Component { onClose={ignoreEscape(onClickCancel)} > - Manage email groups + {formatMessage({id:'alert.emailgroup.manage.title'})} @@ -301,11 +303,11 @@ export default class ManageEmailGroups extends React.Component { - Cancel + {formatMessage({id:'form.button.cancel'})} - Save + {formatMessage({id:'form.button.save'})} diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js index d73c6785..7ba1a07e 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js @@ -39,6 +39,8 @@ import { senderToFormik } from './utils/helpers'; import getSenders from '../EmailSender/utils/helpers'; import { STATE } from '../../../components/createDestinations/Email/utils/constants'; import { ignoreEscape } from '../../../../../utils/helpers'; +import {pathPrefix} from '@/services/common'; +import {formatMessage} from 'umi/locale'; const createSenderContext = (senders) => ({ ctx: { @@ -108,7 +110,7 @@ export default class ManageSenders extends React.Component { password: sender.password, }; try { - const response = await httpClient.post(`/alerting/destinations/email_accounts`, { + const response = await httpClient.post(pathPrefix+`/alerting/destinations/email_accounts`, { body: JSON.stringify(body), }); if (!response.ok) { @@ -140,7 +142,7 @@ export default class ManageSenders extends React.Component { password: updatedSender.password, }; try { - const response = await httpClient.put(`/alerting/email_accounts/${id}`, { + const response = await httpClient.put(pathPrefix+`/alerting/email_accounts/${id}`, { query: { ifSeqNo, ifPrimaryTerm }, body: JSON.stringify(body), }); @@ -165,7 +167,7 @@ export default class ManageSenders extends React.Component { const { httpClient, notifications } = this.props; const { id } = sender; try { - const response = await httpClient.delete(`/alerting/email_accounts/${id}`); + const response = await httpClient.delete(pathPrefix+`/alerting/email_accounts/${id}`); if (!response.ok) { this.setState({ failedSenders: true }); notifications.toasts.addDanger({ @@ -266,7 +268,7 @@ export default class ManageSenders extends React.Component { onClose={ignoreEscape(onClickCancel)} > - Manage email senders + {formatMessage({id:'alert.email.manage.title'})} @@ -291,11 +293,11 @@ export default class ManageSenders extends React.Component { - Cancel + {formatMessage({id:'form.button.cancel'})} - Save + {formatMessage({id:'form.button.save'})} diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/constants.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/constants.js index 85b49156..ecde80de 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/constants.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/constants.js @@ -27,7 +27,7 @@ const DEFAULT_CONTENT_VALUE = 'application/json'; export const formikInitialValues = { urlType: 'url', name: '', - type: 'slack', + type: 'custom_webhook', [DESTINATION_TYPE.SLACK]: { url: '', }, diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js index 3eb38acd..b904065c 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js @@ -17,6 +17,7 @@ import _ from 'lodash'; import { URL_TYPE, CONTENT_TYPE_KEY } from './constants'; import { DESTINATION_TYPE } from '../../../utils/constants'; import { RECIPIENT_TYPE } from '../EmailRecipients/utils/constants'; +import {pathPrefix} from '@/services/common'; const getAttributeArrayFromValues = (attributes) => Object.keys(attributes).map((currentKey) => ({ @@ -49,7 +50,7 @@ const customWebhookToFormik = ({ const getSender = async (httpClient, id) => { try { - const response = await httpClient.get(`/alerting/email_accounts/${id}`); + const response = await httpClient.get(pathPrefix+`/alerting/email_accounts/${id}`); if (response.ok) { return response.resp; } @@ -62,7 +63,7 @@ const getSender = async (httpClient, id) => { const getEmailGroup = async (httpClient, id) => { try { - const response = await httpClient.get(`/alerting/email_groups/${id}`); + const response = await httpClient.get(pathPrefix+`/alerting/email_groups/${id}`); if (response.ok) { return response.resp; } diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js index 6ff3b58f..de1d18e7 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js @@ -16,6 +16,7 @@ import _ from 'lodash'; import { INDEX } from '../../../../../utils/constants'; import { getAllowList } from '../../../utils/helpers'; +import {pathPrefix} from '@/services/common'; export const validateDestinationName = (httpClient, destinationToEdit) => async (value) => { try { @@ -24,8 +25,9 @@ export const validateDestinationName = (httpClient, destinationToEdit) => async index: INDEX.SCHEDULED_JOBS, query: { query: { term: { 'destination.name.keyword': value } } }, }; - const response = await httpClient.post('/alerting/monitors/_search', { + const response = await httpClient.post(pathPrefix+'/alerting/_search', { body: JSON.stringify(options), + prependBasePath: false, }); if (_.get(response, 'resp.hits.total.value', 0)) { if (!destinationToEdit) return 'Destination name is already used'; diff --git a/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js b/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js index 8d43be24..86eacbd5 100644 --- a/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js +++ b/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js @@ -36,6 +36,7 @@ import { getAllowList } from '../../utils/helpers'; import { DESTINATION_TYPE } from '../../utils/constants'; import { backendErrorNotification } from '../../../../utils/helpers'; import { formatMessage } from 'umi/locale'; +import {pathPrefix} from '@/services/common'; class DestinationsList extends React.Component { constructor(props) { @@ -101,7 +102,7 @@ class DestinationsList extends React.Component { async componentDidMount() { const { httpClient } = this.props; - const allowList = await getAllowList(httpClient); + const allowList = [DESTINATION_TYPE.EMAIL, DESTINATION_TYPE.CUSTOM_HOOK];//await getAllowList(httpClient); this.setState({ allowList }); const { page, queryParams } = this.state; @@ -120,8 +121,9 @@ class DestinationsList extends React.Component { query: isDeleteAllowedQuery(type, id), index: INDEX.SCHEDULED_JOBS, }; - const resp = await httpClient.post('/alerting/monitors/_search', { + const resp = await httpClient.post(pathPrefix+'/alerting/_search', { body: JSON.stringify(requestBody), + prependBasePath: false, }); const total = _.get(resp, 'resp.hits.total.value'); return total === 0; @@ -152,7 +154,7 @@ class DestinationsList extends React.Component { const { id: destinationId } = this.state.destinationToDelete; const { httpClient, notifications } = this.props; try { - const resp = await httpClient.delete(`/alerting/destinations/${destinationId}`); + const resp = await httpClient.delete(pathPrefix+`/alerting/destinations/${destinationId}`); if (resp.ok) { await this.getDestinations(); } else { @@ -215,7 +217,7 @@ class DestinationsList extends React.Component { // search: queryParms, // }); try { - const resp = await httpClient.get('/alerting/destinations', { + const resp = await httpClient.get(pathPrefix+ '/alerting/destinations', { query: { from, ...params }, }); if (resp.ok) { diff --git a/web/src/pages/Alerting/pages/Destinations/utils/helpers.js b/web/src/pages/Alerting/pages/Destinations/utils/helpers.js index c8ffe93a..50f19a26 100644 --- a/web/src/pages/Alerting/pages/Destinations/utils/helpers.js +++ b/web/src/pages/Alerting/pages/Destinations/utils/helpers.js @@ -16,10 +16,13 @@ import _ from 'lodash'; import { ALLOW_LIST_SETTING_PATH } from './constants'; import { backendErrorNotification } from '../../../utils/helpers'; +import {pathPrefix} from '@/services/common'; export async function getAllowList(httpClient) { try { - const response = await httpClient.get('/alerting/_settings'); + const response = await httpClient.get(pathPrefix+'/alerting/_settings', { + prependBasePath: false, + }); if (response.ok) { // Attempt to resolve the value of allow_list in the order of 'persistent, 'transient' and 'defaults' settings const { defaults, transient, persistent } = response.resp; diff --git a/web/src/pages/Alerting/pages/Home/Home.js b/web/src/pages/Alerting/pages/Home/Home.js index a8221edb..25087122 100644 --- a/web/src/pages/Alerting/pages/Home/Home.js +++ b/web/src/pages/Alerting/pages/Home/Home.js @@ -49,11 +49,11 @@ export default class Home extends Component { name: formatMessage({ id: 'alert.monitor' }), route: 'monitors', }, - { - id: 'destinations', - name: formatMessage({ id: 'alert.destination' }), - route: 'destinations', - }, + // { + // id: 'destinations', + // name: formatMessage({ id: 'alert.destination' }), + // route: 'destinations', + // }, ]; } @@ -100,10 +100,11 @@ export default class Home extends Component { ( + render={(props) => { + return ( // - )} + )}} /> )} /> - ( @@ -122,7 +123,7 @@ export default class Home extends Component { notifications={notifications} /> )} - /> + /> */} - ( - - )} - /> ( @@ -74,7 +68,7 @@ class Main extends Component { /> )} /> - ( )} - /> + /> */} ( diff --git a/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/MonitorOverview.js b/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/MonitorOverview.js index f6178d88..c18caa2c 100644 --- a/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/MonitorOverview.js +++ b/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/MonitorOverview.js @@ -19,11 +19,12 @@ import { EuiFlexGrid } from '@elastic/eui'; import ContentPanel from '../../../../components/ContentPanel/index'; import OverviewStat from '../OverviewStat/index'; import getOverviewStats from './utils/getOverviewStats'; +import {formatMessage} from 'umi/locale'; const MonitorOverview = ({ monitor, monitorId, monitorVersion, activeCount }) => { const items = getOverviewStats(monitor, monitorId, monitorVersion, activeCount); return ( - + {items.map(props => ( diff --git a/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/utils/getOverviewStats.js b/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/utils/getOverviewStats.js index f2f9918d..8c1c9506 100644 --- a/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/utils/getOverviewStats.js +++ b/web/src/pages/Alerting/pages/MonitorDetails/components/MonitorOverview/utils/getOverviewStats.js @@ -18,6 +18,7 @@ import moment from 'moment-timezone'; import getScheduleFromMonitor from './getScheduleFromMonitor'; import { DEFAULT_EMPTY_DATA, SEARCH_TYPE } from '../../../../../utils/constants'; +import {formatMessage} from 'umi/locale'; // TODO: used in multiple places, move into helper function getTime(time) { @@ -31,42 +32,42 @@ export default function getOverviewStats(monitor, monitorId, monitorVersion, act const searchType = _.get(monitor, 'ui_metadata.search.searchType', 'query'); return [ { - header: 'State', + header: formatMessage({id:"alert.monitor.overview.header.state"}), value: monitor.enabled ? 'Enabled' : 'Disabled', }, { - header: 'Monitor definition type', + header: formatMessage({id:"alert.monitor.overview.header.definition_type"}), value: searchType === SEARCH_TYPE.QUERY ? 'Extraction Query' : 'Visual graph', }, { - header: 'Total active alerts', + header: formatMessage({id:"alert.monitor.overview.header.total_active_alerts"}), value: activeCount, }, { - header: 'Schedule', + header: formatMessage({id:"alert.monitor.overview.header.schedule"}), value: getScheduleFromMonitor(monitor), }, { - header: 'Last updated', + header: formatMessage({id:"alert.monitor.overview.header.last_updated"}), value: getTime(monitor.last_update_time), }, { - header: 'Monitor ID', + header: formatMessage({id:"alert.monitor.overview.header.monitor_id"}), value: monitorId, }, { - header: 'Monitor version number', + header: formatMessage({id:"alert.monitor.overview.header.version_number"}), value: monitorVersion, }, - { - /* There are 3 cases: - 1. Monitors created by older versions and never updated. - These monitors won’t have User details in the monitor object. `monitor.user` will be null. - 2. Monitors are created when security plugin is disabled, these will have empty User object. - (`monitor.user.name`, `monitor.user.roles` are empty ) - 3. Monitors are created when security plugin is enabled, these will have an User object. */ - header: 'Last updated by', - value: monitor.user && monitor.user.name ? monitor.user.name : 'N/A', - }, + // { + // /* There are 3 cases: + // 1. Monitors created by older versions and never updated. + // These monitors won’t have User details in the monitor object. `monitor.user` will be null. + // 2. Monitors are created when security plugin is disabled, these will have empty User object. + // (`monitor.user.name`, `monitor.user.roles` are empty ) + // 3. Monitors are created when security plugin is enabled, these will have an User object. */ + // header: 'Last updated by', + // value: monitor.user && monitor.user.name ? monitor.user.name : 'N/A', + // }, ]; } diff --git a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js index 8c80fa7a..873f9a0c 100644 --- a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js +++ b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js @@ -43,6 +43,7 @@ import { } from '../../../utils/constants'; import { migrateTriggerMetadata } from './utils/helpers'; import { backendErrorNotification } from '../../../utils/helpers'; +import {formatMessage} from 'umi/locale'; export default class MonitorDetails extends Component { constructor(props) { @@ -323,7 +324,7 @@ export default class MonitorDetails extends Component { }); }} > - Edit + {formatMessage({ id: 'form.button.edit' })} @@ -331,7 +332,7 @@ export default class MonitorDetails extends Component { isLoading={updating} onClick={() => this.updateMonitor({ enabled: !monitor.enabled })} > - {monitor.enabled ? 'Disable' : 'Enable'} + {monitor.enabled ? formatMessage({id:'alert.monitor.actions.disable'}) : formatMessage({id:'alert.monitor.actions.enable'})} diff --git a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js index 5c604b95..38879f19 100644 --- a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js +++ b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js @@ -37,6 +37,8 @@ import { import * as HistoryConstants from './utils/constants'; import { INDEX } from '../../../../utils/constants'; import { backendErrorNotification } from '../../../../utils/helpers'; +import {pathPrefix} from '@/services/common'; +import {formatMessage} from 'umi/locale'; class MonitorHistory extends PureComponent { constructor(props) { @@ -200,8 +202,9 @@ class MonitorHistory extends PureComponent { ), index: INDEX.ALL_ALERTS, }; - const resp = await httpClient.post('/alerting/monitors/_search', { + const resp = await httpClient.post(pathPrefix + '/alerting/_search', { body: JSON.stringify(requestBody), + prependBasePath: false, }); if (resp.ok) { const poiData = get(resp, 'resp.aggregations.alerts_over_time.buckets', []).map((item) => ({ @@ -309,7 +312,7 @@ class MonitorHistory extends PureComponent { const { triggers, onShowTrigger } = this.props; return ( actions.length, }, { field: 'severity', - name: 'Severity', + name: formatMessage({ id: 'alert.monitor.triggers.table.header.severity' }), sortable: true, truncateText: false, }, @@ -105,22 +106,22 @@ export default class Triggers extends Component { return ( - Edit + {formatMessage({ id: 'form.button.edit' })} , - Delete + {formatMessage({ id: 'form.button.delete' })} , = MAX_TRIGGERS} fill > - Create + {formatMessage({ id: 'form.button.create' })} , ]} > diff --git a/web/src/pages/Alerting/pages/Overview/Overview.js b/web/src/pages/Alerting/pages/Overview/Overview.js index 00acfd21..01e84580 100644 --- a/web/src/pages/Alerting/pages/Overview/Overview.js +++ b/web/src/pages/Alerting/pages/Overview/Overview.js @@ -1,5 +1,6 @@ -import React, {useEffect, useState} from "react"; +import React, {useEffect, useState, useMemo} from "react"; import {Spin, Card} from 'antd'; +import {Fetch} from '../../../../components/kibana/core/public/http/fetch'; import './overview.scss'; import { Axis, @@ -13,9 +14,11 @@ import { timeFormatter, BarSeries, } from "@elastic/charts"; +import {pathPrefix} from '@/services/common'; import {useAlertData, useAlertHsitoryData} from './hooks/use_alert_data'; import {AlertList} from '../Dashboard/components/AlertList/AlertList'; +import { formatMessage } from 'umi/locale'; const theme = { legend: { @@ -70,7 +73,7 @@ const theme = { export default (props)=>{ - const {httpClient, history} = props; + const {history} = props; const [isLoading, setIsLoading] = useState(true); const [data, setData] = useState({ metrics: { @@ -78,8 +81,18 @@ export default (props)=>{ top_ten_cluster:{}, }, }); + const httpClient = useMemo(()=>{ + return new Fetch({ + basePath:{ + get: () => '', + prepend: (url) => url, + remove: (url) => url, + serverBasePath: '', + } + }); + }) useEffect(()=>{ - httpClient.get('/alerting/overview', {}).then((resp) => { + httpClient.get(pathPrefix + '/alerting/overview', {}).then((resp) => { if (resp.ok) { const { metrics, state_count } = resp; setData({ @@ -97,9 +110,18 @@ export default (props)=>{ const [historyAlerts, onAlertHistoryPageChange] = useAlertHsitoryData(pageSize); const onItemClick = (item)=>{ - history.push(`/monitors/${item.monitor_id}/elasticsearch/${item.cluster_id}`) + history.push(`/alerting/monitor/monitors/${item.monitor_id}/elasticsearch/${item.cluster_id}`) + } + const pickLegendItems = (items)=>{ + return [{title:'ACKNOWLEDGED',color:'pink'}, {title:'ACTIVE',color:' rgb(208, 2, 27)'}, + {title:'ERROR', color:'lightgrey'}, {color:'rgb(208, 2, 27)', title:'COMPLETED'}, {title:'DELETED', color:'gray'}] + .filter(legend=> items.includes(legend.title)).map(legend=>{ + return { + ...legend, + title: formatMessage({id: `alert.dashboard.state-options.${legend.title.toLowerCase()}`}) + } + }) } - return (
@@ -107,19 +129,29 @@ export default (props)=>{
- - {data.state_count?.ACTIVE || 0} + + +
+ {data.state_count?.ACTIVE || 0} +
- - {data.state_count?.ACKNOWLEDGED || 0} + + +
+ {data.state_count?.ACKNOWLEDGED || 0} +
- - {data.state_count?.ERROR || 0} + + +
+ {data.state_count?.ERROR || 0} +
{ onChange: onAlertPageChange, }}/>
-
+
{ @@ -15,14 +16,11 @@ const getAlerts = if(qstr){ qstr = `?${qstr.slice(1)}` } - const resp = await fetch('/elasticsearch/_all/alerting/alerts'+qstr); + const resp = await fetch(pathPrefix + '/alerting/overview/alerts'+qstr); return resp.json(); - // if (resp.ok) { - // const { alerts, totalAlerts } = resp; - } -export const useAlertData = (pageSize, page)=>{ +const useData = (pageSize, page, type) => { const [size, setSize] = useState(pageSize || 10); const [pageIndex, setPageIndex] = useState(page || 1); const [alertData, setAlertData] = useState({ @@ -32,7 +30,7 @@ export const useAlertData = (pageSize, page)=>{ useEffect(()=>{ const from = (pageIndex - 1) * size; const fetchAlerts = async (from, size)=>{ - const resp = await getAlerts(from, size, 'ALERT'); + const resp = await getAlerts(from, size, type); if(resp.ok){ const { alerts, totalAlerts } = resp; setAlertData({ @@ -43,7 +41,7 @@ export const useAlertData = (pageSize, page)=>{ } } fetchAlerts(from,size); - }, [pageIndex, size]); + }, [pageIndex, size, type]); const changePage = (pageIndex) => { setPageIndex(pageIndex); } @@ -51,32 +49,10 @@ export const useAlertData = (pageSize, page)=>{ return [alertData, changePage]; } -export const useAlertHsitoryData = (pageSize, page)=>{ - const [size, setSize] = useState(pageSize || 10); - const [pageIndex, setPageIndex] = useState(page || 1); - const [alertHisotryData, setAlertHisotryData] = useState({ - data: [], - total: 0, - }); - useEffect(()=>{ - const from = (pageIndex - 1) * size; - const fetchHistoryAlerts = async (from, size)=>{ - const resp = await getAlerts(from, size, 'ALERT_HISTORY'); - if(resp.ok){ - const { alerts, totalAlerts } = resp; - setAlertHisotryData({ - ...alertHisotryData, - data: alerts, - total: totalAlerts, - }) - } - } - fetchHistoryAlerts(from, size); - }, [pageIndex, size]) +export const useAlertData = (pageSize, page)=>{ + return useData(pageSize, page, 'ALERT'); +} - const changePage = (pageIndex) => { - setPageIndex(pageIndex); - } - - return [alertHisotryData, changePage]; +export const useAlertHsitoryData = (pageSize, page)=>{ + return useData(pageSize, page, 'ALERT_HISTORY'); } \ No newline at end of file diff --git a/web/src/pages/Alerting/pages/Overview/overview.scss b/web/src/pages/Alerting/pages/Overview/overview.scss index 9726a0e0..0693d785 100644 --- a/web/src/pages/Alerting/pages/Overview/overview.scss +++ b/web/src/pages/Alerting/pages/Overview/overview.scss @@ -6,11 +6,22 @@ flex-direction: column; .state-count{ display: flex; - text-align: center; justify-content: space-between; .item{ min-width: 30%; - } + .title { + padding-bottom: 10px; + border-bottom: 1px solid #eef1f4; + } + .total { + font-size: 40px; + } + .unit { + color: #767676; + font-size: 12px; + font-weight: normal; + } + } margin-bottom: 10px; } } @@ -21,4 +32,5 @@ .overview-wrapper { padding: 10px; + background-color: #fff; } \ No newline at end of file diff --git a/web/src/pages/Alerting/utils/constants.js b/web/src/pages/Alerting/utils/constants.js index cb15664b..0b6879e7 100644 --- a/web/src/pages/Alerting/utils/constants.js +++ b/web/src/pages/Alerting/utils/constants.js @@ -68,7 +68,7 @@ export const MAX_QUERY_RESULT_SIZE = 200; export const OPEN_DISTRO_PREFIX = 'infini-search-center'; -export const PLUGIN_NAME = `alerting`; +export const PLUGIN_NAME = `alerting/monitor`; export const INDEX_PREFIX = `${OPEN_DISTRO_PREFIX}_alerting`; export const INDEX = { SCHEDULED_JOBS: `.${INDEX_PREFIX}-config`, diff --git a/web/src/pages/Alerting/utils/validate.js b/web/src/pages/Alerting/utils/validate.js index 4fc3777d..866600fa 100644 --- a/web/src/pages/Alerting/utils/validate.js +++ b/web/src/pages/Alerting/utils/validate.js @@ -15,6 +15,7 @@ import _ from 'lodash'; import { INDEX, MAX_THROTTLE_VALUE, WRONG_THROTTLE_WARNING } from '../utils/constants'; +import {pathPrefix} from '@/services/common' // TODO: Use a validation framework to clean all of this up or create own. @@ -56,8 +57,9 @@ export const validateMonitorName = (httpClient, monitorToEdit) => async (value) index: INDEX.SCHEDULED_JOBS, query: { query: { term: { 'monitor.name.keyword': value } } }, }; - const response = await httpClient.post('/alerting/monitors/_search', { + const response = await httpClient.post(pathPrefix + '/alerting/_search', { body: JSON.stringify(options), + prependBasePath: false, }); if (_.get(response, 'resp.hits.total.value', 0)) { if (!monitorToEdit) return 'Monitor name is already used';