diff --git a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml index b27244a88b9d..6ef82a62dbaa 100644 --- a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml @@ -146,7 +146,7 @@ services: condition: on-failure query-service: - image: signoz/query-service:0.42.0 + image: signoz/query-service:0.43.0 command: [ "-config=/root/config/prometheus.yml", @@ -186,7 +186,7 @@ services: <<: *db-depend frontend: - image: signoz/frontend:0.42.0 + image: signoz/frontend:0.43.0 deploy: restart_policy: condition: on-failure @@ -199,7 +199,7 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/signoz-otel-collector:0.88.17 + image: signoz/signoz-otel-collector:0.88.20 command: [ "--config=/etc/otel-collector-config.yaml", @@ -237,7 +237,7 @@ services: - query-service otel-collector-migrator: - image: signoz/signoz-schema-migrator:0.88.17 + image: signoz/signoz-schema-migrator:0.88.20 deploy: restart_policy: condition: on-failure diff --git a/deploy/docker/clickhouse-setup/docker-compose-core.yaml b/deploy/docker/clickhouse-setup/docker-compose-core.yaml index 92adebe461e0..ba9047ddf8d2 100644 --- a/deploy/docker/clickhouse-setup/docker-compose-core.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose-core.yaml @@ -66,7 +66,7 @@ services: - --storage.path=/data otel-collector-migrator: - image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.17} + image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.20} container_name: otel-migrator command: - "--dsn=tcp://clickhouse:9000" @@ -81,7 +81,7 @@ services: # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` otel-collector: container_name: signoz-otel-collector - image: signoz/signoz-otel-collector:0.88.17 + image: signoz/signoz-otel-collector:0.88.20 command: [ "--config=/etc/otel-collector-config.yaml", diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index a8b2af5b1366..f7702fa6c1ab 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -164,7 +164,7 @@ services: # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` query-service: - image: signoz/query-service:${DOCKER_TAG:-0.42.0} + image: signoz/query-service:${DOCKER_TAG:-0.43.0} container_name: signoz-query-service command: [ @@ -203,7 +203,7 @@ services: <<: *db-depend frontend: - image: signoz/frontend:${DOCKER_TAG:-0.42.0} + image: signoz/frontend:${DOCKER_TAG:-0.43.0} container_name: signoz-frontend restart: on-failure depends_on: @@ -215,7 +215,7 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector-migrator: - image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.17} + image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.20} container_name: otel-migrator command: - "--dsn=tcp://clickhouse:9000" @@ -229,7 +229,7 @@ services: otel-collector: - image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.17} + image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.20} container_name: signoz-otel-collector command: [ diff --git a/ee/query-service/app/api/api.go b/ee/query-service/app/api/api.go index 6defd8520182..418cd00cf964 100644 --- a/ee/query-service/app/api/api.go +++ b/ee/query-service/app/api/api.go @@ -152,7 +152,6 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddlew router.HandleFunc("/api/v1/register", am.OpenAccess(ah.registerUser)).Methods(http.MethodPost) router.HandleFunc("/api/v1/login", am.OpenAccess(ah.loginUser)).Methods(http.MethodPost) router.HandleFunc("/api/v1/traces/{traceId}", am.ViewAccess(ah.searchTraces)).Methods(http.MethodGet) - router.HandleFunc("/api/v2/metrics/query_range", am.ViewAccess(ah.queryRangeMetricsV2)).Methods(http.MethodPost) // PAT APIs router.HandleFunc("/api/v1/pats", am.AdminAccess(ah.createPAT)).Methods(http.MethodPost) diff --git a/ee/query-service/app/api/metrics.go b/ee/query-service/app/api/metrics.go deleted file mode 100644 index 7c0e320f451a..000000000000 --- a/ee/query-service/app/api/metrics.go +++ /dev/null @@ -1,236 +0,0 @@ -package api - -import ( - "bytes" - "fmt" - "net/http" - "sync" - "text/template" - "time" - - "go.signoz.io/signoz/pkg/query-service/app/metrics" - "go.signoz.io/signoz/pkg/query-service/app/parser" - "go.signoz.io/signoz/pkg/query-service/constants" - basemodel "go.signoz.io/signoz/pkg/query-service/model" - querytemplate "go.signoz.io/signoz/pkg/query-service/utils/queryTemplate" - "go.uber.org/zap" -) - -func (ah *APIHandler) queryRangeMetricsV2(w http.ResponseWriter, r *http.Request) { - if !ah.CheckFeature(basemodel.CustomMetricsFunction) { - zap.L().Info("CustomMetricsFunction feature is not enabled in this plan") - ah.APIHandler.QueryRangeMetricsV2(w, r) - return - } - metricsQueryRangeParams, apiErrorObj := parser.ParseMetricQueryRangeParams(r) - - if apiErrorObj != nil { - zap.L().Error("Error in parsing metric query params", zap.Error(apiErrorObj.Err)) - RespondError(w, apiErrorObj, nil) - return - } - - // prometheus instant query needs same timestamp - if metricsQueryRangeParams.CompositeMetricQuery.PanelType == basemodel.QUERY_VALUE && - metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.PROM { - metricsQueryRangeParams.Start = metricsQueryRangeParams.End - } - - // round up the end to nearest multiple - if metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.QUERY_BUILDER { - end := (metricsQueryRangeParams.End) / 1000 - step := metricsQueryRangeParams.Step - metricsQueryRangeParams.End = (end / step * step) * 1000 - } - - type channelResult struct { - Series []*basemodel.Series - TableName string - Err error - Name string - Query string - } - - execClickHouseQueries := func(queries map[string]string) ([]*basemodel.Series, []string, error, map[string]string) { - var seriesList []*basemodel.Series - var tableName []string - ch := make(chan channelResult, len(queries)) - var wg sync.WaitGroup - - for name, query := range queries { - wg.Add(1) - go func(name, query string) { - defer wg.Done() - seriesList, tableName, err := ah.opts.DataConnector.GetMetricResultEE(r.Context(), query) - for _, series := range seriesList { - series.QueryName = name - } - - if err != nil { - ch <- channelResult{Err: fmt.Errorf("error in query-%s: %v", name, err), Name: name, Query: query} - return - } - ch <- channelResult{Series: seriesList, TableName: tableName} - }(name, query) - } - - wg.Wait() - close(ch) - - var errs []error - errQuriesByName := make(map[string]string) - // read values from the channel - for r := range ch { - if r.Err != nil { - errs = append(errs, r.Err) - errQuriesByName[r.Name] = r.Query - continue - } - seriesList = append(seriesList, r.Series...) - tableName = append(tableName, r.TableName) - } - if len(errs) != 0 { - return nil, nil, fmt.Errorf("encountered multiple errors: %s", metrics.FormatErrs(errs, "\n")), errQuriesByName - } - return seriesList, tableName, nil, nil - } - - execPromQueries := func(metricsQueryRangeParams *basemodel.QueryRangeParamsV2) ([]*basemodel.Series, error, map[string]string) { - var seriesList []*basemodel.Series - ch := make(chan channelResult, len(metricsQueryRangeParams.CompositeMetricQuery.PromQueries)) - var wg sync.WaitGroup - - for name, query := range metricsQueryRangeParams.CompositeMetricQuery.PromQueries { - if query.Disabled { - continue - } - wg.Add(1) - go func(name string, query *basemodel.PromQuery) { - var seriesList []*basemodel.Series - defer wg.Done() - tmpl := template.New("promql-query") - tmpl, tmplErr := tmpl.Parse(query.Query) - if tmplErr != nil { - ch <- channelResult{Err: fmt.Errorf("error in parsing query-%s: %v", name, tmplErr), Name: name, Query: query.Query} - return - } - var queryBuf bytes.Buffer - tmplErr = tmpl.Execute(&queryBuf, metricsQueryRangeParams.Variables) - if tmplErr != nil { - ch <- channelResult{Err: fmt.Errorf("error in parsing query-%s: %v", name, tmplErr), Name: name, Query: query.Query} - return - } - query.Query = queryBuf.String() - queryModel := basemodel.QueryRangeParams{ - Start: time.UnixMilli(metricsQueryRangeParams.Start), - End: time.UnixMilli(metricsQueryRangeParams.End), - Step: time.Duration(metricsQueryRangeParams.Step * int64(time.Second)), - Query: query.Query, - } - promResult, _, err := ah.opts.DataConnector.GetQueryRangeResult(r.Context(), &queryModel) - if err != nil { - ch <- channelResult{Err: fmt.Errorf("error in query-%s: %v", name, err), Name: name, Query: query.Query} - return - } - matrix, _ := promResult.Matrix() - for _, v := range matrix { - var s basemodel.Series - s.QueryName = name - s.Labels = v.Metric.Copy().Map() - for _, p := range v.Floats { - s.Points = append(s.Points, basemodel.MetricPoint{Timestamp: p.T, Value: p.F}) - } - seriesList = append(seriesList, &s) - } - ch <- channelResult{Series: seriesList} - }(name, query) - } - - wg.Wait() - close(ch) - - var errs []error - errQuriesByName := make(map[string]string) - // read values from the channel - for r := range ch { - if r.Err != nil { - errs = append(errs, r.Err) - errQuriesByName[r.Name] = r.Query - continue - } - seriesList = append(seriesList, r.Series...) - } - if len(errs) != 0 { - return nil, fmt.Errorf("encountered multiple errors: %s", metrics.FormatErrs(errs, "\n")), errQuriesByName - } - return seriesList, nil, nil - } - - var seriesList []*basemodel.Series - var tableName []string - var err error - var errQuriesByName map[string]string - switch metricsQueryRangeParams.CompositeMetricQuery.QueryType { - case basemodel.QUERY_BUILDER: - runQueries := metrics.PrepareBuilderMetricQueries(metricsQueryRangeParams, constants.SIGNOZ_TIMESERIES_TABLENAME) - if runQueries.Err != nil { - RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: runQueries.Err}, nil) - return - } - seriesList, tableName, err, errQuriesByName = execClickHouseQueries(runQueries.Queries) - - case basemodel.CLICKHOUSE: - queries := make(map[string]string) - - for name, chQuery := range metricsQueryRangeParams.CompositeMetricQuery.ClickHouseQueries { - if chQuery.Disabled { - continue - } - tmpl := template.New("clickhouse-query") - tmpl, err := tmpl.Parse(chQuery.Query) - if err != nil { - RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}, nil) - return - } - var query bytes.Buffer - - // replace go template variables - querytemplate.AssignReservedVars(metricsQueryRangeParams) - - err = tmpl.Execute(&query, metricsQueryRangeParams.Variables) - if err != nil { - RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}, nil) - return - } - queries[name] = query.String() - } - seriesList, tableName, err, errQuriesByName = execClickHouseQueries(queries) - case basemodel.PROM: - seriesList, err, errQuriesByName = execPromQueries(metricsQueryRangeParams) - default: - err = fmt.Errorf("invalid query type") - RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err}, errQuriesByName) - return - } - - if err != nil { - apiErrObj := &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: err} - RespondError(w, apiErrObj, errQuriesByName) - return - } - if metricsQueryRangeParams.CompositeMetricQuery.PanelType == basemodel.QUERY_VALUE && - len(seriesList) > 1 && - (metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.QUERY_BUILDER || - metricsQueryRangeParams.CompositeMetricQuery.QueryType == basemodel.CLICKHOUSE) { - RespondError(w, &basemodel.ApiError{Typ: basemodel.ErrorBadData, Err: fmt.Errorf("invalid: query resulted in more than one series for value type")}, nil) - return - } - - type ResponseFormat struct { - ResultType string `json:"resultType"` - Result []*basemodel.Series `json:"result"` - TableName []string `json:"tableName"` - } - resp := ResponseFormat{ResultType: "matrix", Result: seriesList, TableName: tableName} - ah.Respond(w, resp) -} diff --git a/ee/query-service/app/server.go b/ee/query-service/app/server.go index c742eef01b90..53b9a27314bb 100644 --- a/ee/query-service/app/server.go +++ b/ee/query-service/app/server.go @@ -10,6 +10,7 @@ import ( "net/http" _ "net/http/pprof" // http profiler "os" + "regexp" "time" "github.com/gorilla/handlers" @@ -328,7 +329,6 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e r.Use(loggingMiddleware) apiHandler.RegisterRoutes(r, am) - apiHandler.RegisterMetricsRoutes(r, am) apiHandler.RegisterLogsRoutes(r, am) apiHandler.RegisterIntegrationRoutes(r, am) apiHandler.RegisterQueryRangeV3Routes(r, am) @@ -393,13 +393,14 @@ func (lrw *loggingResponseWriter) Flush() { lrw.ResponseWriter.(http.Flusher).Flush() } -func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface{}, bool) { - pathToExtractBodyFrom := "/api/v3/query_range" +func extractQueryRangeData(path string, r *http.Request) (map[string]interface{}, bool) { + pathToExtractBodyFromV3 := "/api/v3/query_range" + pathToExtractBodyFromV4 := "/api/v4/query_range" data := map[string]interface{}{} var postData *v3.QueryRangeParamsV3 - if path == pathToExtractBodyFrom && (r.Method == "POST") { + if (r.Method == "POST") && ((path == pathToExtractBodyFromV3) || (path == pathToExtractBodyFromV4)) { if r.Body != nil { bodyBytes, err := io.ReadAll(r.Body) if err != nil { @@ -417,6 +418,25 @@ func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface return nil, false } + referrer := r.Header.Get("Referer") + + dashboardMatched, err := regexp.MatchString(`/dashboard/[a-zA-Z0-9\-]+/(new|edit)(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the referrer", zap.Error(err)) + } + alertMatched, err := regexp.MatchString(`/alerts/(new|edit)(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the alert: ", zap.Error(err)) + } + logsExplorerMatched, err := regexp.MatchString(`/logs/logs-explorer(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the logs explorer: ", zap.Error(err)) + } + traceExplorerMatched, err := regexp.MatchString(`/traces-explorer(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the trace explorer: ", zap.Error(err)) + } + signozMetricsUsed := false signozLogsUsed := false signozTracesUsed := false @@ -445,7 +465,21 @@ func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface data["tracesUsed"] = signozTracesUsed userEmail, err := baseauth.GetEmailFromJwt(r.Context()) if err == nil { - telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail) + // switch case to set data["screen"] based on the referrer + switch { + case dashboardMatched: + data["screen"] = "panel" + case alertMatched: + data["screen"] = "alert" + case logsExplorerMatched: + data["screen"] = "logs-explorer" + case traceExplorerMatched: + data["screen"] = "traces-explorer" + default: + data["screen"] = "unknown" + return data, true + } + telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail, true, false) } } return data, true @@ -472,7 +506,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler { route := mux.CurrentRoute(r) path, _ := route.GetPathTemplate() - queryRangeV3data, metadataExists := extractQueryRangeV3Data(path, r) + queryRangeData, metadataExists := extractQueryRangeData(path, r) getActiveLogs(path, r) lrw := NewLoggingResponseWriter(w) @@ -480,7 +514,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler { data := map[string]interface{}{"path": path, "statusCode": lrw.statusCode} if metadataExists { - for key, value := range queryRangeV3data { + for key, value := range queryRangeData { data[key] = value } } @@ -488,7 +522,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler { if _, ok := telemetry.EnabledPaths()[path]; ok { userEmail, err := baseauth.GetEmailFromJwt(r.Context()) if err == nil { - telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail) + telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail, true, false) } } diff --git a/ee/query-service/license/manager.go b/ee/query-service/license/manager.go index 56cb685fecb9..d348b6d216a1 100644 --- a/ee/query-service/license/manager.go +++ b/ee/query-service/license/manager.go @@ -204,7 +204,7 @@ func (lm *Manager) Validate(ctx context.Context) (reterr error) { zap.L().Error("License validation completed with error", zap.Error(reterr)) atomic.AddUint64(&lm.failedAttempts, 1) telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_CHECK_FAILED, - map[string]interface{}{"err": reterr.Error()}, "") + map[string]interface{}{"err": reterr.Error()}, "", true, false) } else { zap.L().Info("License validation completed with no errors") } @@ -263,7 +263,7 @@ func (lm *Manager) Activate(ctx context.Context, key string) (licenseResponse *m userEmail, err := auth.GetEmailFromJwt(ctx) if err == nil { telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_ACT_FAILED, - map[string]interface{}{"err": errResponse.Err.Error()}, userEmail) + map[string]interface{}{"err": errResponse.Err.Error()}, userEmail, true, false) } } }() diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 000000000000..7d7c7a5f2d0d --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,3 @@ + +# Sentry Config File +.env.sentry-build-plugin diff --git a/frontend/package.json b/frontend/package.json index e7d1861cd4e7..6040b2e3f07f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,9 +41,12 @@ "@radix-ui/react-tabs": "1.0.4", "@radix-ui/react-tooltip": "1.0.7", "@sentry/react": "7.102.1", - "@sentry/webpack-plugin": "2.14.2", + "@sentry/webpack-plugin": "2.16.0", "@signozhq/design-tokens": "0.0.8", "@uiw/react-md-editor": "3.23.5", + "@visx/group": "3.3.0", + "@visx/shape": "3.5.0", + "@visx/tooltip": "3.3.0", "@xstate/react": "^3.0.0", "ansi-to-html": "0.7.2", "antd": "5.11.0", @@ -121,6 +124,7 @@ "web-vitals": "^0.2.4", "webpack": "5.88.2", "webpack-dev-server": "^4.15.1", + "webpack-retry-chunk-load-plugin": "3.1.1", "xstate": "^4.31.0" }, "browserslist": { diff --git a/frontend/public/locales/en-GB/channels.json b/frontend/public/locales/en-GB/channels.json index 027501f69d43..807b7a6e3b81 100644 --- a/frontend/public/locales/en-GB/channels.json +++ b/frontend/public/locales/en-GB/channels.json @@ -15,6 +15,7 @@ "button_test_channel": "Test", "button_return": "Back", "field_channel_name": "Name", + "field_send_resolved": "Send resolved alerts", "field_channel_type": "Type", "field_webhook_url": "Webhook URL", "field_slack_recipient": "Recipient", diff --git a/frontend/public/locales/en/channels.json b/frontend/public/locales/en/channels.json index 9ab31d697cca..0d9387d3291b 100644 --- a/frontend/public/locales/en/channels.json +++ b/frontend/public/locales/en/channels.json @@ -15,6 +15,7 @@ "button_test_channel": "Test", "button_return": "Back", "field_channel_name": "Name", + "field_send_resolved": "Send resolved alerts", "field_channel_type": "Type", "field_webhook_url": "Webhook URL", "field_slack_recipient": "Recipient", diff --git a/frontend/public/locales/en/titles.json b/frontend/public/locales/en/titles.json index e707c998f7d1..8aef9c9af6cb 100644 --- a/frontend/public/locales/en/titles.json +++ b/frontend/public/locales/en/titles.json @@ -48,5 +48,5 @@ "TRACES_SAVE_VIEWS": "SigNoz | Traces Saved Views", "DEFAULT": "Open source Observability Platform | SigNoz", "SHORTCUTS": "SigNoz | Shortcuts", - "INTEGRATIONS_INSTALLED": "SigNoz | Integrations" + "INTEGRATIONS": "SigNoz | Integrations" } diff --git a/frontend/src/AppRoutes/index.tsx b/frontend/src/AppRoutes/index.tsx index f1927c9a4c20..7bc58c509e6a 100644 --- a/frontend/src/AppRoutes/index.tsx +++ b/frontend/src/AppRoutes/index.tsx @@ -147,7 +147,11 @@ function App(): JSX.Element { } } - if (isOnBasicPlan || (isLoggedInState && role && role !== 'ADMIN')) { + if ( + isOnBasicPlan || + (isLoggedInState && role && role !== 'ADMIN') || + !(isCloudUserVal || isEECloudUser()) + ) { const newRoutes = routes.filter((route) => route?.path !== ROUTES.BILLING); setRoutes(newRoutes); } diff --git a/frontend/src/AppRoutes/pageComponents.ts b/frontend/src/AppRoutes/pageComponents.ts index bea07a7e51f1..1252496c08cf 100644 --- a/frontend/src/AppRoutes/pageComponents.ts +++ b/frontend/src/AppRoutes/pageComponents.ts @@ -197,11 +197,3 @@ export const InstalledIntegrations = Loadable( /* webpackChunkName: "InstalledIntegrations" */ 'pages/IntegrationsModulePage' ), ); - -export const IntegrationsMarketPlace = Loadable( - // eslint-disable-next-line sonarjs/no-identical-functions - () => - import( - /* webpackChunkName: "IntegrationsMarketPlace" */ 'pages/IntegrationsModulePage' - ), -); diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index 360c74d8dafe..fed77f186ef2 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -15,7 +15,6 @@ import { ErrorDetails, IngestionSettings, InstalledIntegrations, - IntegrationsMarketPlace, LicensePage, ListAllALertsPage, LiveLogs, @@ -338,18 +337,11 @@ const routes: AppRoutes[] = [ key: 'SHORTCUTS', }, { - path: ROUTES.INTEGRATIONS_INSTALLED, + path: ROUTES.INTEGRATIONS, exact: true, component: InstalledIntegrations, isPrivate: true, - key: 'INTEGRATIONS_INSTALLED', - }, - { - path: ROUTES.INTEGRATIONS_MARKETPLACE, - exact: true, - component: IntegrationsMarketPlace, - isPrivate: true, - key: 'INTEGRATIONS_MARKETPLACE', + key: 'INTEGRATIONS', }, ]; diff --git a/frontend/src/api/ErrorResponseHandler.ts b/frontend/src/api/ErrorResponseHandler.ts index 3f28ff418dbe..027418ec8457 100644 --- a/frontend/src/api/ErrorResponseHandler.ts +++ b/frontend/src/api/ErrorResponseHandler.ts @@ -30,7 +30,8 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse { statusCode, payload: null, error: errorMessage, - message: null, + message: (response.data as any)?.status, + body: JSON.stringify((response.data as any).data), }; } diff --git a/frontend/src/api/SAML/listAllDomain.ts b/frontend/src/api/SAML/listAllDomain.ts index dea73e4311e6..41620f7d3e50 100644 --- a/frontend/src/api/SAML/listAllDomain.ts +++ b/frontend/src/api/SAML/listAllDomain.ts @@ -8,7 +8,7 @@ const listAllDomain = async ( props: Props, ): Promise | ErrorResponse> => { try { - const response = await axios.get(`orgs/${props.orgId}/domains`); + const response = await axios.get(`/orgs/${props.orgId}/domains`); return { statusCode: 200, diff --git a/frontend/src/api/channels/createEmail.ts b/frontend/src/api/channels/createEmail.ts index cde74b9c6d1c..7d0910d40f43 100644 --- a/frontend/src/api/channels/createEmail.ts +++ b/frontend/src/api/channels/createEmail.ts @@ -12,7 +12,7 @@ const create = async ( name: props.name, email_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, to: props.to, html: props.html, headers: props.headers, diff --git a/frontend/src/api/channels/createMsTeams.ts b/frontend/src/api/channels/createMsTeams.ts index 9e06e275a00c..ef9d309a9786 100644 --- a/frontend/src/api/channels/createMsTeams.ts +++ b/frontend/src/api/channels/createMsTeams.ts @@ -12,7 +12,7 @@ const create = async ( name: props.name, msteams_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, webhook_url: props.webhook_url, title: props.title, text: props.text, diff --git a/frontend/src/api/channels/createPager.ts b/frontend/src/api/channels/createPager.ts index 2747768cf12b..682874f7b48c 100644 --- a/frontend/src/api/channels/createPager.ts +++ b/frontend/src/api/channels/createPager.ts @@ -12,7 +12,7 @@ const create = async ( name: props.name, pagerduty_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, routing_key: props.routing_key, client: props.client, client_url: props.client_url, diff --git a/frontend/src/api/channels/createSlack.ts b/frontend/src/api/channels/createSlack.ts index f9e430fbc9c3..d68beddc9b57 100644 --- a/frontend/src/api/channels/createSlack.ts +++ b/frontend/src/api/channels/createSlack.ts @@ -12,7 +12,7 @@ const create = async ( name: props.name, slack_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, api_url: props.api_url, channel: props.channel, title: props.title, diff --git a/frontend/src/api/channels/createWebhook.ts b/frontend/src/api/channels/createWebhook.ts index 9c3c52c943b8..67a0de7a7b94 100644 --- a/frontend/src/api/channels/createWebhook.ts +++ b/frontend/src/api/channels/createWebhook.ts @@ -30,7 +30,7 @@ const create = async ( name: props.name, webhook_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, url: props.api_url, http_config: httpConfig, }, diff --git a/frontend/src/api/channels/editEmail.ts b/frontend/src/api/channels/editEmail.ts index f20e5eb8f90e..b80fe687a9a9 100644 --- a/frontend/src/api/channels/editEmail.ts +++ b/frontend/src/api/channels/editEmail.ts @@ -12,7 +12,7 @@ const editEmail = async ( name: props.name, email_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, to: props.to, html: props.html, headers: props.headers, diff --git a/frontend/src/api/channels/editMsTeams.ts b/frontend/src/api/channels/editMsTeams.ts index ee6bd309c119..293688f6c2a2 100644 --- a/frontend/src/api/channels/editMsTeams.ts +++ b/frontend/src/api/channels/editMsTeams.ts @@ -12,7 +12,7 @@ const editMsTeams = async ( name: props.name, msteams_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, webhook_url: props.webhook_url, title: props.title, text: props.text, diff --git a/frontend/src/api/channels/editOpsgenie.ts b/frontend/src/api/channels/editOpsgenie.ts index 71f830f9f867..1eb65c7adddd 100644 --- a/frontend/src/api/channels/editOpsgenie.ts +++ b/frontend/src/api/channels/editOpsgenie.ts @@ -12,7 +12,7 @@ const editOpsgenie = async ( name: props.name, opsgenie_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, api_key: props.api_key, description: props.description, priority: props.priority, diff --git a/frontend/src/api/channels/editPager.ts b/frontend/src/api/channels/editPager.ts index a31d73dcdbfa..091d42b640e5 100644 --- a/frontend/src/api/channels/editPager.ts +++ b/frontend/src/api/channels/editPager.ts @@ -12,7 +12,7 @@ const editPager = async ( name: props.name, pagerduty_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, routing_key: props.routing_key, client: props.client, client_url: props.client_url, diff --git a/frontend/src/api/channels/editSlack.ts b/frontend/src/api/channels/editSlack.ts index 9a34f41318fc..639646452cc1 100644 --- a/frontend/src/api/channels/editSlack.ts +++ b/frontend/src/api/channels/editSlack.ts @@ -12,7 +12,7 @@ const editSlack = async ( name: props.name, slack_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, api_url: props.api_url, channel: props.channel, title: props.title, diff --git a/frontend/src/api/channels/editWebhook.ts b/frontend/src/api/channels/editWebhook.ts index a574633e4e21..a96850c2db2c 100644 --- a/frontend/src/api/channels/editWebhook.ts +++ b/frontend/src/api/channels/editWebhook.ts @@ -29,7 +29,7 @@ const editWebhook = async ( name: props.name, webhook_configs: [ { - send_resolved: true, + send_resolved: props.send_resolved, url: props.api_url, http_config: httpConfig, }, diff --git a/frontend/src/api/common/logEvent.ts b/frontend/src/api/common/logEvent.ts new file mode 100644 index 000000000000..212d382d7765 --- /dev/null +++ b/frontend/src/api/common/logEvent.ts @@ -0,0 +1,28 @@ +import axios from 'api'; +import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; +import { AxiosError } from 'axios'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { EventSuccessPayloadProps } from 'types/api/events/types'; + +const logEvent = async ( + eventName: string, + attributes: Record, +): Promise | ErrorResponse> => { + try { + const response = await axios.post('/event', { + eventName, + attributes, + }); + + return { + statusCode: 200, + error: null, + message: response.data.status, + payload: response.data.data, + }; + } catch (error) { + return ErrorResponseHandler(error as AxiosError); + } +}; + +export default logEvent; diff --git a/frontend/src/api/metrics/ApDex/getMetricMeta.ts b/frontend/src/api/metrics/ApDex/getMetricMeta.ts index e3045730a73c..90baa61cd81a 100644 --- a/frontend/src/api/metrics/ApDex/getMetricMeta.ts +++ b/frontend/src/api/metrics/ApDex/getMetricMeta.ts @@ -1,4 +1,4 @@ -import axios from 'api'; +import { ApiV4Instance } from 'api'; import { AxiosResponse } from 'axios'; import { MetricMetaProps } from 'types/api/metrics/getApDex'; @@ -6,4 +6,6 @@ export const getMetricMeta = ( metricName: string, servicename: string, ): Promise> => - axios.get(`/metric_meta?metricName=${metricName}&serviceName=${servicename}`); + ApiV4Instance.get( + `/metric/metric_metadata?metricName=${metricName}&serviceName=${servicename}`, + ); diff --git a/frontend/src/api/metrics/getMetricName.ts b/frontend/src/api/metrics/getMetricName.ts deleted file mode 100644 index f3bff5a921ea..000000000000 --- a/frontend/src/api/metrics/getMetricName.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ApiV2Instance as axios } from 'api'; -import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; -import { AxiosError } from 'axios'; -import { ErrorResponse, SuccessResponse } from 'types/api'; -import { - MetricNameProps, - MetricNamesPayloadProps, -} from 'types/api/metrics/getMetricName'; - -export const getMetricName = async ( - props: MetricNameProps, -): Promise | ErrorResponse> => { - try { - const response = await axios.get( - `/metrics/autocomplete/list?match=${props || ''}`, - ); - - return { - statusCode: 200, - error: null, - message: response.data.status, - payload: response.data, - }; - } catch (error) { - return ErrorResponseHandler(error as AxiosError); - } -}; diff --git a/frontend/src/api/metrics/getResourceAttributes.ts b/frontend/src/api/metrics/getResourceAttributes.ts index 66524bf8f788..c482f863aedc 100644 --- a/frontend/src/api/metrics/getResourceAttributes.ts +++ b/frontend/src/api/metrics/getResourceAttributes.ts @@ -1,6 +1,7 @@ -import { ApiV2Instance as axios } from 'api'; +import { ApiV3Instance as axios } from 'api'; import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { AxiosError } from 'axios'; +import createQueryParams from 'lib/createQueryParams'; import { ErrorResponse, SuccessResponse } from 'types/api'; import { TagKeyProps, @@ -8,15 +9,19 @@ import { TagValueProps, TagValuesPayloadProps, } from 'types/api/metrics/getResourceAttributes'; +import { DataSource, MetricAggregateOperator } from 'types/common/queryBuilder'; export const getResourceAttributesTagKeys = async ( props: TagKeyProps, ): Promise | ErrorResponse> => { try { const response = await axios.get( - `/metrics/autocomplete/tagKey?metricName=${props.metricName}${ - props.match ? `&match=${props.match}` : '' - }`, + `/autocomplete/attribute_keys?${createQueryParams({ + aggregateOperator: MetricAggregateOperator.RATE, + searchText: props.match, + dataSource: DataSource.METRICS, + aggregateAttribute: props.metricName, + })}`, ); return { @@ -35,7 +40,13 @@ export const getResourceAttributesTagValues = async ( ): Promise | ErrorResponse> => { try { const response = await axios.get( - `/metrics/autocomplete/tagValue?metricName=${props.metricName}&tagKey=${props.tagKey}`, + `/autocomplete/attribute_values?${createQueryParams({ + aggregateOperator: MetricAggregateOperator.RATE, + dataSource: DataSource.METRICS, + aggregateAttribute: props.metricName, + attributeKey: props.tagKey, + searchText: '', + })}`, ); return { diff --git a/frontend/src/api/queryBuilder/getAggregateAttribute.ts b/frontend/src/api/queryBuilder/getAggregateAttribute.ts index e493bb460ae9..f13c3da4a891 100644 --- a/frontend/src/api/queryBuilder/getAggregateAttribute.ts +++ b/frontend/src/api/queryBuilder/getAggregateAttribute.ts @@ -24,7 +24,7 @@ export const getAggregateAttribute = async ({ const response: AxiosResponse<{ data: IQueryAutocompleteResponse; }> = await ApiV3Instance.get( - `autocomplete/aggregate_attributes?${createQueryParams({ + `/autocomplete/aggregate_attributes?${createQueryParams({ aggregateOperator, searchText, dataSource, diff --git a/frontend/src/api/queryBuilder/getAttributeKeys.ts b/frontend/src/api/queryBuilder/getAttributeKeys.ts index 99edc630c825..9cc127bb716e 100644 --- a/frontend/src/api/queryBuilder/getAttributeKeys.ts +++ b/frontend/src/api/queryBuilder/getAttributeKeys.ts @@ -25,7 +25,7 @@ export const getAggregateKeys = async ({ const response: AxiosResponse<{ data: IQueryAutocompleteResponse; }> = await ApiV3Instance.get( - `autocomplete/attribute_keys?${createQueryParams({ + `/autocomplete/attribute_keys?${createQueryParams({ aggregateOperator, searchText, dataSource, diff --git a/frontend/src/api/saveView/deleteView.ts b/frontend/src/api/saveView/deleteView.ts index e58e731d10a6..9317c8331ab9 100644 --- a/frontend/src/api/saveView/deleteView.ts +++ b/frontend/src/api/saveView/deleteView.ts @@ -2,4 +2,4 @@ import axios from 'api'; import { DeleteViewPayloadProps } from 'types/api/saveViews/types'; export const deleteView = (uuid: string): Promise => - axios.delete(`explorer/views/${uuid}`); + axios.delete(`/explorer/views/${uuid}`); diff --git a/frontend/src/api/saveView/getAllViews.ts b/frontend/src/api/saveView/getAllViews.ts index bdafb96b610b..4a54d6af0df4 100644 --- a/frontend/src/api/saveView/getAllViews.ts +++ b/frontend/src/api/saveView/getAllViews.ts @@ -6,4 +6,4 @@ import { DataSource } from 'types/common/queryBuilder'; export const getAllViews = ( sourcepage: DataSource, ): Promise> => - axios.get(`explorer/views?sourcePage=${sourcepage}`); + axios.get(`/explorer/views?sourcePage=${sourcepage}`); diff --git a/frontend/src/api/saveView/saveView.ts b/frontend/src/api/saveView/saveView.ts index a0c7ba5bf42a..60a552f0bb24 100644 --- a/frontend/src/api/saveView/saveView.ts +++ b/frontend/src/api/saveView/saveView.ts @@ -8,7 +8,7 @@ export const saveView = ({ viewName, extraData, }: SaveViewProps): Promise> => - axios.post('explorer/views', { + axios.post('/explorer/views', { name: viewName, sourcePage, compositeQuery, diff --git a/frontend/src/api/saveView/updateView.ts b/frontend/src/api/saveView/updateView.ts index 6ee745ffc2e7..b48b73f275a6 100644 --- a/frontend/src/api/saveView/updateView.ts +++ b/frontend/src/api/saveView/updateView.ts @@ -11,7 +11,7 @@ export const updateView = ({ sourcePage, viewKey, }: UpdateViewProps): Promise => - axios.put(`explorer/views/${viewKey}`, { + axios.put(`/explorer/views/${viewKey}`, { name: viewName, compositeQuery, extraData, diff --git a/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx b/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx index a29f0180b4e9..114db1792401 100644 --- a/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx +++ b/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx @@ -5,13 +5,14 @@ import './CustomTimePicker.styles.scss'; import { Input, Popover, Tooltip, Typography } from 'antd'; import cx from 'classnames'; import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal'; -import { Options } from 'container/TopNav/DateTimeSelection/config'; import { FixedDurationSuggestionOptions, + Options, RelativeDurationSuggestionOptions, } from 'container/TopNav/DateTimeSelectionV2/config'; import dayjs from 'dayjs'; -import { defaultTo, noop } from 'lodash-es'; +import { isValidTimeFormat } from 'lib/getMinMax'; +import { defaultTo, isFunction, noop } from 'lodash-es'; import debounce from 'lodash-es/debounce'; import { CheckCircle, ChevronDown, Clock } from 'lucide-react'; import { @@ -33,7 +34,14 @@ interface CustomTimePickerProps { onError: (value: boolean) => void; selectedValue: string; selectedTime: string; - onValidCustomDateChange: ([t1, t2]: any[]) => void; + onValidCustomDateChange: ({ + time: [t1, t2], + timeStr, + }: { + time: [dayjs.Dayjs | null, dayjs.Dayjs | null]; + timeStr: string; + }) => void; + onCustomTimeStatusUpdate?: (isValid: boolean) => void; open: boolean; setOpen: Dispatch>; items: any[]; @@ -53,6 +61,7 @@ function CustomTimePicker({ open, setOpen, onValidCustomDateChange, + onCustomTimeStatusUpdate, newPopover, customDateTimeVisible, setCustomDTPickerVisible, @@ -85,6 +94,7 @@ function CustomTimePicker({ return Options[index].label; } } + for ( let index = 0; index < RelativeDurationSuggestionOptions.length; @@ -94,12 +104,17 @@ function CustomTimePicker({ return RelativeDurationSuggestionOptions[index].label; } } + for (let index = 0; index < FixedDurationSuggestionOptions.length; index++) { if (FixedDurationSuggestionOptions[index].value === selectedTime) { return FixedDurationSuggestionOptions[index].label; } } + if (isValidTimeFormat(selectedTime)) { + return selectedTime; + } + return ''; }; @@ -161,13 +176,22 @@ function CustomTimePicker({ setInputStatus('error'); onError(true); setInputErrorMessage('Please enter time less than 6 months'); + if (isFunction(onCustomTimeStatusUpdate)) { + onCustomTimeStatusUpdate(true); + } } else { - onValidCustomDateChange([minTime, currentTime]); + onValidCustomDateChange({ + time: [minTime, currentTime], + timeStr: inputValue, + }); } } else { setInputStatus('error'); onError(true); setInputErrorMessage(null); + if (isFunction(onCustomTimeStatusUpdate)) { + onCustomTimeStatusUpdate(false); + } } }, 300); @@ -320,4 +344,5 @@ CustomTimePicker.defaultProps = { setCustomDTPickerVisible: noop, onCustomDateHandler: noop, handleGoLive: noop, + onCustomTimeStatusUpdate: noop, }; diff --git a/frontend/src/components/Loadable/index.tsx b/frontend/src/components/Loadable/index.tsx index 5cffc5793e72..e562b564924f 100644 --- a/frontend/src/components/Loadable/index.tsx +++ b/frontend/src/components/Loadable/index.tsx @@ -1,9 +1,10 @@ import { ComponentType, lazy, LazyExoticComponent } from 'react'; +import { lazyRetry } from 'utils/lazyWithRetries'; function Loadable(importPath: { (): LoadableProps; }): LazyExoticComponent { - return lazy(() => importPath()); + return lazy(() => lazyRetry(() => importPath())); } type LazyComponent = ComponentType>; diff --git a/frontend/src/components/TableRenderer/LabelColumn.tsx b/frontend/src/components/TableRenderer/LabelColumn.tsx index b7210d455785..d78d76f69e44 100644 --- a/frontend/src/components/TableRenderer/LabelColumn.tsx +++ b/frontend/src/components/TableRenderer/LabelColumn.tsx @@ -1,10 +1,10 @@ import './LabelColumn.styles.scss'; import { Popover, Tag } from 'antd'; -import { popupContainer } from 'utils/selectPopupContainer'; import { LabelColumnProps } from './TableRenderer.types'; import TagWithToolTip from './TagWithToolTip'; +import { getLabelAndValueContent } from './utils'; function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element { const newLabels = labels.length > 3 ? labels.slice(0, 3) : labels; @@ -19,19 +19,17 @@ function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element { )} {remainingLabels.length > 0 && ( {labels.map( (label: string): JSX.Element => ( - +
+ + {getLabelAndValueContent(label, value && value[label])} + +
), )} diff --git a/frontend/src/components/TableRenderer/utils.ts b/frontend/src/components/TableRenderer/utils.ts index ebceffe4360e..ef5ec104a263 100644 --- a/frontend/src/components/TableRenderer/utils.ts +++ b/frontend/src/components/TableRenderer/utils.ts @@ -38,6 +38,16 @@ export const getLabelRenderingValue = ( return label; }; +export const getLabelAndValueContent = ( + label: string, + value?: string, +): string => { + if (value) { + return `${label}: ${value}`; + } + return `${label}`; +}; + interface GeneratorResizeTableColumnsProp { baseColumnOptions: ColumnsType; dynamicColumnOption: { key: string; columnOption: ColumnType }[]; diff --git a/frontend/src/constants/localStorage.ts b/frontend/src/constants/localStorage.ts index 0ba6cac30212..85f46ab8924c 100644 --- a/frontend/src/constants/localStorage.ts +++ b/frontend/src/constants/localStorage.ts @@ -17,4 +17,5 @@ export enum LOCALSTORAGE { IS_IDENTIFIED_USER = 'IS_IDENTIFIED_USER', DASHBOARD_VARIABLES = 'DASHBOARD_VARIABLES', SHOW_EXPLORER_TOOLBAR = 'SHOW_EXPLORER_TOOLBAR', + PINNED_ATTRIBUTES = 'PINNED_ATTRIBUTES', } diff --git a/frontend/src/constants/panelTypes.ts b/frontend/src/constants/panelTypes.ts index c6db5db2dadd..c76380fff1ec 100644 --- a/frontend/src/constants/panelTypes.ts +++ b/frontend/src/constants/panelTypes.ts @@ -29,6 +29,7 @@ export const getComponentForPanelType = ( [PANEL_TYPES.LIST]: dataSource === DataSource.LOGS ? LogsPanelComponent : TracesTableComponent, [PANEL_TYPES.BAR]: Uplot, + [PANEL_TYPES.PIE]: null, [PANEL_TYPES.EMPTY_WIDGET]: null, }; diff --git a/frontend/src/constants/query.ts b/frontend/src/constants/query.ts index 31ec5fcd20a4..6b70ae9786f1 100644 --- a/frontend/src/constants/query.ts +++ b/frontend/src/constants/query.ts @@ -29,4 +29,5 @@ export enum QueryParams { expandedWidgetId = 'expandedWidgetId', integration = 'integration', pagination = 'pagination', + relativeTime = 'relativeTime', } diff --git a/frontend/src/constants/queryBuilder.ts b/frontend/src/constants/queryBuilder.ts index 0999b634baa6..c1603e02e5f1 100644 --- a/frontend/src/constants/queryBuilder.ts +++ b/frontend/src/constants/queryBuilder.ts @@ -285,6 +285,7 @@ export enum PANEL_TYPES { LIST = 'list', TRACE = 'trace', BAR = 'bar', + PIE = 'pie', EMPTY_WIDGET = 'EMPTY_WIDGET', } diff --git a/frontend/src/constants/queryFunctionOptions.ts b/frontend/src/constants/queryFunctionOptions.ts index b79f673c46c0..4aa6332d67bd 100644 --- a/frontend/src/constants/queryFunctionOptions.ts +++ b/frontend/src/constants/queryFunctionOptions.ts @@ -2,7 +2,7 @@ import { QueryFunctionsTypes } from 'types/common/queryBuilder'; import { SelectOption } from 'types/common/select'; -export const queryFunctionOptions: SelectOption[] = [ +export const metricQueryFunctionOptions: SelectOption[] = [ { value: QueryFunctionsTypes.CUTOFF_MIN, label: 'Cut Off Min', @@ -65,6 +65,12 @@ export const queryFunctionOptions: SelectOption[] = [ }, ]; +export const logsQueryFunctionOptions: SelectOption[] = [ + { + value: QueryFunctionsTypes.TIME_SHIFT, + label: 'Time Shift', + }, +]; interface QueryFunctionConfigType { [key: string]: { showInput: boolean; diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index 0b087ff8cd88..cbeb672a5cff 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -51,9 +51,7 @@ const ROUTES = { TRACES_SAVE_VIEWS: '/traces/saved-views', WORKSPACE_LOCKED: '/workspace-locked', SHORTCUTS: '/shortcuts', - INTEGRATIONS_BASE: '/integrations', - INTEGRATIONS_INSTALLED: '/integrations/installed', - INTEGRATIONS_MARKETPLACE: '/integrations/marketplace', + INTEGRATIONS: '/integrations', } as const; export default ROUTES; diff --git a/frontend/src/constants/sessionStorage.ts b/frontend/src/constants/sessionStorage.ts new file mode 100644 index 000000000000..fd24322d06f8 --- /dev/null +++ b/frontend/src/constants/sessionStorage.ts @@ -0,0 +1,3 @@ +export enum SESSIONSTORAGE { + RETRY_LAZY_REFRESHED = 'retry-lazy-refreshed', +} diff --git a/frontend/src/constants/shortcuts/DashboardShortcuts.ts b/frontend/src/constants/shortcuts/DashboardShortcuts.ts index ee861708f751..aaa81cb3c16e 100644 --- a/frontend/src/constants/shortcuts/DashboardShortcuts.ts +++ b/frontend/src/constants/shortcuts/DashboardShortcuts.ts @@ -9,9 +9,10 @@ export const DashboardShortcuts = { export const DashboardShortcutsName = { SaveChanges: `${userOS === UserOperatingSystem.MACOS ? 'cmd' : 'ctrl'}+s`, + DiscardChanges: `${userOS === UserOperatingSystem.MACOS ? 'cmd' : 'ctrl'}+d`, }; export const DashboardShortcutsDescription = { - SaveChanges: 'Save Changes', - DiscardChanges: 'Discard Changes', + SaveChanges: 'Save Changes for panel', + DiscardChanges: 'Discard Changes for panel', }; diff --git a/frontend/src/constants/shortcuts/QBShortcuts.ts b/frontend/src/constants/shortcuts/QBShortcuts.ts index 56fea081df6d..d1d841595abf 100644 --- a/frontend/src/constants/shortcuts/QBShortcuts.ts +++ b/frontend/src/constants/shortcuts/QBShortcuts.ts @@ -13,5 +13,5 @@ export const QBShortcutsName = { }; export const QBShortcutsDescription = { - StageAndRunQuery: 'Stage and Run the query', + StageAndRunQuery: 'Stage and Run the current query', }; diff --git a/frontend/src/container/AppLayout/AppLayout.styles.scss b/frontend/src/container/AppLayout/AppLayout.styles.scss index 21dc54fb980b..6a0b223edf0f 100644 --- a/frontend/src/container/AppLayout/AppLayout.styles.scss +++ b/frontend/src/container/AppLayout/AppLayout.styles.scss @@ -4,8 +4,9 @@ width: 100%; .app-content { - width: 100%; + width: calc(100% - 64px); overflow: auto; + z-index: 0; .content-container { position: relative; @@ -16,6 +17,12 @@ width: 100%; } } + + &.docked { + .app-content { + width: calc(100% - 240px); + } + } } .isDarkMode { diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx index 5d18e7d30737..901e2b36d8b1 100644 --- a/frontend/src/container/AppLayout/index.tsx +++ b/frontend/src/container/AppLayout/index.tsx @@ -311,7 +311,13 @@ function AppLayout(props: AppLayoutProps): JSX.Element { )} - + {isToDisplayLayout && !renderFullScreen && ( { const timestamps: number[] = []; data?.details?.breakdown?.forEach((breakdown: any) => { - breakdown?.dayWiseBreakdown?.breakdown.forEach((entry: any) => { + breakdown?.dayWiseBreakdown?.breakdown?.forEach((entry: any) => { timestamps.push(entry?.timestamp); }); }); diff --git a/frontend/src/container/ConfigDropdown/Config/index.tsx b/frontend/src/container/ConfigDropdown/Config/index.tsx index 52879ce2d71d..94ad32286011 100644 --- a/frontend/src/container/ConfigDropdown/Config/index.tsx +++ b/frontend/src/container/ConfigDropdown/Config/index.tsx @@ -3,6 +3,7 @@ import Spinner from 'components/Spinner'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { lazy, Suspense, useMemo } from 'react'; import { ConfigProps } from 'types/api/dynamicConfigs/getDynamicConfigs'; +import { lazyRetry } from 'utils/lazyWithRetries'; import ErrorLink from './ErrorLink'; import LinkContainer from './Link'; @@ -17,8 +18,9 @@ function HelpToolTip({ config }: HelpToolTipProps): JSX.Element { const items = sortedConfig.map((item) => { const iconName = `${isDarkMode ? item.darkIcon : item.lightIcon}`; - const Component = lazy( - () => import(`@ant-design/icons/es/icons/${iconName}.js`), + + const Component = lazy(() => + lazyRetry(() => import(`@ant-design/icons/es/icons/${iconName}.js`)), ); return { key: item.text + item.href, diff --git a/frontend/src/container/CreateAlertChannels/index.tsx b/frontend/src/container/CreateAlertChannels/index.tsx index 51a0b6214e42..c0eec3ecdd4c 100644 --- a/frontend/src/container/CreateAlertChannels/index.tsx +++ b/frontend/src/container/CreateAlertChannels/index.tsx @@ -53,6 +53,7 @@ function CreateAlertChannels({ EmailChannel > >({ + send_resolved: true, text: `{{ range .Alerts -}} *Alert:* {{ .Labels.alertname }}{{ if .Labels.severity }} - {{ .Labels.severity }}{{ end }} @@ -119,7 +120,7 @@ function CreateAlertChannels({ api_url: selectedConfig?.api_url || '', channel: selectedConfig?.channel || '', name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, text: selectedConfig?.text || '', title: selectedConfig?.title || '', }), @@ -158,7 +159,7 @@ function CreateAlertChannels({ let request: WebhookChannel = { api_url: selectedConfig?.api_url || '', name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, }; if (selectedConfig?.username !== '' || selectedConfig?.password !== '') { @@ -226,7 +227,7 @@ function CreateAlertChannels({ return { name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, routing_key: selectedConfig?.routing_key || '', client: selectedConfig?.client || '', client_url: selectedConfig?.client_url || '', @@ -274,7 +275,7 @@ function CreateAlertChannels({ () => ({ api_key: selectedConfig?.api_key || '', name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, description: selectedConfig?.description || '', message: selectedConfig?.message || '', priority: selectedConfig?.priority || '', @@ -312,7 +313,7 @@ function CreateAlertChannels({ const prepareEmailRequest = useCallback( () => ({ name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, to: selectedConfig?.to || '', html: selectedConfig?.html || '', headers: selectedConfig?.headers || {}, @@ -350,7 +351,7 @@ function CreateAlertChannels({ () => ({ webhook_url: selectedConfig?.webhook_url || '', name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, text: selectedConfig?.text || '', title: selectedConfig?.title || '', }), diff --git a/frontend/src/container/EditAlertChannels/index.tsx b/frontend/src/container/EditAlertChannels/index.tsx index 29d7816d90dd..3c2e956f141a 100644 --- a/frontend/src/container/EditAlertChannels/index.tsx +++ b/frontend/src/container/EditAlertChannels/index.tsx @@ -72,7 +72,7 @@ function EditAlertChannels({ api_url: selectedConfig?.api_url || '', channel: selectedConfig?.channel || '', name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, text: selectedConfig?.text || '', title: selectedConfig?.title || '', id, @@ -115,7 +115,7 @@ function EditAlertChannels({ return { api_url: selectedConfig?.api_url || '', name: name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, username, password, id, @@ -284,7 +284,7 @@ function EditAlertChannels({ () => ({ webhook_url: selectedConfig?.webhook_url || '', name: selectedConfig?.name || '', - send_resolved: true, + send_resolved: selectedConfig?.send_resolved || false, text: selectedConfig?.text || '', title: selectedConfig?.title || '', id, diff --git a/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss b/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss index cddeb356b895..7f6ac6a4dd94 100644 --- a/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss +++ b/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss @@ -1,10 +1,10 @@ .hide-update { - left: calc(50% - 41px) !important; + left: calc(50% - 72px) !important; } .explorer-update { position: fixed; bottom: 24px; - left: calc(50% - 250px); + left: calc(50% - 352px); display: flex; align-items: center; gap: 12px; @@ -37,7 +37,6 @@ } } - .explorer-options { position: fixed; bottom: 24px; @@ -78,11 +77,9 @@ display: flex; justify-content: center; align-items: center; - gap: 8px; + border: none; border: 1px solid #1d2023; - color: #c0c1c3; - background-color: #161922; box-shadow: none !important; diff --git a/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx b/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx index 635d085e1e91..0e9fd3704bdc 100644 --- a/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx +++ b/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx @@ -373,34 +373,42 @@ function ExplorerOptions({ onClick={handleSaveViewModalToggle} className={isEditDeleteSupported ? '' : 'hidden'} disabled={viewsIsLoading || isRefetching} + icon={} > - Save this view + Save this view
- + + + +
+
+ - - - - - - - - + onClick={hideToolbar} + icon={} + />
@@ -413,6 +421,7 @@ function ExplorerOptions({ isQueryUpdated={isQueryUpdated} handleClearSelect={handleClearSelect} onUpdateQueryHandler={onUpdateQueryHandler} + isEditDeleteSupported={isEditDeleteSupported} /> >; handleClearSelect: () => void; onUpdateQueryHandler: () => void; + isEditDeleteSupported: boolean; } function ExplorerOptionsHideArea({ @@ -25,6 +26,7 @@ function ExplorerOptionsHideArea({ setIsExplorerOptionHidden, handleClearSelect, onUpdateQueryHandler, + isEditDeleteSupported, }: DroppableAreaProps): JSX.Element { const handleShowExplorerOption = (): void => { if (setIsExplorerOptionHidden) { @@ -47,14 +49,16 @@ function ExplorerOptionsHideArea({ icon={} /> - - + + + + - )} + ); } diff --git a/frontend/src/container/OnboardingContainer/Steps/EnvironmentDetails/EnvironmentDetails.tsx b/frontend/src/container/OnboardingContainer/Steps/EnvironmentDetails/EnvironmentDetails.tsx index f4f8381de774..60ecf403bfee 100644 --- a/frontend/src/container/OnboardingContainer/Steps/EnvironmentDetails/EnvironmentDetails.tsx +++ b/frontend/src/container/OnboardingContainer/Steps/EnvironmentDetails/EnvironmentDetails.tsx @@ -1,8 +1,13 @@ -import { Card, Typography } from 'antd'; +import { LoadingOutlined } from '@ant-design/icons'; +import { Button, Card, Form, Input, Space, Typography } from 'antd'; +import logEvent from 'api/common/logEvent'; import cx from 'classnames'; import { useOnboardingContext } from 'container/OnboardingContainer/context/OnboardingContext'; import { useCases } from 'container/OnboardingContainer/OnboardingContainer'; -import { Server } from 'lucide-react'; +import { useNotifications } from 'hooks/useNotifications'; +import { Check, Server } from 'lucide-react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; interface SupportedEnvironmentsProps { name: string; @@ -30,19 +35,85 @@ const supportedEnvironments: SupportedEnvironmentsProps[] = [ name: 'MacOS ARM64', id: 'macOsARM64', }, + { + name: 'Docker', + id: 'docker', + }, ]; export default function EnvironmentDetails(): JSX.Element { + const [form] = Form.useForm(); + const { t } = useTranslation(['common']); + const { selectedEnvironment, updateSelectedEnvironment, selectedModule, + selectedDataSource, + selectedFramework, errorDetails, updateErrorDetails, } = useOnboardingContext(); + const requestedEnvironmentName = Form.useWatch( + 'requestedEnvironmentName', + form, + ); + + const { notifications } = useNotifications(); + + const [ + isSubmittingRequestForEnvironment, + setIsSubmittingRequestForEnvironment, + ] = useState(false); + + const handleRequestedEnvironmentSubmit = async (): Promise => { + try { + setIsSubmittingRequestForEnvironment(true); + const response = await logEvent('Onboarding V2: Environment Requested', { + module: selectedModule?.id, + dataSource: selectedDataSource?.id, + framework: selectedFramework, + environment: requestedEnvironmentName, + }); + + if (response.statusCode === 200) { + notifications.success({ + message: 'Environment Request Submitted', + }); + + form.setFieldValue('requestedEnvironmentName', ''); + + setIsSubmittingRequestForEnvironment(false); + } else { + notifications.error({ + message: + response.error || + t('something_went_wrong', { + ns: 'common', + }), + }); + + setIsSubmittingRequestForEnvironment(false); + } + } catch (error) { + notifications.error({ + message: t('something_went_wrong', { + ns: 'common', + }), + }); + + setIsSubmittingRequestForEnvironment(false); + } + }; + return ( - <> +
* Select Environment @@ -55,6 +126,12 @@ export default function EnvironmentDetails(): JSX.Element { ) { return null; } + if ( + selectedModule?.id !== useCases.APM.id && + environment.id === 'docker' + ) { + return null; + } return ( +
+ + Cannot find what you’re looking for? Request an environment + + +
+ + + + + + +
+
+ {errorDetails && (
{errorDetails}
)} - + ); } diff --git a/frontend/src/container/OnboardingContainer/Steps/MarkdownStep/MarkdownStep.tsx b/frontend/src/container/OnboardingContainer/Steps/MarkdownStep/MarkdownStep.tsx index 36b07cd191b3..ce38786deee7 100644 --- a/frontend/src/container/OnboardingContainer/Steps/MarkdownStep/MarkdownStep.tsx +++ b/frontend/src/container/OnboardingContainer/Steps/MarkdownStep/MarkdownStep.tsx @@ -84,6 +84,7 @@ export default function MarkdownStep(): JSX.Element { SIGNOZ_INGESTION_KEY: ingestionData?.SIGNOZ_INGESTION_KEY || '', REGION: ingestionData?.REGION || 'region', + OTEL_VERSION: '0.88.0', }; return ( diff --git a/frontend/src/container/OnboardingContainer/common/ModuleStepsContainer/ModuleStepsContainer.tsx b/frontend/src/container/OnboardingContainer/common/ModuleStepsContainer/ModuleStepsContainer.tsx index 272d2b5083e5..91df3591c4c5 100644 --- a/frontend/src/container/OnboardingContainer/common/ModuleStepsContainer/ModuleStepsContainer.tsx +++ b/frontend/src/container/OnboardingContainer/common/ModuleStepsContainer/ModuleStepsContainer.tsx @@ -16,7 +16,8 @@ import { DataSourceType } from 'container/OnboardingContainer/Steps/DataSource/D import { hasFrameworks } from 'container/OnboardingContainer/utils/dataSourceUtils'; import useAnalytics from 'hooks/analytics/useAnalytics'; import history from 'lib/history'; -import { isEmpty } from 'lodash-es'; +import { isEmpty, isNull } from 'lodash-es'; +import { HelpCircle } from 'lucide-react'; import { useState } from 'react'; import { useOnboardingContext } from '../../context/OnboardingContext'; @@ -91,7 +92,10 @@ export default function ModuleStepsContainer({ name: selectedDataSourceName = '', } = selectedDataSource as DataSourceType; - if (step.id === environmentDetailsStep && selectedEnvironment === '') { + if ( + step.id === environmentDetailsStep && + (selectedEnvironment === '' || isNull(selectedEnvironment)) + ) { updateErrorDetails('Please select environment'); return false; } @@ -376,6 +380,30 @@ export default function ModuleStepsContainer({ history.push('/'); }; + const handleFacingIssuesClick = (): void => { + trackEvent('Onboarding V2: Facing Issues Sending Data to SigNoz', { + dataSource: selectedDataSource?.id, + framework: selectedFramework, + environment: selectedEnvironment, + module: activeStep?.module?.id, + }); + + const message = `Hi Team, + +I am facing issues sending data to SigNoz. Here are my application details + +Data Source: ${selectedDataSource?.name} +Framework: +Environment: +Module: ${activeStep?.module?.id} + +Thanks +`; + if (window.Intercom) { + window.Intercom('showNewMessage', message); + } + }; + return (
@@ -452,6 +480,15 @@ export default function ModuleStepsContainer({ + +
diff --git a/frontend/src/container/OnboardingContainer/constants/apmDocFilePaths.ts b/frontend/src/container/OnboardingContainer/constants/apmDocFilePaths.ts index 485a33382c10..f88f39518f40 100644 --- a/frontend/src/container/OnboardingContainer/constants/apmDocFilePaths.ts +++ b/frontend/src/container/OnboardingContainer/constants/apmDocFilePaths.ts @@ -9,6 +9,13 @@ // Go-Kubernetes /// /// ROR Done /// /// .NET Start +// dotnet Docker +import APM_dotnet_docker_quickStart_instrumentApplication from '../Modules/APM/Dotnet/md-docs/Docker/QuickStart/dotnet-docker-quickStart-instrumentApplication.md'; +import APM_dotnet_docker_quickStart_runApplication from '../Modules/APM/Dotnet/md-docs/Docker/QuickStart/dotnet-docker-quickStart-runApplication.md'; +// dotnet-LinuxAMD64-recommended +import APM_dotnet_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Dotnet/md-docs/Docker/Recommended/dotnet-docker-recommended-installOtelCollector.md'; +import APM_dotnet_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Dotnet/md-docs/Docker/Recommended/dotnet-docker-recommended-instrumentApplication.md'; +import APM_dotnet_docker_recommendedSteps_runApplication from '../Modules/APM/Dotnet/md-docs/Docker/Recommended/dotnet-docker-recommended-runApplication.md'; // dotnet-Kubernetes import APM_dotnet_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Dotnet/md-docs/Kubernetes/dotnet-kubernetes-installOtelCollector.md'; import APM_dotnet_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Dotnet/md-docs/Kubernetes/dotnet-kubernetes-instrumentApplication.md'; @@ -41,6 +48,13 @@ import APM_dotnet_macOsARM64_quickStart_runApplication from '../Modules/APM/Dotn import APM_dotnet_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/Dotnet/md-docs/MacOsARM64/Recommended/dotnet-macosarm64-recommended-installOtelCollector.md'; import APM_dotnet_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Dotnet/md-docs/MacOsARM64/Recommended/dotnet-macosarm64-recommended-instrumentApplication.md'; import APM_dotnet_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Dotnet/md-docs/MacOsARM64/Recommended/dotnet-macosarm64-recommended-runApplication.md'; +// Elixir Docker +import APM_elixir_docker_quickStart_instrumentApplication from '../Modules/APM/Elixir/md-docs/Docker/QuickStart/elixir-docker-quickStart-instrumentApplication.md'; +import APM_elixir_docker_quickStart_runApplication from '../Modules/APM/Elixir/md-docs/Docker/QuickStart/elixir-docker-quickStart-runApplication.md'; +// Elixir-LinuxAMD64-recommended +import APM_elixir_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Elixir/md-docs/Docker/Recommended/elixir-docker-recommended-installOtelCollector.md'; +import APM_elixir_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Elixir/md-docs/Docker/Recommended/elixir-docker-recommended-instrumentApplication.md'; +import APM_elixir_docker_recommendedSteps_runApplication from '../Modules/APM/Elixir/md-docs/Docker/Recommended/elixir-docker-recommended-runApplication.md'; // Elixir-Kubernetes import APM_elixir_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Elixir/md-docs/Kubernetes/elixir-kubernetes-installOtelCollector.md'; import APM_elixir_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Elixir/md-docs/Kubernetes/elixir-kubernetes-instrumentApplication.md'; @@ -73,6 +87,14 @@ import APM_elixir_macOsARM64_quickStart_runApplication from '../Modules/APM/Elix import APM_elixir_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/Elixir/md-docs/MacOsARM64/Recommended/elixir-macosarm64-recommended-installOtelCollector.md'; import APM_elixir_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Elixir/md-docs/MacOsARM64/Recommended/elixir-macosarm64-recommended-instrumentApplication.md'; import APM_elixir_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Elixir/md-docs/MacOsARM64/Recommended/elixir-macosarm64-recommended-runApplication.md'; +// Golang Docker +import APM_go_docker_quickStart_instrumentApplication from '../Modules/APM/GoLang/md-docs/Docker/QuickStart/golang-docker-quickStart-instrumentApplication.md'; +import APM_go_docker_quickStart_runApplication from '../Modules/APM/GoLang/md-docs/Docker/QuickStart/golang-docker-quickStart-runApplication.md'; +// Go-LinuxAMD64-recommended +import APM_go_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/GoLang/md-docs/Docker/Recommended/golang-docker-recommended-installOtelCollector.md'; +import APM_go_docker_recommendedSteps_instrumentApplication from '../Modules/APM/GoLang/md-docs/Docker/Recommended/golang-docker-recommended-instrumentApplication.md'; +import APM_go_docker_recommendedSteps_runApplication from '../Modules/APM/GoLang/md-docs/Docker/Recommended/golang-docker-recommended-runApplication.md'; +// Golang Kubernetes import APM_go_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/GoLang/md-docs/Kubernetes/golang-kubernetes-installOtelCollector.md'; import APM_go_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/GoLang/md-docs/Kubernetes/golang-kubernetes-instrumentApplication.md'; import APM_go_kubernetes_recommendedSteps_runApplication from '../Modules/APM/GoLang/md-docs/Kubernetes/golang-kubernetes-runApplication.md'; @@ -105,6 +127,13 @@ import APM_go_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/AP import APM_go_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/GoLang/md-docs/MacOsARM64/Recommended/golang-macosarm64-recommended-instrumentApplication.md'; import APM_go_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/GoLang/md-docs/MacOsARM64/Recommended/golang-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- +// JBoss DOcker +import APM_java_jboss_docker_quickStart_instrumentApplication from '../Modules/APM/Java/md-docs/Jboss/Docker/QuickStart/jboss-docker-quickStart-instrumentApplication.md'; +import APM_java_jboss_docker_quickStart_runApplication from '../Modules/APM/Java/md-docs/Jboss/Docker/QuickStart/jboss-docker-quickStart-runApplication.md'; +// Jboss-LinuxAMD64-recommended +import APM_java_jboss_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Jboss/Docker/Recommended/jboss-docker-recommended-installOtelCollector.md'; +import APM_java_jboss_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Jboss/Docker/Recommended/jboss-docker-recommended-instrumentApplication.md'; +import APM_java_jboss_docker_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/Jboss/Docker/Recommended/jboss-docker-recommended-runApplication.md'; // Jboss-Kubernetes import APM_java_jboss_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Jboss/Kubernetes/jboss-kubernetes-installOtelCollector.md'; import APM_java_jboss_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Jboss/Kubernetes/jboss-kubernetes-instrumentApplication.md'; @@ -138,6 +167,13 @@ import APM_java_jboss_macOsARM64_recommendedSteps_setupOtelCollector from '../Mo import APM_java_jboss_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Jboss/MacOsARM64/Recommended/jboss-macosarm64-recommended-instrumentApplication.md'; import APM_java_jboss_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/Jboss/MacOsARM64/Recommended/jboss-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- +// Other Docker +import APM_java_other_docker_quickStart_instrumentApplication from '../Modules/APM/Java/md-docs/Others/Docker/QuickStart/others-docker-quickStart-instrumentApplication.md'; +import APM_java_other_docker_quickStart_runApplication from '../Modules/APM/Java/md-docs/Others/Docker/QuickStart/others-docker-quickStart-runApplication.md'; +// Other-LinuxAMD64-recommended +import APM_java_other_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Others/Docker/Recommended/others-docker-recommended-installOtelCollector.md'; +import APM_java_other_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Others/Docker/Recommended/others-docker-recommended-instrumentApplication.md'; +import APM_java_other_docker_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/Others/Docker/Recommended/others-docker-recommended-runApplication.md'; // Other-Kubernetes import APM_java_other_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Others/Kubernetes/others-kubernetes-installOtelCollector.md'; import APM_java_other_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Others/Kubernetes/others-kubernetes-instrumentApplication.md'; @@ -170,6 +206,14 @@ import APM_java_other_macOsARM64_quickStart_runApplication from '../Modules/APM/ import APM_java_other_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Others/MacOsARM64/Recommended/others-macosarm64-recommended-installOtelCollector.md'; import APM_java_other_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Others/MacOsARM64/Recommended/others-macosarm64-recommended-instrumentApplication.md'; import APM_java_other_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/Others/MacOsARM64/Recommended/others-macosarm64-recommended-runApplication.md'; +// SpringBoot Docker +import APM_java_springBoot_docker_quickStart_instrumentApplication from '../Modules/APM/Java/md-docs/SpringBoot/Docker/QuickStart/springBoot-docker-quickStart-instrumentApplication.md'; +import APM_java_springBoot_docker_quickStart_runApplication from '../Modules/APM/Java/md-docs/SpringBoot/Docker/QuickStart/springBoot-docker-quickStart-runApplication.md'; +// SpringBoot-LinuxAMD64-recommended +import APM_java_springBoot_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/SpringBoot/Docker/Recommended/springBoot-docker-recommended-installOtelCollector.md'; +import APM_java_springBoot_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/SpringBoot/Docker/Recommended/springBoot-docker-recommended-instrumentApplication.md'; +import APM_java_springBoot_docker_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/SpringBoot/Docker/Recommended/springBoot-docker-recommended-runApplication.md'; +// SpringBoot-Kubernetes import APM_java_springBoot_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/SpringBoot/Kubernetes/springBoot-kubernetes-installOtelCollector.md'; import APM_java_springBoot_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/SpringBoot/Kubernetes/springBoot-kubernetes-instrumentApplication.md'; import APM_java_springBoot_kubernetes_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/SpringBoot/Kubernetes/springBoot-kubernetes-runApplication.md'; @@ -202,6 +246,13 @@ import APM_java_springBoot_macOsARM64_recommendedSteps_setupOtelCollector from ' import APM_java_springBoot_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/SpringBoot/MacOsARM64/Recommended/springBoot-macosarm64-recommended-instrumentApplication.md'; import APM_java_springBoot_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/SpringBoot/MacOsARM64/Recommended/springBoot-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- +// Tomcat Docker +import APM_java_tomcat_docker_quickStart_instrumentApplication from '../Modules/APM/Java/md-docs/Tomcat/Docker/QuickStart/tomcat-docker-quickStart-instrumentApplication.md'; +import APM_java_tomcat_docker_quickStart_runApplication from '../Modules/APM/Java/md-docs/Tomcat/Docker/QuickStart/tomcat-docker-quickStart-runApplication.md'; +// Tomcat-LinuxAMD64-recommended +import APM_java_tomcat_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Tomcat/Docker/Recommended/tomcat-docker-recommended-installOtelCollector.md'; +import APM_java_tomcat_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Tomcat/Docker/Recommended/tomcat-docker-recommended-instrumentApplication.md'; +import APM_java_tomcat_docker_recommendedSteps_runApplication from '../Modules/APM/Java/md-docs/Tomcat/Docker/Recommended/tomcat-docker-recommended-runApplication.md'; // Tomcat-Kubernetes import APM_java_tomcat_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Java/md-docs/Tomcat/Kubernetes/tomcat-kubernetes-installOtelCollector.md'; import APM_java_tomcat_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Java/md-docs/Tomcat/Kubernetes/tomcat-kubernetes-instrumentApplication.md'; @@ -238,6 +289,13 @@ import APM_java_tomcat_macOsARM64_recommendedSteps_runApplication from '../Modul /// ////// Python Done /// ///// JavaScript Start // Express +// Express Docker +import APM_javascript_express_docker_quickStart_instrumentApplication from '../Modules/APM/Javascript/md-docs/Express/Docker/QuickStart/express-docker-quickStart-instrumentApplication.md'; +import APM_javascript_express_docker_quickStart_runApplication from '../Modules/APM/Javascript/md-docs/Express/Docker/QuickStart/express-docker-quickStart-runApplication.md'; +// Express-LinuxAMD64-recommended +import APM_javascript_express_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/Express/Docker/Recommended/express-docker-recommended-installOtelCollector.md'; +import APM_javascript_express_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/Express/Docker/Recommended/express-docker-recommended-instrumentApplication.md'; +import APM_javascript_express_docker_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/Express/Docker/Recommended/express-docker-recommended-runApplication.md'; // Express-Kubernetes import APM_javascript_express_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/Express/Kubernetes/express-kubernetes-installOtelCollector.md'; import APM_javascript_express_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/Express/Kubernetes/express-kubernetes-instrumentApplication.md'; @@ -272,6 +330,13 @@ import APM_javascript_express_macOsARM64_recommendedSteps_instrumentApplication import APM_javascript_express_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/Express/MacOsARM64/Recommended/express-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- // NestJS +// NestJS Docker +import APM_javascript_nestjs_docker_quickStart_instrumentApplication from '../Modules/APM/Javascript/md-docs/NestJS/Docker/QuickStart/nestjs-docker-quickStart-instrumentApplication.md'; +import APM_javascript_nestjs_docker_quickStart_runApplication from '../Modules/APM/Javascript/md-docs/NestJS/Docker/QuickStart/nestjs-docker-quickStart-runApplication.md'; +// NestJS-LinuxAMD64-recommended +import APM_javascript_nestjs_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/NestJS/Docker/Recommended/nestjs-docker-recommended-installOtelCollector.md'; +import APM_javascript_nestjs_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/NestJS/Docker/Recommended/nestjs-docker-recommended-instrumentApplication.md'; +import APM_javascript_nestjs_docker_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/NestJS/Docker/Recommended/nestjs-docker-recommended-runApplication.md'; // NestJS-Kubernetes import APM_javascript_nestjs_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/NestJS/Kubernetes/nestjs-kubernetes-installOtelCollector.md'; import APM_javascript_nestjs_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/NestJS/Kubernetes/nestjs-kubernetes-instrumentApplication.md'; @@ -306,6 +371,13 @@ import APM_javascript_nestjs_macOsARM64_recommendedSteps_instrumentApplication f import APM_javascript_nestjs_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/NestJS/MacOsARM64/Recommended/nestjs-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- // NodeJS +// NodeJS Docker +import APM_javascript_nodejs_docker_quickStart_instrumentApplication from '../Modules/APM/Javascript/md-docs/NodeJS/Docker/QuickStart/nodejs-docker-quickStart-instrumentApplication.md'; +import APM_javascript_nodejs_docker_quickStart_runApplication from '../Modules/APM/Javascript/md-docs/NodeJS/Docker/QuickStart/nodejs-docker-quickStart-runApplication.md'; +// NodeJS-LinuxAMD64-recommended +import APM_javascript_nodejs_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/NodeJS/Docker/Recommended/nodejs-docker-recommended-installOtelCollector.md'; +import APM_javascript_nodejs_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/NodeJS/Docker/Recommended/nodejs-docker-recommended-instrumentApplication.md'; +import APM_javascript_nodejs_docker_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/NodeJS/Docker/Recommended/nodejs-docker-recommended-runApplication.md'; // NodeJS-Kubernetes import APM_javascript_nodejs_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/NodeJS/Kubernetes/nodejs-kubernetes-installOtelCollector.md'; import APM_javascript_nodejs_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/NodeJS/Kubernetes/nodejs-kubernetes-instrumentApplication.md'; @@ -339,6 +411,14 @@ import APM_javascript_nodejs_macOsARM64_recommendedSteps_setupOtelCollector from import APM_javascript_nodejs_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/NodeJS/MacOsARM64/Recommended/nodejs-macosarm64-recommended-instrumentApplication.md'; import APM_javascript_nodejs_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/NodeJS/MacOsARM64/Recommended/nodejs-macosarm64-recommended-runApplication.md'; /// // JavaScript Others +// Others Docker +import APM_javascript_others_docker_quickStart_instrumentApplication from '../Modules/APM/Javascript/md-docs/Others/Docker/QuickStart/others-docker-quickStart-instrumentApplication.md'; +import APM_javascript_others_docker_quickStart_runApplication from '../Modules/APM/Javascript/md-docs/Others/Docker/QuickStart/others-docker-quickStart-runApplication.md'; +// // Others-JavaScript-LinuxAMD64-recommended +import APM_javascript_others_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/Others/Docker/Recommended/others-docker-recommended-installOtelCollector.md'; +import APM_javascript_others_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/Others/Docker/Recommended/others-docker-recommended-instrumentApplication.md'; +import APM_javascript_others_docker_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/Others/Docker/Recommended/others-docker-recommended-runApplication.md'; +// Kubernetes import APM_javascript_others_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/Others/Kubernetes/others-kubernetes-installOtelCollector.md'; import APM_javascript_others_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/Others/Kubernetes/others-kubernetes-instrumentApplication.md'; import APM_javascript_others_kubernetes_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/Others/Kubernetes/others-kubernetes-runApplication.md'; @@ -371,6 +451,13 @@ import APM_javascript_others_macOsARM64_recommendedSteps_setupOtelCollector from import APM_javascript_others_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/Others/MacOsARM64/Recommended/others-macosarm64-recommended-instrumentApplication.md'; import APM_javascript_others_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/Others/MacOsARM64/Recommended/others-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- +// ReactJS Docker +import APM_javascript_reactjs_docker_quickStart_instrumentApplication from '../Modules/APM/Javascript/md-docs/ReactJS/Docker/QuickStart/reactjs-docker-quickStart-instrumentApplication.md'; +import APM_javascript_reactjs_docker_quickStart_runApplication from '../Modules/APM/Javascript/md-docs/ReactJS/Docker/QuickStart/reactjs-docker-quickStart-runApplication.md'; +// // ReactJS-LinuxAMD64-recommended +import APM_javascript_reactjs_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/ReactJS/Docker/Recommended/reactjs-docker-recommended-installOtelCollector.md'; +import APM_javascript_reactjs_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/ReactJS/Docker/Recommended/reactjs-docker-recommended-instrumentApplication.md'; +import APM_javascript_reactjs_docker_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/ReactJS/Docker/Recommended/reactjs-docker-recommended-runApplication.md'; // ReactJS-Kubernetes import APM_javascript_reactjs_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/ReactJS/Kubernetes/reactjs-kubernetes-installOtelCollector.md'; import APM_javascript_reactjs_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/ReactJS/Kubernetes/reactjs-kubernetes-instrumentApplication.md'; @@ -403,6 +490,13 @@ import APM_javascript_reactjs_macOsARM64_quickStart_runApplication from '../Modu import APM_javascript_reactjs_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/Javascript/md-docs/ReactJS/MacOsARM64/Recommended/reactjs-macosarm64-recommended-installOtelCollector.md'; import APM_javascript_reactjs_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Javascript/md-docs/ReactJS/MacOsARM64/Recommended/reactjs-macosarm64-recommended-instrumentApplication.md'; import APM_javascript_reactjs_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Javascript/md-docs/ReactJS/MacOsARM64/Recommended/reactjs-macosarm64-recommended-runApplication.md'; +// PHP Docker +import APM_php_docker_quickStart_instrumentApplication from '../Modules/APM/Php/md-docs/Docker/QuickStart/php-docker-quickStart-instrumentApplication.md'; +import APM_php_docker_quickStart_runApplication from '../Modules/APM/Php/md-docs/Docker/QuickStart/php-docker-quickStart-runApplication.md'; +// PHP-LinuxAMD64-recommended +import APM_php_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Php/md-docs/Docker/Recommended/php-docker-recommended-installOtelCollector.md'; +import APM_php_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Php/md-docs/Docker/Recommended/php-docker-recommended-instrumentApplication.md'; +import APM_php_docker_recommendedSteps_runApplication from '../Modules/APM/Php/md-docs/Docker/Recommended/php-docker-recommended-runApplication.md'; // PHP-Kubernetes import APM_php_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Php/md-docs/Kubernetes/php-kubernetes-installOtelCollector.md'; import APM_php_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Php/md-docs/Kubernetes/php-kubernetes-instrumentApplication.md'; @@ -435,6 +529,13 @@ import APM_php_macOsARM64_quickStart_runApplication from '../Modules/APM/Php/md- import APM_php_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/Php/md-docs/MacOsARM64/Recommended/php-macosarm64-recommended-installOtelCollector.md'; import APM_php_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Php/md-docs/MacOsARM64/Recommended/php-macosarm64-recommended-instrumentApplication.md'; import APM_php_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Php/md-docs/MacOsARM64/Recommended/php-macosarm64-recommended-runApplication.md'; +/// ////// Docker instructions +import APM_python_django_docker_quickStart_instrumentApplication from '../Modules/APM/Python/md-docs/Django/Docker/QuickStart/django-docker-quickStart-instrumentApplication.md'; +import APM_python_django_docker_quickStart_runApplication from '../Modules/APM/Python/md-docs/Django/Docker/QuickStart/django-docker-quickStart-runApplication.md'; +// Django-LinuxAMD64-recommended +import APM_python_django_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Django/Docker/Recommended/django-docker-recommended-installOtelCollector.md'; +import APM_python_django_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Django/Docker/Recommended/django-docker-recommended-instrumentApplication.md'; +import APM_python_django_docker_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Django/Docker/Recommended/django-docker-recommended-runApplication.md'; /// ////// Javascript Done /// ///// Python Start // Django @@ -472,6 +573,13 @@ import APM_python_django_macOsARM64_recommendedSteps_instrumentApplication from import APM_python_django_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Django/MacOsARM64/Recommended/django-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- // Falcon +// Falcon Docker +import APM_python_falcon_docker_quickStart_instrumentApplication from '../Modules/APM/Python/md-docs/Falcon/Docker/QuickStart/falcon-docker-quickStart-instrumentApplication.md'; +import APM_python_falcon_docker_quickStart_runApplication from '../Modules/APM/Python/md-docs/Falcon/Docker/QuickStart/falcon-docker-quickStart-runApplication.md'; +// Falcon-LinuxAMD64-recommended +import APM_python_falcon_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Falcon/Docker/Recommended/falcon-docker-recommended-installOtelCollector.md'; +import APM_python_falcon_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Falcon/Docker/Recommended/falcon-docker-recommended-instrumentApplication.md'; +import APM_python_falcon_docker_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Falcon/Docker/Recommended/falcon-docker-recommended-runApplication.md'; // Falcon-Kubernetes import APM_python_falcon_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Falcon/Kubernetes/falcon-kubernetes-installOtelCollector.md'; import APM_python_falcon_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Falcon/Kubernetes/falcon-kubernetes-instrumentApplication.md'; @@ -506,6 +614,13 @@ import APM_python_falcon_macOsARM64_recommendedSteps_instrumentApplication from import APM_python_falcon_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Falcon/MacOsARM64/Recommended/falcon-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- // FastAPI +// FastAPI Docker +import APM_python_fastAPI_docker_quickStart_instrumentApplication from '../Modules/APM/Python/md-docs/FastAPI/Docker/QuickStart/fastapi-docker-quickStart-instrumentApplication.md'; +import APM_python_fastAPI_docker_quickStart_runApplication from '../Modules/APM/Python/md-docs/FastAPI/Docker/QuickStart/fastapi-docker-quickStart-runApplication.md'; +// FastAPI-LinuxAMD64-recommended +import APM_python_fastAPI_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/FastAPI/Docker/Recommended/fastapi-docker-recommended-installOtelCollector.md'; +import APM_python_fastAPI_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/FastAPI/Docker/Recommended/fastapi-docker-recommended-instrumentApplication.md'; +import APM_python_fastAPI_docker_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/FastAPI/Docker/Recommended/fastapi-docker-recommended-runApplication.md'; // FastAPI-Kubernetes import APM_python_fastAPI_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/FastAPI/Kubernetes/fastapi-kubernetes-installOtelCollector.md'; import APM_python_fastAPI_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/FastAPI/Kubernetes/fastapi-kubernetes-instrumentApplication.md'; @@ -540,6 +655,12 @@ import APM_python_fastAPI_macOsARM64_recommendedSteps_instrumentApplication from import APM_python_fastAPI_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/FastAPI/MacOsARM64/Recommended/fastapi-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- // Flask +// Flask Docker +import APM_python_flask_docker_quickStart_instrumentApplication from '../Modules/APM/Python/md-docs/Flask/Docker/QuickStart/flask-docker-quickStart-instrumentApplication.md'; +import APM_python_flask_docker_quickStart_runApplication from '../Modules/APM/Python/md-docs/Flask/Docker/QuickStart/flask-docker-quickStart-runApplication.md'; +import APM_python_flask_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Flask/Docker/Recommended/flask-docker-recommended-installOtelCollector.md'; +import APM_python_flask_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Flask/Docker/Recommended/flask-docker-recommended-instrumentApplication.md'; +import APM_python_flask_docker_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Flask/Docker/Recommended/flask-docker-recommended-runApplication.md'; // Flask-Kubernetes import APM_python_flask_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Flask/Kubernetes/flask-kubernetes-installOtelCollector.md'; import APM_python_flask_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Flask/Kubernetes/flask-kubernetes-instrumentApplication.md'; @@ -574,6 +695,13 @@ import APM_python_flask_macOsARM64_recommendedSteps_instrumentApplication from ' import APM_python_flask_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Flask/MacOsARM64/Recommended/flask-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- // Others +// Others Docker +import APM_python_other_docker_quickStart_instrumentApplication from '../Modules/APM/Python/md-docs/Others/Docker/QuickStart/others-docker-quickStart-instrumentApplication.md'; +import APM_python_other_docker_quickStart_runApplication from '../Modules/APM/Python/md-docs/Others/Docker/QuickStart/others-docker-quickStart-runApplication.md'; +// Others-LinuxAMD64-recommended +import APM_python_other_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Others/Docker/Recommended/others-docker-recommended-installOtelCollector.md'; +import APM_python_other_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Others/Docker/Recommended/others-docker-recommended-instrumentApplication.md'; +import APM_python_other_docker_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Others/Docker/Recommended/others-docker-recommended-runApplication.md'; // Others-Kubernetes import APM_python_other_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Python/md-docs/Others/Kubernetes/others-kubernetes-installOtelCollector.md'; import APM_python_other_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Python/md-docs/Others/Kubernetes/others-kubernetes-instrumentApplication.md'; @@ -608,6 +736,13 @@ import APM_python_other_macOsARM64_recommendedSteps_instrumentApplication from ' import APM_python_other_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Python/md-docs/Others/MacOsARM64/Recommended/others-macosarm64-recommended-runApplication.md'; // ---------------------------------------------------------------------------- /// ///// ROR Start +// ROR Docker +import APM_rails_docker_quickStart_instrumentApplication from '../Modules/APM/RubyOnRails/md-docs/Docker/QuickStart/ror-docker-quickStart-instrumentApplication.md'; +import APM_rails_docker_quickStart_runApplication from '../Modules/APM/RubyOnRails/md-docs/Docker/QuickStart/ror-docker-quickStart-runApplication.md'; +// ROR-LinuxAMD64-recommended +import APM_rails_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/RubyOnRails/md-docs/Docker/Recommended/ror-docker-recommended-installOtelCollector.md'; +import APM_rails_docker_recommendedSteps_instrumentApplication from '../Modules/APM/RubyOnRails/md-docs/Docker/Recommended/ror-docker-recommended-instrumentApplication.md'; +import APM_rails_docker_recommendedSteps_runApplication from '../Modules/APM/RubyOnRails/md-docs/Docker/Recommended/ror-docker-recommended-runApplication.md'; // ROR-Kubernetes import APM_rails_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/RubyOnRails/md-docs/Kubernetes/ror-kubernetes-installOtelCollector.md'; import APM_rails_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/RubyOnRails/md-docs/Kubernetes/ror-kubernetes-instrumentApplication.md'; @@ -640,6 +775,13 @@ import APM_rails_macOsARM64_quickStart_runApplication from '../Modules/APM/RubyO import APM_rails_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/RubyOnRails/md-docs/MacOsARM64/Recommended/ror-macosarm64-recommended-installOtelCollector.md'; import APM_rails_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/RubyOnRails/md-docs/MacOsARM64/Recommended/ror-macosarm64-recommended-instrumentApplication.md'; import APM_rails_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/RubyOnRails/md-docs/MacOsARM64/Recommended/ror-macosarm64-recommended-runApplication.md'; +// Rust DOcker +import APM_rust_docker_quickStart_instrumentApplication from '../Modules/APM/Rust/md-docs/Docker/QuickStart/rust-docker-quickStart-instrumentApplication.md'; +import APM_rust_docker_quickStart_runApplication from '../Modules/APM/Rust/md-docs/Docker/QuickStart/rust-docker-quickStart-runApplication.md'; +// Rust-LinuxAMD64-recommended +import APM_rust_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Rust/md-docs/Docker/Recommended/rust-docker-recommended-installOtelCollector.md'; +import APM_rust_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Rust/md-docs/Docker/Recommended/rust-docker-recommended-instrumentApplication.md'; +import APM_rust_docker_recommendedSteps_runApplication from '../Modules/APM/Rust/md-docs/Docker/Recommended/rust-docker-recommended-runApplication.md'; // Rust-Kubernetes import APM_rust_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Rust/md-docs/Kubernetes/rust-kubernetes-installOtelCollector.md'; import APM_rust_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Rust/md-docs/Kubernetes/rust-kubernetes-instrumentApplication.md'; @@ -672,6 +814,13 @@ import APM_rust_macOsARM64_quickStart_runApplication from '../Modules/APM/Rust/m import APM_rust_macOsARM64_recommendedSteps_setupOtelCollector from '../Modules/APM/Rust/md-docs/MacOsARM64/Recommended/rust-macosarm64-recommended-installOtelCollector.md'; import APM_rust_macOsARM64_recommendedSteps_instrumentApplication from '../Modules/APM/Rust/md-docs/MacOsARM64/Recommended/rust-macosarm64-recommended-instrumentApplication.md'; import APM_rust_macOsARM64_recommendedSteps_runApplication from '../Modules/APM/Rust/md-docs/MacOsARM64/Recommended/rust-macosarm64-recommended-runApplication.md'; +// Swift Docker +import APM_swift_docker_quickStart_instrumentApplication from '../Modules/APM/Swift/md-docs/Docker/QuickStart/swift-docker-quickStart-instrumentApplication.md'; +import APM_swift_docker_quickStart_runApplication from '../Modules/APM/Swift/md-docs/Docker/QuickStart/swift-docker-quickStart-runApplication.md'; +// Swift-LinuxAMD64-recommended +import APM_swift_docker_recommendedSteps_setupOtelCollector from '../Modules/APM/Swift/md-docs/Docker/Recommended/swift-docker-recommended-installOtelCollector.md'; +import APM_swift_docker_recommendedSteps_instrumentApplication from '../Modules/APM/Swift/md-docs/Docker/Recommended/swift-docker-recommended-instrumentApplication.md'; +import APM_swift_docker_recommendedSteps_runApplication from '../Modules/APM/Swift/md-docs/Docker/Recommended/swift-docker-recommended-runApplication.md'; // Swift-Kubernetes import APM_swift_kubernetes_recommendedSteps_setupOtelCollector from '../Modules/APM/Swift/md-docs/Kubernetes/swift-kubernetes-installOtelCollector.md'; import APM_swift_kubernetes_recommendedSteps_instrumentApplication from '../Modules/APM/Swift/md-docs/Kubernetes/swift-kubernetes-instrumentApplication.md'; @@ -1609,4 +1758,153 @@ export const ApmDocFilePaths = { APM_php_macOsARM64_recommendedSteps_setupOtelCollector, APM_php_macOsARM64_recommendedSteps_instrumentApplication, APM_php_macOsARM64_recommendedSteps_runApplication, + + /// ///// Docker Steps + + APM_python_django_docker_quickStart_instrumentApplication, + APM_python_django_docker_quickStart_runApplication, + + APM_python_django_docker_recommendedSteps_setupOtelCollector, + APM_python_django_docker_recommendedSteps_instrumentApplication, + APM_python_django_docker_recommendedSteps_runApplication, + + APM_python_flask_docker_quickStart_instrumentApplication, + APM_python_flask_docker_quickStart_runApplication, + + APM_python_flask_docker_recommendedSteps_setupOtelCollector, + APM_python_flask_docker_recommendedSteps_instrumentApplication, + APM_python_flask_docker_recommendedSteps_runApplication, + + APM_python_fastAPI_docker_quickStart_instrumentApplication, + APM_python_fastAPI_docker_quickStart_runApplication, + + APM_python_fastAPI_docker_recommendedSteps_setupOtelCollector, + APM_python_fastAPI_docker_recommendedSteps_instrumentApplication, + APM_python_fastAPI_docker_recommendedSteps_runApplication, + + APM_python_falcon_docker_quickStart_instrumentApplication, + APM_python_falcon_docker_quickStart_runApplication, + + APM_python_falcon_docker_recommendedSteps_setupOtelCollector, + APM_python_falcon_docker_recommendedSteps_instrumentApplication, + APM_python_falcon_docker_recommendedSteps_runApplication, + + APM_python_other_docker_quickStart_instrumentApplication, + APM_python_other_docker_quickStart_runApplication, + + APM_python_other_docker_recommendedSteps_setupOtelCollector, + APM_python_other_docker_recommendedSteps_instrumentApplication, + APM_python_other_docker_recommendedSteps_runApplication, + + APM_javascript_nodejs_docker_quickStart_instrumentApplication, + APM_javascript_nodejs_docker_quickStart_runApplication, + + APM_javascript_nodejs_docker_recommendedSteps_setupOtelCollector, + APM_javascript_nodejs_docker_recommendedSteps_instrumentApplication, + APM_javascript_nodejs_docker_recommendedSteps_runApplication, + + APM_javascript_nestjs_docker_quickStart_instrumentApplication, + APM_javascript_nestjs_docker_quickStart_runApplication, + + APM_javascript_nestjs_docker_recommendedSteps_instrumentApplication, + APM_javascript_nestjs_docker_recommendedSteps_setupOtelCollector, + APM_javascript_nestjs_docker_recommendedSteps_runApplication, + + APM_javascript_express_docker_quickStart_instrumentApplication, + APM_javascript_express_docker_quickStart_runApplication, + + APM_javascript_express_docker_recommendedSteps_setupOtelCollector, + APM_javascript_express_docker_recommendedSteps_instrumentApplication, + APM_javascript_express_docker_recommendedSteps_runApplication, + + APM_javascript_reactjs_docker_quickStart_instrumentApplication, + APM_javascript_reactjs_docker_quickStart_runApplication, + + APM_javascript_reactjs_docker_recommendedSteps_setupOtelCollector, + APM_javascript_reactjs_docker_recommendedSteps_instrumentApplication, + APM_javascript_reactjs_docker_recommendedSteps_runApplication, + + APM_javascript_others_docker_quickStart_instrumentApplication, + APM_javascript_others_docker_quickStart_runApplication, + + APM_javascript_others_docker_recommendedSteps_setupOtelCollector, + APM_javascript_others_docker_recommendedSteps_instrumentApplication, + APM_javascript_others_docker_recommendedSteps_runApplication, + + APM_java_jboss_docker_quickStart_instrumentApplication, + APM_java_jboss_docker_quickStart_runApplication, + + APM_java_jboss_docker_recommendedSteps_setupOtelCollector, + APM_java_jboss_docker_recommendedSteps_instrumentApplication, + APM_java_jboss_docker_recommendedSteps_runApplication, + + APM_java_springBoot_docker_quickStart_instrumentApplication, + APM_java_springBoot_docker_quickStart_runApplication, + + APM_java_springBoot_docker_recommendedSteps_setupOtelCollector, + APM_java_springBoot_docker_recommendedSteps_instrumentApplication, + APM_java_springBoot_docker_recommendedSteps_runApplication, + + APM_java_tomcat_docker_quickStart_instrumentApplication, + APM_java_tomcat_docker_quickStart_runApplication, + + APM_java_tomcat_docker_recommendedSteps_setupOtelCollector, + APM_java_tomcat_docker_recommendedSteps_instrumentApplication, + APM_java_tomcat_docker_recommendedSteps_runApplication, + + APM_java_other_docker_quickStart_instrumentApplication, + APM_java_other_docker_quickStart_runApplication, + + APM_java_other_docker_recommendedSteps_setupOtelCollector, + APM_java_other_docker_recommendedSteps_instrumentApplication, + APM_java_other_docker_recommendedSteps_runApplication, + + APM_go_docker_quickStart_instrumentApplication, + APM_go_docker_quickStart_runApplication, + + APM_go_docker_recommendedSteps_setupOtelCollector, + APM_go_docker_recommendedSteps_instrumentApplication, + APM_go_docker_recommendedSteps_runApplication, + + APM_rust_docker_quickStart_instrumentApplication, + APM_rust_docker_quickStart_runApplication, + + APM_rust_docker_recommendedSteps_setupOtelCollector, + APM_rust_docker_recommendedSteps_instrumentApplication, + APM_rust_docker_recommendedSteps_runApplication, + + APM_elixir_docker_quickStart_instrumentApplication, + APM_elixir_docker_quickStart_runApplication, + + APM_elixir_docker_recommendedSteps_setupOtelCollector, + APM_elixir_docker_recommendedSteps_instrumentApplication, + APM_elixir_docker_recommendedSteps_runApplication, + + APM_dotnet_docker_quickStart_instrumentApplication, + APM_dotnet_docker_quickStart_runApplication, + + APM_dotnet_docker_recommendedSteps_setupOtelCollector, + APM_dotnet_docker_recommendedSteps_instrumentApplication, + APM_dotnet_docker_recommendedSteps_runApplication, + + APM_rails_docker_quickStart_instrumentApplication, + APM_rails_docker_quickStart_runApplication, + + APM_rails_docker_recommendedSteps_setupOtelCollector, + APM_rails_docker_recommendedSteps_instrumentApplication, + APM_rails_docker_recommendedSteps_runApplication, + + APM_swift_docker_quickStart_instrumentApplication, + APM_swift_docker_quickStart_runApplication, + + APM_swift_docker_recommendedSteps_setupOtelCollector, + APM_swift_docker_recommendedSteps_instrumentApplication, + APM_swift_docker_recommendedSteps_runApplication, + + APM_php_docker_quickStart_instrumentApplication, + APM_php_docker_quickStart_runApplication, + + APM_php_docker_recommendedSteps_setupOtelCollector, + APM_php_docker_recommendedSteps_instrumentApplication, + APM_php_docker_recommendedSteps_runApplication, }; diff --git a/frontend/src/container/OptionsMenu/constants.ts b/frontend/src/container/OptionsMenu/constants.ts index b1e54636865a..2db02f85b8de 100644 --- a/frontend/src/container/OptionsMenu/constants.ts +++ b/frontend/src/container/OptionsMenu/constants.ts @@ -1,3 +1,5 @@ +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; + import { OptionsQuery } from './types'; export const URL_OPTIONS = 'options'; @@ -7,3 +9,46 @@ export const defaultOptionsQuery: OptionsQuery = { maxLines: 2, format: 'list', }; + +export const defaultTraceSelectedColumns = [ + { + key: 'serviceName', + dataType: DataTypes.String, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'serviceName--string--tag--true', + }, + { + key: 'name', + dataType: DataTypes.String, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'name--string--tag--true', + }, + { + key: 'durationNano', + dataType: DataTypes.Float64, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'durationNano--float64--tag--true', + }, + { + key: 'httpMethod', + dataType: DataTypes.String, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'httpMethod--string--tag--true', + }, + { + key: 'responseStatusCode', + dataType: DataTypes.String, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'responseStatusCode--string--tag--true', + }, +]; diff --git a/frontend/src/container/OptionsMenu/useOptionsMenu.ts b/frontend/src/container/OptionsMenu/useOptionsMenu.ts index be2ae00b3703..97fbbbb00666 100644 --- a/frontend/src/container/OptionsMenu/useOptionsMenu.ts +++ b/frontend/src/container/OptionsMenu/useOptionsMenu.ts @@ -16,7 +16,11 @@ import { } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { DataSource } from 'types/common/queryBuilder'; -import { defaultOptionsQuery, URL_OPTIONS } from './constants'; +import { + defaultOptionsQuery, + defaultTraceSelectedColumns, + URL_OPTIONS, +} from './constants'; import { InitialOptions, OptionsMenuConfig, OptionsQuery } from './types'; import { getOptionsFromKeys } from './utils'; @@ -124,20 +128,29 @@ const useOptionsMenu = ({ { queryKey: [debouncedSearchText, isFocused], enabled: isFocused }, ); - const searchedAttributeKeys = useMemo( - () => searchedAttributesData?.payload?.attributeKeys || [], - [searchedAttributesData?.payload?.attributeKeys], - ); + const searchedAttributeKeys = useMemo(() => { + if (searchedAttributesData?.payload?.attributeKeys?.length) { + return searchedAttributesData.payload.attributeKeys; + } + if (dataSource === DataSource.TRACES) { + return defaultTraceSelectedColumns; + } + + return []; + }, [dataSource, searchedAttributesData?.payload?.attributeKeys]); const initialOptionsQuery: OptionsQuery = useMemo( () => ({ ...defaultOptionsQuery, ...initialOptions, + // eslint-disable-next-line no-nested-ternary selectColumns: initialOptions?.selectColumns ? initialSelectedColumns + : dataSource === DataSource.TRACES + ? defaultTraceSelectedColumns : defaultOptionsQuery.selectColumns, }), - [initialOptions, initialSelectedColumns], + [dataSource, initialOptions, initialSelectedColumns], ); const selectedColumnKeys = useMemo( diff --git a/frontend/src/container/PanelWrapper/ListPanelWrapper.tsx b/frontend/src/container/PanelWrapper/ListPanelWrapper.tsx new file mode 100644 index 000000000000..f43fc4e30931 --- /dev/null +++ b/frontend/src/container/PanelWrapper/ListPanelWrapper.tsx @@ -0,0 +1,37 @@ +import LogsPanelComponent from 'container/LogsPanelTable/LogsPanelComponent'; +import TracesTableComponent from 'container/TracesTableComponent/TracesTableComponent'; +import { DataSource } from 'types/common/queryBuilder'; + +import { PanelWrapperProps } from './panelWrapper.types'; + +function ListPanelWrapper({ + widget, + queryResponse, + setRequestData, +}: PanelWrapperProps): JSX.Element { + const dataSource = widget.query.builder?.queryData[0]?.dataSource; + + if (!setRequestData) { + // eslint-disable-next-line react/jsx-no-useless-fragment + return <>; + } + + if (dataSource === DataSource.LOGS) { + return ( + + ); + } + return ( + + ); +} + +export default ListPanelWrapper; diff --git a/frontend/src/container/PanelWrapper/PanelWrapper.tsx b/frontend/src/container/PanelWrapper/PanelWrapper.tsx new file mode 100644 index 000000000000..4e8d7eff9666 --- /dev/null +++ b/frontend/src/container/PanelWrapper/PanelWrapper.tsx @@ -0,0 +1,42 @@ +import { FC } from 'react'; + +import { PanelTypeVsPanelWrapper } from './constants'; +import { PanelWrapperProps } from './panelWrapper.types'; + +function PanelWrapper({ + widget, + queryResponse, + setRequestData, + isFullViewMode, + setGraphVisibility, + graphVisibility, + onToggleModelHandler, + onClickHandler, + onDragSelect, + selectedGraph, +}: PanelWrapperProps): JSX.Element { + const Component = PanelTypeVsPanelWrapper[ + selectedGraph || widget.panelTypes + ] as FC; + + if (!Component) { + // eslint-disable-next-line react/jsx-no-useless-fragment + return <>; + } + return ( + + ); +} + +export default PanelWrapper; diff --git a/frontend/src/container/PanelWrapper/PiePanelWrapper.styles.scss b/frontend/src/container/PanelWrapper/PiePanelWrapper.styles.scss new file mode 100644 index 000000000000..86f5ec3444e4 --- /dev/null +++ b/frontend/src/container/PanelWrapper/PiePanelWrapper.styles.scss @@ -0,0 +1,50 @@ +.piechart-no-data { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; +} + +.piechart-container { + height: 90%; + width: 100%; +} + +.piechart-tooltip { + + .piechart-indicator { + width: 15px; + height: 3px; + border-radius: 2px; + } + + .tooltip-value { + font-size: 12px; + font-weight: 600; + } +} + +.piechart-legend { + width: 100%; + height: 40px; + overflow-y: scroll; + display: flex; + gap: 10px; + justify-content: center; + align-items: center; + flex-wrap: wrap; + + .piechart-legend-item { + display: flex; + justify-content: center; + align-items: center; + gap: 5px; + + .piechart-legend-label { + width: 10px; + height: 10px; + border-radius: 50%; + } + } +} \ No newline at end of file diff --git a/frontend/src/container/PanelWrapper/PiePanelWrapper.tsx b/frontend/src/container/PanelWrapper/PiePanelWrapper.tsx new file mode 100644 index 000000000000..71c74b4b4607 --- /dev/null +++ b/frontend/src/container/PanelWrapper/PiePanelWrapper.tsx @@ -0,0 +1,218 @@ +import './PiePanelWrapper.styles.scss'; + +import { Color } from '@signozhq/design-tokens'; +import { Group } from '@visx/group'; +import { Pie } from '@visx/shape'; +import { useTooltip, useTooltipInPortal } from '@visx/tooltip'; +import { themeColors } from 'constants/theme'; +import { useIsDarkMode } from 'hooks/useDarkMode'; +import { generateColor } from 'lib/uPlotLib/utils/generateColor'; +import { useRef, useState } from 'react'; +import { Query } from 'types/api/queryBuilder/queryBuilderData'; + +import { PanelWrapperProps, TooltipData } from './panelWrapper.types'; +import { getLabel, lightenColor, tooltipStyles } from './utils'; + +// refernce: https://www.youtube.com/watch?v=bL3P9CqQkKw +function PiePanelWrapper({ + queryResponse, + widget, +}: PanelWrapperProps): JSX.Element { + const [active, setActive] = useState<{ + label: string; + value: string; + color: string; + } | null>(null); + + const { + tooltipOpen, + tooltipLeft, + tooltipTop, + tooltipData, + hideTooltip, + showTooltip, + } = useTooltip(); + + const { containerRef, TooltipInPortal } = useTooltipInPortal({ + scroll: true, + detectBounds: true, + }); + + const panelData = + queryResponse.data?.payload?.data.newResult.data.result || []; + + const isDarkMode = useIsDarkMode(); + + const pieChartData: { + label: string; + value: string; + color: string; + }[] = [].concat( + ...(panelData + .map((d) => + d.series?.map((s) => ({ + label: + d.series?.length === 1 + ? getLabel(Object.values(s.labels)[0], widget.query, d.queryName) + : getLabel(Object.values(s.labels)[0], {} as Query, d.queryName, true), + value: s.values[0].value, + color: generateColor( + d.series?.length === 1 + ? getLabel(Object.values(s.labels)[0], widget.query, d.queryName) + : getLabel(Object.values(s.labels)[0], {} as Query, d.queryName, true), + themeColors.chartcolors, + ), + })), + ) + .filter((d) => d !== undefined) as never[]), + ); + + let size = 0; + let width = 0; + let height = 0; + + const chartRef = useRef(null); + if (chartRef.current) { + const { offsetWidth, offsetHeight } = chartRef.current; + size = Math.min(offsetWidth, offsetHeight); + width = offsetWidth; + height = offsetHeight; + } + const half = size / 2; + + const getFillColor = (color: string): string => { + if (active === null) { + return color; + } + const lightenedColor = lightenColor(color, 0.4); // Adjust the opacity value (0.7 in this case) + return active.color === color ? color : lightenedColor; + }; + + return ( + <> + {!pieChartData.length &&
No data
} + {pieChartData.length > 0 && ( + <> +
+ + + parseFloat(data.value)} + outerRadius={({ data }): number => { + if (!active) return half - 3; + return data.label === active.label ? half : half - 3; + }} + padAngle={0.02} + cornerRadius={3} + width={size} + height={size} + > + { + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + (pie) => + pie.arcs.map((arc, index) => { + const { label } = arc.data; + const [centroidX, centroidY] = pie.path.centroid(arc); + const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.6; + const arcPath = pie.path(arc); + const arcFill = arc.data.color; + return ( + { + showTooltip({ + tooltipData: { + label, + value: arc.data.value, + color: arc.data.color, + key: label, + }, + tooltipTop: centroidY + height / 2, + tooltipLeft: centroidX + width / 2, + }); + setActive(arc.data); + }} + onMouseLeave={(): void => { + hideTooltip(); + setActive(null); + }} + > + + {hasSpaceForLabel && ( + + {arc.data.label} + + )} + + ); + }) + } + + + + {tooltipOpen && tooltipData && ( + +
+ {tooltipData.key} +
{tooltipData.value}
+ + )} +
+
+ {pieChartData.length > 0 && + pieChartData.map((data) => ( +
{ + setActive(data); + }} + onMouseLeave={(): void => { + setActive(null); + }} + > +
+ {data.label} +
+ ))} +
+ + )} + + ); +} + +export default PiePanelWrapper; diff --git a/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx b/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx new file mode 100644 index 000000000000..10a41493df13 --- /dev/null +++ b/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx @@ -0,0 +1,24 @@ +import GridTableComponent from 'container/GridTableComponent'; +import { GRID_TABLE_CONFIG } from 'container/GridTableComponent/config'; + +import { PanelWrapperProps } from './panelWrapper.types'; + +function TablePanelWrapper({ + widget, + queryResponse, +}: PanelWrapperProps): JSX.Element { + const panelData = + queryResponse.data?.payload?.data.newResult.data.result || []; + const { thresholds } = widget; + return ( + + ); +} + +export default TablePanelWrapper; diff --git a/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx b/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx new file mode 100644 index 000000000000..f95d5772afb9 --- /dev/null +++ b/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx @@ -0,0 +1,143 @@ +import { ToggleGraphProps } from 'components/Graph/types'; +import Uplot from 'components/Uplot'; +import { PANEL_TYPES } from 'constants/queryBuilder'; +import GraphManager from 'container/GridCardLayout/GridCard/FullView/GraphManager'; +import { getLocalStorageGraphVisibilityState } from 'container/GridCardLayout/GridCard/utils'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import { useIsDarkMode } from 'hooks/useDarkMode'; +import { useResizeObserver } from 'hooks/useDimensions'; +import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions'; +import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData'; +import _noop from 'lodash-es/noop'; +import { useDashboard } from 'providers/Dashboard/Dashboard'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import { getSortedSeriesData } from 'utils/getSortedSeriesData'; +import { getTimeRange } from 'utils/getTimeRange'; + +import { PanelWrapperProps } from './panelWrapper.types'; + +function UplotPanelWrapper({ + queryResponse, + widget, + isFullViewMode, + setGraphVisibility, + graphVisibility, + onToggleModelHandler, + onClickHandler, + onDragSelect, + selectedGraph, +}: PanelWrapperProps): JSX.Element { + const { toScrollWidgetId, setToScrollWidgetId } = useDashboard(); + const isDarkMode = useIsDarkMode(); + const lineChartRef = useRef(); + const graphRef = useRef(null); + const [minTimeScale, setMinTimeScale] = useState(); + const [maxTimeScale, setMaxTimeScale] = useState(); + const { currentQuery } = useQueryBuilder(); + + useEffect(() => { + if (toScrollWidgetId === widget.id) { + graphRef.current?.scrollIntoView({ + behavior: 'smooth', + block: 'center', + }); + graphRef.current?.focus(); + setToScrollWidgetId(''); + } + }, [toScrollWidgetId, setToScrollWidgetId, widget.id]); + + useEffect((): void => { + const { startTime, endTime } = getTimeRange(queryResponse); + + setMinTimeScale(startTime); + setMaxTimeScale(endTime); + }, [queryResponse]); + + const containerDimensions = useResizeObserver(graphRef); + + useEffect(() => { + const { + graphVisibilityStates: localStoredVisibilityState, + } = getLocalStorageGraphVisibilityState({ + apiResponse: queryResponse.data?.payload.data.result || [], + name: widget.id, + }); + if (setGraphVisibility) { + setGraphVisibility(localStoredVisibilityState); + } + }, [queryResponse.data?.payload.data.result, setGraphVisibility, widget.id]); + + if (queryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) { + const sortedSeriesData = getSortedSeriesData( + queryResponse.data?.payload.data.result, + ); + // eslint-disable-next-line no-param-reassign + queryResponse.data.payload.data.result = sortedSeriesData; + } + + const chartData = getUPlotChartData( + queryResponse?.data?.payload, + widget.fillSpans, + ); + + const options = useMemo( + () => + getUPlotChartOptions({ + id: widget?.id, + apiResponse: queryResponse.data?.payload, + dimensions: containerDimensions, + isDarkMode, + onDragSelect, + yAxisUnit: widget?.yAxisUnit, + onClickHandler: onClickHandler || _noop, + thresholds: widget.thresholds, + minTimeScale, + maxTimeScale, + softMax: widget.softMax === undefined ? null : widget.softMax, + softMin: widget.softMin === undefined ? null : widget.softMin, + graphsVisibilityStates: graphVisibility, + setGraphsVisibilityStates: setGraphVisibility, + panelType: selectedGraph || widget.panelTypes, + currentQuery, + }), + [ + widget?.id, + widget?.yAxisUnit, + widget.thresholds, + widget.softMax, + widget.softMin, + widget.panelTypes, + queryResponse.data?.payload, + containerDimensions, + isDarkMode, + onDragSelect, + onClickHandler, + minTimeScale, + maxTimeScale, + graphVisibility, + setGraphVisibility, + selectedGraph, + currentQuery, + ], + ); + + return ( +
+ + {isFullViewMode && setGraphVisibility && ( + + )} +
+ ); +} + +export default UplotPanelWrapper; diff --git a/frontend/src/container/PanelWrapper/ValuePanelWrapper.tsx b/frontend/src/container/PanelWrapper/ValuePanelWrapper.tsx new file mode 100644 index 000000000000..b5640d6fcaa4 --- /dev/null +++ b/frontend/src/container/PanelWrapper/ValuePanelWrapper.tsx @@ -0,0 +1,21 @@ +import GridValueComponent from 'container/GridValueComponent'; +import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData'; + +import { PanelWrapperProps } from './panelWrapper.types'; + +function ValuePanelWrapper({ + widget, + queryResponse, +}: PanelWrapperProps): JSX.Element { + const { yAxisUnit, thresholds } = widget; + const data = getUPlotChartData(queryResponse?.data?.payload); + return ( + + ); +} + +export default ValuePanelWrapper; diff --git a/frontend/src/container/PanelWrapper/constants.ts b/frontend/src/container/PanelWrapper/constants.ts new file mode 100644 index 000000000000..a8c456d469b8 --- /dev/null +++ b/frontend/src/container/PanelWrapper/constants.ts @@ -0,0 +1,18 @@ +import { PANEL_TYPES } from 'constants/queryBuilder'; + +import ListPanelWrapper from './ListPanelWrapper'; +import PiePanelWrapper from './PiePanelWrapper'; +import TablePanelWrapper from './TablePanelWrapper'; +import UplotPanelWrapper from './UplotPanelWrapper'; +import ValuePanelWrapper from './ValuePanelWrapper'; + +export const PanelTypeVsPanelWrapper = { + [PANEL_TYPES.TIME_SERIES]: UplotPanelWrapper, + [PANEL_TYPES.TABLE]: TablePanelWrapper, + [PANEL_TYPES.LIST]: ListPanelWrapper, + [PANEL_TYPES.VALUE]: ValuePanelWrapper, + [PANEL_TYPES.TRACE]: null, + [PANEL_TYPES.EMPTY_WIDGET]: null, + [PANEL_TYPES.PIE]: PiePanelWrapper, + [PANEL_TYPES.BAR]: UplotPanelWrapper, +}; diff --git a/frontend/src/container/PanelWrapper/panelWrapper.types.ts b/frontend/src/container/PanelWrapper/panelWrapper.types.ts new file mode 100644 index 000000000000..e2b6ef70c6b7 --- /dev/null +++ b/frontend/src/container/PanelWrapper/panelWrapper.types.ts @@ -0,0 +1,31 @@ +import { PANEL_TYPES } from 'constants/queryBuilder'; +import { WidgetGraphComponentProps } from 'container/GridCardLayout/GridCard/types'; +import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin'; +import { Dispatch, SetStateAction } from 'react'; +import { UseQueryResult } from 'react-query'; +import { SuccessResponse } from 'types/api'; +import { Widgets } from 'types/api/dashboard/getAll'; +import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; + +export type PanelWrapperProps = { + queryResponse: UseQueryResult< + SuccessResponse, + Error + >; + widget: Widgets; + setRequestData?: WidgetGraphComponentProps['setRequestData']; + isFullViewMode?: boolean; + onToggleModelHandler?: () => void; + graphVisibility?: boolean[]; + setGraphVisibility?: Dispatch>; + onClickHandler?: OnClickPluginOpts['onClick']; + onDragSelect: (start: number, end: number) => void; + selectedGraph?: PANEL_TYPES; +}; + +export type TooltipData = { + label: string; + key: string; + value: string; + color: string; +}; diff --git a/frontend/src/container/PanelWrapper/utils.ts b/frontend/src/container/PanelWrapper/utils.ts new file mode 100644 index 000000000000..9ed8c86ba211 --- /dev/null +++ b/frontend/src/container/PanelWrapper/utils.ts @@ -0,0 +1,73 @@ +import { defaultStyles } from '@visx/tooltip'; +import { Query } from 'types/api/queryBuilder/queryBuilderData'; + +export const tooltipStyles = { + ...defaultStyles, + minWidth: 60, + backgroundColor: 'rgba(0,0,0,0.9)', + color: 'white', + zIndex: 9999, + display: 'flex', + gap: '10px', + justifyContent: 'center', + alignItems: 'center', + padding: '5px 10px', +}; + +export const getLabel = ( + label: string, + query: Query, + queryName: string, + isQueryContentMultipleResult = false, // If there are more than one aggregation return by the query, this should be set to true. Default is false. +): string => { + let finalQuery; + if (!isQueryContentMultipleResult) { + finalQuery = query.builder.queryData.find((q) => q.queryName === queryName); + if (!finalQuery) { + // If the query is not found in queryData, then check in queryFormulas + finalQuery = query.builder.queryFormulas.find( + (q) => q.queryName === queryName, + ); + } + } + if (finalQuery) { + if (finalQuery.legend !== '') { + return finalQuery.legend; + } + if (label !== undefined) { + return label; + } + return queryName; + } + return label; +}; + +// Function to convert a hex color to RGB format +const hexToRgb = ( + color: string, +): { r: number; g: number; b: number } | null => { + const hex = color.replace( + /^#?([a-f\d])([a-f\d])([a-f\d])$/i, + (m, r, g, b) => r + r + g + g + b + b, + ); + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } + : null; +}; + +export const lightenColor = (color: string, opacity: number): string => { + // Convert the hex color to RGB format + const rgbColor = hexToRgb(color); + if (!rgbColor) return color; // Return the original color if unable to parse + + // Extract the RGB components + const { r, g, b } = rgbColor; + + // Create a new RGBA color string with the specified opacity + return `rgba(${r}, ${g}, ${b}, ${opacity})`; +}; diff --git a/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.styles.scss b/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.styles.scss index 3bafb59879dc..f0c7565d2926 100644 --- a/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.styles.scss +++ b/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.styles.scss @@ -77,6 +77,7 @@ .qb-entity-options { .options { border-color: var(--bg-vanilla-300); + box-shadow: none; .periscope-btn { border-color: var(--bg-vanilla-300); diff --git a/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.tsx b/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.tsx index 8730506a888a..f7a6f53a3829 100644 --- a/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.tsx +++ b/frontend/src/container/QueryBuilder/components/QBEntityOptions/QBEntityOptions.tsx @@ -17,6 +17,7 @@ import { IBuilderQuery, QueryFunctionProps, } from 'types/api/queryBuilder/queryBuilderData'; +import { DataSource } from 'types/common/queryBuilder'; import QueryFunctions from '../QueryFunctions/QueryFunctions'; @@ -57,6 +58,8 @@ export default function QBEntityOptions({ } }; + const isLogsDataSource = query?.dataSource === DataSource.LOGS; + return (
@@ -97,12 +100,15 @@ export default function QBEntityOptions({ {showFunctions && - isMetricsDataSource && + (isMetricsDataSource || isLogsDataSource) && query && onQueryFunctionsUpdates && ( )} diff --git a/frontend/src/container/QueryBuilder/components/Query/Query.tsx b/frontend/src/container/QueryBuilder/components/Query/Query.tsx index 1bb761fde781..fb8b0e15611c 100644 --- a/frontend/src/container/QueryBuilder/components/Query/Query.tsx +++ b/frontend/src/container/QueryBuilder/components/Query/Query.tsx @@ -36,6 +36,7 @@ import { } from 'react'; import { useLocation } from 'react-use'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; +import { DataSource } from 'types/common/queryBuilder'; import { transformToUpperCase } from 'utils/transformToUpperCase'; import QBEntityOptions from '../QBEntityOptions/QBEntityOptions'; @@ -324,7 +325,10 @@ export const Query = memo(function Query({