mirror of
https://github.com/SigNoz/signoz.git
synced 2026-04-17 01:10:27 +01:00
Compare commits
41 Commits
main
...
platform-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
719b1b14f9 | ||
|
|
82d4040050 | ||
|
|
ca01a288a5 | ||
|
|
3c1ee390a9 | ||
|
|
bb1ca4f698 | ||
|
|
18b49afd4d | ||
|
|
d804d9ca3c | ||
|
|
b4e39f82f6 | ||
|
|
ad834ff618 | ||
|
|
cdd667e9ea | ||
|
|
5a4b8c4a4f | ||
|
|
3e19f2f308 | ||
|
|
37b5e03e24 | ||
|
|
0e8a328146 | ||
|
|
72f0e16b77 | ||
|
|
2dc396effe | ||
|
|
5d74dedfc9 | ||
|
|
c1b70e82d5 | ||
|
|
af692d681b | ||
|
|
5f805a2ad0 | ||
|
|
dfb3c6adf5 | ||
|
|
5d5a3b135d | ||
|
|
aea55afb0a | ||
|
|
a2d7ff166d | ||
|
|
3aefd7a549 | ||
|
|
ecbbeb9103 | ||
|
|
27a073770b | ||
|
|
da1b093c7f | ||
|
|
61cd81b072 | ||
|
|
c40a3dbc08 | ||
|
|
f45228b605 | ||
|
|
20dcd11d80 | ||
|
|
99ceb7149f | ||
|
|
2e6da1092c | ||
|
|
70533f91a9 | ||
|
|
92062ef0f2 | ||
|
|
ec85586fa1 | ||
|
|
950524c0f7 | ||
|
|
9305a45cd1 | ||
|
|
e90e9bd9ce | ||
|
|
fdb8b45667 |
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/SigNoz/signoz/cmd"
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/analytics"
|
||||
"github.com/SigNoz/signoz/pkg/auditor"
|
||||
"github.com/SigNoz/signoz/pkg/authn"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaauthz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaschema"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaserver"
|
||||
"github.com/SigNoz/signoz/pkg/cache"
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/gateway"
|
||||
@@ -26,14 +28,20 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
|
||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/signozruler"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/SigNoz/signoz/pkg/version"
|
||||
"github.com/SigNoz/signoz/pkg/zeus"
|
||||
"github.com/SigNoz/signoz/pkg/zeus/noopzeus"
|
||||
@@ -107,6 +115,9 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
func(_ sqlstore.SQLStore, _ global.Global, _ zeus.Zeus, _ gateway.Gateway, _ licensing.Licensing, _ serviceaccount.Module, _ cloudintegration.Config) (cloudintegration.Module, error) {
|
||||
return implcloudintegration.NewModule(), nil
|
||||
},
|
||||
func(c cache.Cache, am alertmanager.Alertmanager, ss sqlstore.SQLStore, ts telemetrystore.TelemetryStore, ms telemetrytypes.MetadataStore, p prometheus.Prometheus, og organization.Getter, rsh rulestatehistory.Module, q querier.Querier, qp queryparser.QueryParser) factory.NamedMap[factory.ProviderFactory[ruler.Ruler, ruler.Config]] {
|
||||
return factory.MustNewNamedMap(signozruler.NewFactory(c, am, ss, ts, ms, p, og, rsh, q, qp, nil, nil))
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
logger.ErrorContext(ctx, "failed to create signoz", errors.Attr(err))
|
||||
|
||||
@@ -22,14 +22,17 @@ import (
|
||||
"github.com/SigNoz/signoz/ee/modules/dashboard/impldashboard"
|
||||
eequerier "github.com/SigNoz/signoz/ee/querier"
|
||||
enterpriseapp "github.com/SigNoz/signoz/ee/query-service/app"
|
||||
eerules "github.com/SigNoz/signoz/ee/query-service/rules"
|
||||
"github.com/SigNoz/signoz/ee/sqlschema/postgressqlschema"
|
||||
"github.com/SigNoz/signoz/ee/sqlstore/postgressqlstore"
|
||||
enterprisezeus "github.com/SigNoz/signoz/ee/zeus"
|
||||
"github.com/SigNoz/signoz/ee/zeus/httpzeus"
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/analytics"
|
||||
"github.com/SigNoz/signoz/pkg/auditor"
|
||||
"github.com/SigNoz/signoz/pkg/authn"
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/cache"
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/gateway"
|
||||
@@ -40,15 +43,21 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
pkgimpldashboard "github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
|
||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/signozruler"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstorehook"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/SigNoz/signoz/pkg/version"
|
||||
"github.com/SigNoz/signoz/pkg/zeus"
|
||||
)
|
||||
@@ -166,6 +175,9 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
|
||||
return implcloudintegration.NewModule(pkgcloudintegration.NewStore(sqlStore), global, zeus, gateway, licensing, serviceAccount, cloudProvidersMap, config)
|
||||
},
|
||||
func(c cache.Cache, am alertmanager.Alertmanager, ss sqlstore.SQLStore, ts telemetrystore.TelemetryStore, ms telemetrytypes.MetadataStore, p prometheus.Prometheus, og organization.Getter, rsh rulestatehistory.Module, q querier.Querier, qp queryparser.QueryParser) factory.NamedMap[factory.ProviderFactory[ruler.Ruler, ruler.Config]] {
|
||||
return factory.MustNewNamedMap(signozruler.NewFactory(c, am, ss, ts, ms, p, og, rsh, q, qp, eerules.PrepareTaskFunc, eerules.TestNotification))
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
logger.ErrorContext(ctx, "failed to create signoz", errors.Attr(err))
|
||||
|
||||
1326
docs/api/openapi.yml
1326
docs/api/openapi.yml
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/logparsingpipeline"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/interfaces"
|
||||
basemodel "github.com/SigNoz/signoz/pkg/query-service/model"
|
||||
rules "github.com/SigNoz/signoz/pkg/query-service/rules"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/version"
|
||||
@@ -23,7 +22,6 @@ import (
|
||||
|
||||
type APIHandlerOptions struct {
|
||||
DataConnector interfaces.Reader
|
||||
RulesManager *rules.Manager
|
||||
UsageManager *usage.Manager
|
||||
IntegrationsController *integrations.Controller
|
||||
CloudIntegrationsController *cloudintegrations.Controller
|
||||
@@ -43,7 +41,6 @@ type APIHandler struct {
|
||||
func NewAPIHandler(opts APIHandlerOptions, signoz *signoz.SigNoz, config signoz.Config) (*APIHandler, error) {
|
||||
baseHandler, err := baseapp.NewAPIHandler(baseapp.APIHandlerOpts{
|
||||
Reader: opts.DataConnector,
|
||||
RuleManager: opts.RulesManager,
|
||||
IntegrationsController: opts.IntegrationsController,
|
||||
CloudIntegrationsController: opts.CloudIntegrationsController,
|
||||
LogsParsingPipelineController: opts.LogsParsingPipelineController,
|
||||
@@ -64,10 +61,6 @@ func NewAPIHandler(opts APIHandlerOptions, signoz *signoz.SigNoz, config signoz.
|
||||
return ah, nil
|
||||
}
|
||||
|
||||
func (ah *APIHandler) RM() *rules.Manager {
|
||||
return ah.opts.RulesManager
|
||||
}
|
||||
|
||||
func (ah *APIHandler) UM() *usage.Manager {
|
||||
return ah.opts.UsageManager
|
||||
}
|
||||
|
||||
@@ -12,10 +12,6 @@ import (
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/cache/memorycache"
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/rulestore/sqlrulestore"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
|
||||
@@ -23,18 +19,10 @@ import (
|
||||
"github.com/soheilhy/cmux"
|
||||
|
||||
"github.com/SigNoz/signoz/ee/query-service/app/api"
|
||||
"github.com/SigNoz/signoz/ee/query-service/rules"
|
||||
"github.com/SigNoz/signoz/ee/query-service/usage"
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/cache"
|
||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/web"
|
||||
|
||||
"log/slog"
|
||||
@@ -49,7 +37,6 @@ import (
|
||||
opAmpModel "github.com/SigNoz/signoz/pkg/query-service/app/opamp/model"
|
||||
baseconst "github.com/SigNoz/signoz/pkg/query-service/constants"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/healthcheck"
|
||||
baserules "github.com/SigNoz/signoz/pkg/query-service/rules"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
||||
)
|
||||
|
||||
@@ -57,7 +44,6 @@ import (
|
||||
type Server struct {
|
||||
config signoz.Config
|
||||
signoz *signoz.SigNoz
|
||||
ruleManager *baserules.Manager
|
||||
|
||||
// public http router
|
||||
httpConn net.Listener
|
||||
@@ -97,24 +83,6 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
nil,
|
||||
)
|
||||
|
||||
rm, err := makeRulesManager(
|
||||
signoz.Cache,
|
||||
signoz.Alertmanager,
|
||||
signoz.SQLStore,
|
||||
signoz.TelemetryStore,
|
||||
signoz.TelemetryMetadataStore,
|
||||
signoz.Prometheus,
|
||||
signoz.Modules.OrgGetter,
|
||||
signoz.Modules.RuleStateHistory,
|
||||
signoz.Querier,
|
||||
signoz.Instrumentation.ToProviderSettings(),
|
||||
signoz.QueryParser,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// initiate opamp
|
||||
opAmpModel.Init(signoz.SQLStore, signoz.Instrumentation.Logger(), signoz.Modules.OrgGetter)
|
||||
|
||||
@@ -163,7 +131,6 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
|
||||
apiOpts := api.APIHandlerOptions{
|
||||
DataConnector: reader,
|
||||
RulesManager: rm,
|
||||
UsageManager: usageManager,
|
||||
IntegrationsController: integrationsController,
|
||||
CloudIntegrationsController: cloudIntegrationsController,
|
||||
@@ -180,8 +147,7 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
|
||||
s := &Server{
|
||||
config: config,
|
||||
signoz: signoz,
|
||||
ruleManager: rm,
|
||||
signoz: signoz,
|
||||
httpHostPort: baseconst.HTTPHostPort,
|
||||
unavailableChannel: make(chan healthcheck.Status),
|
||||
usageManager: usageManager,
|
||||
@@ -288,8 +254,6 @@ func (s *Server) initListeners() error {
|
||||
|
||||
// Start listening on http and private http port concurrently
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
s.ruleManager.Start(ctx)
|
||||
|
||||
err := s.initListeners()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -333,47 +297,9 @@ func (s *Server) Stop(ctx context.Context) error {
|
||||
|
||||
s.opampServer.Stop()
|
||||
|
||||
if s.ruleManager != nil {
|
||||
s.ruleManager.Stop(ctx)
|
||||
}
|
||||
|
||||
// stop usage manager
|
||||
s.usageManager.Stop(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeRulesManager(cache cache.Cache, alertmanager alertmanager.Alertmanager, sqlstore sqlstore.SQLStore, telemetryStore telemetrystore.TelemetryStore, metadataStore telemetrytypes.MetadataStore, prometheus prometheus.Prometheus, orgGetter organization.Getter, ruleStateHistoryModule rulestatehistory.Module, querier querier.Querier, providerSettings factory.ProviderSettings, queryParser queryparser.QueryParser) (*baserules.Manager, error) {
|
||||
ruleStore := sqlrulestore.NewRuleStore(sqlstore, queryParser, providerSettings)
|
||||
maintenanceStore := sqlrulestore.NewMaintenanceStore(sqlstore)
|
||||
// create manager opts
|
||||
managerOpts := &baserules.ManagerOptions{
|
||||
TelemetryStore: telemetryStore,
|
||||
MetadataStore: metadataStore,
|
||||
Prometheus: prometheus,
|
||||
Context: context.Background(),
|
||||
Querier: querier,
|
||||
Logger: providerSettings.Logger,
|
||||
Cache: cache,
|
||||
EvalDelay: baseconst.GetEvalDelay(),
|
||||
PrepareTaskFunc: rules.PrepareTaskFunc,
|
||||
PrepareTestRuleFunc: rules.TestNotification,
|
||||
Alertmanager: alertmanager,
|
||||
OrgGetter: orgGetter,
|
||||
RuleStore: ruleStore,
|
||||
MaintenanceStore: maintenanceStore,
|
||||
SQLStore: sqlstore,
|
||||
QueryParser: queryParser,
|
||||
RuleStateHistoryModule: ruleStateHistoryModule,
|
||||
}
|
||||
|
||||
// create Manager
|
||||
manager, err := baserules.NewManager(managerOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rule manager error: %v", err)
|
||||
}
|
||||
|
||||
slog.Info("rules manager is ready")
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/create';
|
||||
|
||||
const create = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
const response = await axios.post('/rules', {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default create;
|
||||
@@ -1,28 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import {
|
||||
AlertRuleV2,
|
||||
PostableAlertRuleV2,
|
||||
} from 'types/api/alerts/alertTypesV2';
|
||||
|
||||
export interface CreateAlertRuleResponse {
|
||||
data: AlertRuleV2;
|
||||
status: string;
|
||||
}
|
||||
|
||||
const createAlertRule = async (
|
||||
props: PostableAlertRuleV2,
|
||||
): Promise<SuccessResponse<CreateAlertRuleResponse> | ErrorResponse> => {
|
||||
const response = await axios.post(`/rules`, {
|
||||
...props,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default createAlertRule;
|
||||
@@ -1,18 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/delete';
|
||||
|
||||
const deleteAlerts = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
const response = await axios.delete(`/rules/${props.id}`);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data.rules,
|
||||
};
|
||||
};
|
||||
|
||||
export default deleteAlerts;
|
||||
@@ -1,16 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/get';
|
||||
|
||||
const get = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
const response = await axios.get(`/rules/${props.id}`);
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
};
|
||||
export default get;
|
||||
@@ -1,24 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps } from 'types/api/alerts/getAll';
|
||||
|
||||
const getAll = async (): Promise<
|
||||
SuccessResponse<PayloadProps> | ErrorResponse
|
||||
> => {
|
||||
try {
|
||||
const response = await axios.get('/rules');
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data.rules,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default getAll;
|
||||
@@ -1,29 +0,0 @@
|
||||
import { AxiosAlertManagerInstance } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/getGroups';
|
||||
|
||||
const getGroups = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const queryParams = convertObjectIntoParams(props);
|
||||
|
||||
const response = await AxiosAlertManagerInstance.get(
|
||||
`/alerts/groups?${queryParams}`,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default getGroups;
|
||||
@@ -1,20 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/patch';
|
||||
|
||||
const patch = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
const response = await axios.patch(`/rules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default patch;
|
||||
@@ -1,20 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/save';
|
||||
|
||||
const put = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
const response = await axios.put(`/rules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default put;
|
||||
@@ -1,18 +0,0 @@
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/save';
|
||||
|
||||
import create from './create';
|
||||
import put from './put';
|
||||
|
||||
const save = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
if (props.id && !isEmpty(props.id)) {
|
||||
return put({ ...props });
|
||||
}
|
||||
|
||||
return create({ ...props });
|
||||
};
|
||||
|
||||
export default save;
|
||||
@@ -1,26 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/testAlert';
|
||||
|
||||
const testAlert = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post('/testRule', {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default testAlert;
|
||||
@@ -1,28 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
|
||||
|
||||
export interface TestAlertRuleResponse {
|
||||
data: {
|
||||
alertCount: number;
|
||||
message: string;
|
||||
};
|
||||
status: string;
|
||||
}
|
||||
|
||||
const testAlertRule = async (
|
||||
props: PostableAlertRuleV2,
|
||||
): Promise<SuccessResponse<TestAlertRuleResponse> | ErrorResponse> => {
|
||||
const response = await axios.post(`/testRule`, {
|
||||
...props,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default testAlertRule;
|
||||
@@ -1,26 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
|
||||
|
||||
export interface UpdateAlertRuleResponse {
|
||||
data: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
const updateAlertRule = async (
|
||||
id: string,
|
||||
postableAlertRule: PostableAlertRuleV2,
|
||||
): Promise<SuccessResponse<UpdateAlertRuleResponse> | ErrorResponse> => {
|
||||
const response = await axios.put(`/rules/${id}`, {
|
||||
...postableAlertRule,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default updateAlertRule;
|
||||
495
frontend/src/api/generated/services/downtimeschedules/index.ts
Normal file
495
frontend/src/api/generated/services/downtimeschedules/index.ts
Normal file
@@ -0,0 +1,495 @@
|
||||
/**
|
||||
* ! Do not edit manually
|
||||
* * The file has been auto-generated using Orval for SigNoz
|
||||
* * regenerate with 'yarn generate:api'
|
||||
* SigNoz
|
||||
*/
|
||||
import type {
|
||||
InvalidateOptions,
|
||||
MutationFunction,
|
||||
QueryClient,
|
||||
QueryFunction,
|
||||
QueryKey,
|
||||
UseMutationOptions,
|
||||
UseMutationResult,
|
||||
UseQueryOptions,
|
||||
UseQueryResult,
|
||||
} from 'react-query';
|
||||
import { useMutation, useQuery } from 'react-query';
|
||||
|
||||
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
|
||||
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
|
||||
import type {
|
||||
DeleteDowntimeScheduleByIDPathParameters,
|
||||
GetDowntimeScheduleByID200,
|
||||
GetDowntimeScheduleByIDPathParameters,
|
||||
ListDowntimeSchedules200,
|
||||
ListDowntimeSchedulesParams,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettablePlannedMaintenanceDTO,
|
||||
UpdateDowntimeScheduleByIDPathParameters,
|
||||
} from '../sigNoz.schemas';
|
||||
|
||||
/**
|
||||
* This endpoint lists all planned maintenance / downtime schedules
|
||||
* @summary List downtime schedules
|
||||
*/
|
||||
export const listDowntimeSchedules = (
|
||||
params?: ListDowntimeSchedulesParams,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<ListDowntimeSchedules200>({
|
||||
url: `/api/v1/downtime_schedules`,
|
||||
method: 'GET',
|
||||
params,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getListDowntimeSchedulesQueryKey = (
|
||||
params?: ListDowntimeSchedulesParams,
|
||||
) => {
|
||||
return [`/api/v1/downtime_schedules`, ...(params ? [params] : [])] as const;
|
||||
};
|
||||
|
||||
export const getListDowntimeSchedulesQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof listDowntimeSchedules>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
params?: ListDowntimeSchedulesParams,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listDowntimeSchedules>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ?? getListDowntimeSchedulesQueryKey(params);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof listDowntimeSchedules>>
|
||||
> = ({ signal }) => listDowntimeSchedules(params, signal);
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listDowntimeSchedules>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type ListDowntimeSchedulesQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof listDowntimeSchedules>>
|
||||
>;
|
||||
export type ListDowntimeSchedulesQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary List downtime schedules
|
||||
*/
|
||||
|
||||
export function useListDowntimeSchedules<
|
||||
TData = Awaited<ReturnType<typeof listDowntimeSchedules>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
params?: ListDowntimeSchedulesParams,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listDowntimeSchedules>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getListDowntimeSchedulesQueryOptions(params, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary List downtime schedules
|
||||
*/
|
||||
export const invalidateListDowntimeSchedules = async (
|
||||
queryClient: QueryClient,
|
||||
params?: ListDowntimeSchedulesParams,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getListDowntimeSchedulesQueryKey(params) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint creates a new planned maintenance / downtime schedule
|
||||
* @summary Create downtime schedule
|
||||
*/
|
||||
export const createDowntimeSchedule = (
|
||||
ruletypesGettablePlannedMaintenanceDTO: BodyType<RuletypesGettablePlannedMaintenanceDTO>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v1/downtime_schedules`,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesGettablePlannedMaintenanceDTO,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getCreateDowntimeScheduleMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createDowntimeSchedule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesGettablePlannedMaintenanceDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createDowntimeSchedule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesGettablePlannedMaintenanceDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['createDowntimeSchedule'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof createDowntimeSchedule>>,
|
||||
{ data: BodyType<RuletypesGettablePlannedMaintenanceDTO> }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return createDowntimeSchedule(data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type CreateDowntimeScheduleMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof createDowntimeSchedule>>
|
||||
>;
|
||||
export type CreateDowntimeScheduleMutationBody = BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
export type CreateDowntimeScheduleMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Create downtime schedule
|
||||
*/
|
||||
export const useCreateDowntimeSchedule = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createDowntimeSchedule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesGettablePlannedMaintenanceDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof createDowntimeSchedule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesGettablePlannedMaintenanceDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getCreateDowntimeScheduleMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint deletes a downtime schedule by ID
|
||||
* @summary Delete downtime schedule
|
||||
*/
|
||||
export const deleteDowntimeScheduleByID = ({
|
||||
id,
|
||||
}: DeleteDowntimeScheduleByIDPathParameters) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v1/downtime_schedules/${id}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
};
|
||||
|
||||
export const getDeleteDowntimeScheduleByIDMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof deleteDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteDowntimeScheduleByIDPathParameters },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof deleteDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteDowntimeScheduleByIDPathParameters },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['deleteDowntimeScheduleByID'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof deleteDowntimeScheduleByID>>,
|
||||
{ pathParams: DeleteDowntimeScheduleByIDPathParameters }
|
||||
> = (props) => {
|
||||
const { pathParams } = props ?? {};
|
||||
|
||||
return deleteDowntimeScheduleByID(pathParams);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type DeleteDowntimeScheduleByIDMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof deleteDowntimeScheduleByID>>
|
||||
>;
|
||||
|
||||
export type DeleteDowntimeScheduleByIDMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Delete downtime schedule
|
||||
*/
|
||||
export const useDeleteDowntimeScheduleByID = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof deleteDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteDowntimeScheduleByIDPathParameters },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof deleteDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteDowntimeScheduleByIDPathParameters },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getDeleteDowntimeScheduleByIDMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns a downtime schedule by ID
|
||||
* @summary Get downtime schedule by ID
|
||||
*/
|
||||
export const getDowntimeScheduleByID = (
|
||||
{ id }: GetDowntimeScheduleByIDPathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetDowntimeScheduleByID200>({
|
||||
url: `/api/v1/downtime_schedules/${id}`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetDowntimeScheduleByIDQueryKey = ({
|
||||
id,
|
||||
}: GetDowntimeScheduleByIDPathParameters) => {
|
||||
return [`/api/v1/downtime_schedules/${id}`] as const;
|
||||
};
|
||||
|
||||
export const getGetDowntimeScheduleByIDQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getDowntimeScheduleByID>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetDowntimeScheduleByIDPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getDowntimeScheduleByID>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ?? getGetDowntimeScheduleByIDQueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof getDowntimeScheduleByID>>
|
||||
> = ({ signal }) => getDowntimeScheduleByID({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getDowntimeScheduleByID>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetDowntimeScheduleByIDQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getDowntimeScheduleByID>>
|
||||
>;
|
||||
export type GetDowntimeScheduleByIDQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get downtime schedule by ID
|
||||
*/
|
||||
|
||||
export function useGetDowntimeScheduleByID<
|
||||
TData = Awaited<ReturnType<typeof getDowntimeScheduleByID>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetDowntimeScheduleByIDPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getDowntimeScheduleByID>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetDowntimeScheduleByIDQueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get downtime schedule by ID
|
||||
*/
|
||||
export const invalidateGetDowntimeScheduleByID = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetDowntimeScheduleByIDPathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetDowntimeScheduleByIDQueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint updates a downtime schedule by ID
|
||||
* @summary Update downtime schedule
|
||||
*/
|
||||
export const updateDowntimeScheduleByID = (
|
||||
{ id }: UpdateDowntimeScheduleByIDPathParameters,
|
||||
ruletypesGettablePlannedMaintenanceDTO: BodyType<RuletypesGettablePlannedMaintenanceDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v1/downtime_schedules/${id}`,
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesGettablePlannedMaintenanceDTO,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUpdateDowntimeScheduleByIDMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateDowntimeScheduleByIDPathParameters;
|
||||
data: BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateDowntimeScheduleByIDPathParameters;
|
||||
data: BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['updateDowntimeScheduleByID'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof updateDowntimeScheduleByID>>,
|
||||
{
|
||||
pathParams: UpdateDowntimeScheduleByIDPathParameters;
|
||||
data: BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { pathParams, data } = props ?? {};
|
||||
|
||||
return updateDowntimeScheduleByID(pathParams, data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateDowntimeScheduleByIDMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof updateDowntimeScheduleByID>>
|
||||
>;
|
||||
export type UpdateDowntimeScheduleByIDMutationBody = BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
export type UpdateDowntimeScheduleByIDMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Update downtime schedule
|
||||
*/
|
||||
export const useUpdateDowntimeScheduleByID = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateDowntimeScheduleByIDPathParameters;
|
||||
data: BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof updateDowntimeScheduleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateDowntimeScheduleByIDPathParameters;
|
||||
data: BodyType<RuletypesGettablePlannedMaintenanceDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getUpdateDowntimeScheduleByIDMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
@@ -6,17 +6,24 @@
|
||||
*/
|
||||
import type {
|
||||
InvalidateOptions,
|
||||
MutationFunction,
|
||||
QueryClient,
|
||||
QueryFunction,
|
||||
QueryKey,
|
||||
UseMutationOptions,
|
||||
UseMutationResult,
|
||||
UseQueryOptions,
|
||||
UseQueryResult,
|
||||
} from 'react-query';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useMutation, useQuery } from 'react-query';
|
||||
|
||||
import type { ErrorType } from '../../../generatedAPIInstance';
|
||||
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
|
||||
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
|
||||
import type {
|
||||
CreateRule200,
|
||||
DeleteRuleByIDPathParameters,
|
||||
GetRuleByID200,
|
||||
GetRuleByIDPathParameters,
|
||||
GetRuleHistoryFilterKeys200,
|
||||
GetRuleHistoryFilterKeysParams,
|
||||
GetRuleHistoryFilterKeysPathParameters,
|
||||
@@ -35,9 +42,717 @@ import type {
|
||||
GetRuleHistoryTopContributors200,
|
||||
GetRuleHistoryTopContributorsParams,
|
||||
GetRuleHistoryTopContributorsPathParameters,
|
||||
ListRules200,
|
||||
PatchRuleByID200,
|
||||
PatchRuleByIDPathParameters,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
TestRule200,
|
||||
TestRuleDeprecated200,
|
||||
UpdateRuleByIDPathParameters,
|
||||
} from '../sigNoz.schemas';
|
||||
|
||||
/**
|
||||
* This endpoint lists all alert rules with their current evaluation state
|
||||
* @summary List alert rules
|
||||
*/
|
||||
export const listRules = (signal?: AbortSignal) => {
|
||||
return GeneratedAPIInstance<ListRules200>({
|
||||
url: `/api/v1/rules`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getListRulesQueryKey = () => {
|
||||
return [`/api/v1/rules`] as const;
|
||||
};
|
||||
|
||||
export const getListRulesQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof listRules>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<Awaited<ReturnType<typeof listRules>>, TError, TData>;
|
||||
}) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getListRulesQueryKey();
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof listRules>>> = ({
|
||||
signal,
|
||||
}) => listRules(signal);
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listRules>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type ListRulesQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof listRules>>
|
||||
>;
|
||||
export type ListRulesQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary List alert rules
|
||||
*/
|
||||
|
||||
export function useListRules<
|
||||
TData = Awaited<ReturnType<typeof listRules>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<Awaited<ReturnType<typeof listRules>>, TError, TData>;
|
||||
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getListRulesQueryOptions(options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary List alert rules
|
||||
*/
|
||||
export const invalidateListRules = async (
|
||||
queryClient: QueryClient,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getListRulesQueryKey() },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint creates a new alert rule
|
||||
* @summary Create alert rule
|
||||
*/
|
||||
export const createRule = (
|
||||
ruletypesPostableRuleDTO: BodyType<RuletypesPostableRuleDTO>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<CreateRule200>({
|
||||
url: `/api/v1/rules`,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesPostableRuleDTO,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getCreateRuleMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['createRule'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof createRule>>,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return createRule(data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type CreateRuleMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof createRule>>
|
||||
>;
|
||||
export type CreateRuleMutationBody = BodyType<RuletypesPostableRuleDTO>;
|
||||
export type CreateRuleMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Create alert rule
|
||||
*/
|
||||
export const useCreateRule = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof createRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getCreateRuleMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint deletes an alert rule by ID
|
||||
* @summary Delete alert rule
|
||||
*/
|
||||
export const deleteRuleByID = ({ id }: DeleteRuleByIDPathParameters) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v1/rules/${id}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
};
|
||||
|
||||
export const getDeleteRuleByIDMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof deleteRuleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteRuleByIDPathParameters },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof deleteRuleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteRuleByIDPathParameters },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['deleteRuleByID'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof deleteRuleByID>>,
|
||||
{ pathParams: DeleteRuleByIDPathParameters }
|
||||
> = (props) => {
|
||||
const { pathParams } = props ?? {};
|
||||
|
||||
return deleteRuleByID(pathParams);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type DeleteRuleByIDMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof deleteRuleByID>>
|
||||
>;
|
||||
|
||||
export type DeleteRuleByIDMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Delete alert rule
|
||||
*/
|
||||
export const useDeleteRuleByID = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof deleteRuleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteRuleByIDPathParameters },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof deleteRuleByID>>,
|
||||
TError,
|
||||
{ pathParams: DeleteRuleByIDPathParameters },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getDeleteRuleByIDMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns an alert rule by ID
|
||||
* @summary Get alert rule by ID
|
||||
*/
|
||||
export const getRuleByID = (
|
||||
{ id }: GetRuleByIDPathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetRuleByID200>({
|
||||
url: `/api/v1/rules/${id}`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetRuleByIDQueryKey = ({ id }: GetRuleByIDPathParameters) => {
|
||||
return [`/api/v1/rules/${id}`] as const;
|
||||
};
|
||||
|
||||
export const getGetRuleByIDQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getRuleByID>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetRuleByIDPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getRuleByID>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getGetRuleByIDQueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof getRuleByID>>> = ({
|
||||
signal,
|
||||
}) => getRuleByID({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getRuleByID>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetRuleByIDQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getRuleByID>>
|
||||
>;
|
||||
export type GetRuleByIDQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get alert rule by ID
|
||||
*/
|
||||
|
||||
export function useGetRuleByID<
|
||||
TData = Awaited<ReturnType<typeof getRuleByID>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetRuleByIDPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getRuleByID>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetRuleByIDQueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get alert rule by ID
|
||||
*/
|
||||
export const invalidateGetRuleByID = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetRuleByIDPathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetRuleByIDQueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint applies a partial update to an alert rule by ID
|
||||
* @summary Patch alert rule
|
||||
*/
|
||||
export const patchRuleByID = (
|
||||
{ id }: PatchRuleByIDPathParameters,
|
||||
ruletypesPostableRuleDTO: BodyType<RuletypesPostableRuleDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<PatchRuleByID200>({
|
||||
url: `/api/v1/rules/${id}`,
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesPostableRuleDTO,
|
||||
});
|
||||
};
|
||||
|
||||
export const getPatchRuleByIDMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof patchRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof patchRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['patchRuleByID'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof patchRuleByID>>,
|
||||
{
|
||||
pathParams: PatchRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { pathParams, data } = props ?? {};
|
||||
|
||||
return patchRuleByID(pathParams, data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type PatchRuleByIDMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof patchRuleByID>>
|
||||
>;
|
||||
export type PatchRuleByIDMutationBody = BodyType<RuletypesPostableRuleDTO>;
|
||||
export type PatchRuleByIDMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Patch alert rule
|
||||
*/
|
||||
export const usePatchRuleByID = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof patchRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof patchRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getPatchRuleByIDMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint updates an alert rule by ID
|
||||
* @summary Update alert rule
|
||||
*/
|
||||
export const updateRuleByID = (
|
||||
{ id }: UpdateRuleByIDPathParameters,
|
||||
ruletypesPostableRuleDTO: BodyType<RuletypesPostableRuleDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v1/rules/${id}`,
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesPostableRuleDTO,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUpdateRuleByIDMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['updateRuleByID'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof updateRuleByID>>,
|
||||
{
|
||||
pathParams: UpdateRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { pathParams, data } = props ?? {};
|
||||
|
||||
return updateRuleByID(pathParams, data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateRuleByIDMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof updateRuleByID>>
|
||||
>;
|
||||
export type UpdateRuleByIDMutationBody = BodyType<RuletypesPostableRuleDTO>;
|
||||
export type UpdateRuleByIDMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Update alert rule
|
||||
*/
|
||||
export const useUpdateRuleByID = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof updateRuleByID>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getUpdateRuleByIDMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint fires a test notification for the given rule definition
|
||||
* @summary Test alert rule
|
||||
*/
|
||||
export const testRule = (
|
||||
ruletypesPostableRuleDTO: BodyType<RuletypesPostableRuleDTO>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<TestRule200>({
|
||||
url: `/api/v1/rules/test`,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesPostableRuleDTO,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getTestRuleMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof testRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof testRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['testRule'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof testRule>>,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return testRule(data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type TestRuleMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof testRule>>
|
||||
>;
|
||||
export type TestRuleMutationBody = BodyType<RuletypesPostableRuleDTO>;
|
||||
export type TestRuleMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Test alert rule
|
||||
*/
|
||||
export const useTestRule = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof testRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof testRule>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getTestRuleMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* Deprecated: use /api/v1/rules/test instead
|
||||
* @deprecated
|
||||
* @summary Test alert rule (deprecated)
|
||||
*/
|
||||
export const testRuleDeprecated = (
|
||||
ruletypesPostableRuleDTO: BodyType<RuletypesPostableRuleDTO>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<TestRuleDeprecated200>({
|
||||
url: `/api/v1/testRule`,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: ruletypesPostableRuleDTO,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getTestRuleDeprecatedMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof testRuleDeprecated>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof testRuleDeprecated>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['testRuleDeprecated'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof testRuleDeprecated>>,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return testRuleDeprecated(data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type TestRuleDeprecatedMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof testRuleDeprecated>>
|
||||
>;
|
||||
export type TestRuleDeprecatedMutationBody = BodyType<RuletypesPostableRuleDTO>;
|
||||
export type TestRuleDeprecatedMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @summary Test alert rule (deprecated)
|
||||
*/
|
||||
export const useTestRuleDeprecated = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof testRuleDeprecated>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof testRuleDeprecated>>,
|
||||
TError,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getTestRuleDeprecatedMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* Returns distinct label keys from rule history entries for the selected range.
|
||||
* @summary Get rule history filter keys
|
||||
|
||||
@@ -4529,6 +4529,26 @@ export interface RulestatehistorytypesGettableRuleStateWindowDTO {
|
||||
state: RuletypesAlertStateDTO;
|
||||
}
|
||||
|
||||
export interface RuletypesAlertCompositeQueryDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
panelType?: string;
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
queries?: Querybuildertypesv5QueryEnvelopeDTO[] | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
queryType?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
unit?: string;
|
||||
}
|
||||
|
||||
export enum RuletypesAlertStateDTO {
|
||||
inactive = 'inactive',
|
||||
pending = 'pending',
|
||||
@@ -4537,6 +4557,495 @@ export enum RuletypesAlertStateDTO {
|
||||
nodata = 'nodata',
|
||||
disabled = 'disabled',
|
||||
}
|
||||
export interface RuletypesBasicRuleThresholdDTO {
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
channels?: string[] | null;
|
||||
matchType?: RuletypesMatchTypeDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
name?: string;
|
||||
op?: RuletypesCompareOperatorDTO;
|
||||
/**
|
||||
* @type number
|
||||
* @nullable true
|
||||
*/
|
||||
recoveryTarget?: number | null;
|
||||
/**
|
||||
* @type number
|
||||
* @nullable true
|
||||
*/
|
||||
target?: number | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
targetUnit?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @nullable
|
||||
*/
|
||||
export type RuletypesBasicRuleThresholdsDTO =
|
||||
| RuletypesBasicRuleThresholdDTO[]
|
||||
| null;
|
||||
|
||||
export enum RuletypesCompareOperatorDTO {
|
||||
above = 'above',
|
||||
below = 'below',
|
||||
equal = 'equal',
|
||||
not_equal = 'not_equal',
|
||||
outside_bounds = 'outside_bounds',
|
||||
}
|
||||
export interface RuletypesCumulativeScheduleDTO {
|
||||
/**
|
||||
* @type integer
|
||||
* @nullable true
|
||||
*/
|
||||
day?: number | null;
|
||||
/**
|
||||
* @type integer
|
||||
* @nullable true
|
||||
*/
|
||||
hour?: number | null;
|
||||
/**
|
||||
* @type integer
|
||||
* @nullable true
|
||||
*/
|
||||
minute?: number | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
type?: string;
|
||||
/**
|
||||
* @type integer
|
||||
* @nullable true
|
||||
*/
|
||||
weekday?: number | null;
|
||||
}
|
||||
|
||||
export interface RuletypesCumulativeWindowDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
frequency?: string;
|
||||
schedule?: RuletypesCumulativeScheduleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
timezone?: string;
|
||||
}
|
||||
|
||||
export interface RuletypesEvaluationCumulativeDTO {
|
||||
/**
|
||||
* @type string
|
||||
* @description The kind of evaluation.
|
||||
*/
|
||||
kind?: string;
|
||||
spec?: RuletypesCumulativeWindowDTO;
|
||||
}
|
||||
|
||||
export type RuletypesEvaluationEnvelopeDTO =
|
||||
| (RuletypesEvaluationRollingDTO & {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
kind?: string;
|
||||
spec?: unknown;
|
||||
})
|
||||
| (RuletypesEvaluationCumulativeDTO & {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
kind?: string;
|
||||
spec?: unknown;
|
||||
});
|
||||
|
||||
export interface RuletypesEvaluationRollingDTO {
|
||||
/**
|
||||
* @type string
|
||||
* @description The kind of evaluation.
|
||||
*/
|
||||
kind?: string;
|
||||
spec?: RuletypesRollingWindowDTO;
|
||||
}
|
||||
|
||||
export interface RuletypesGettablePlannedMaintenanceDTO {
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
alertIds?: string[] | null;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
createdAt?: Date;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
createdBy?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
kind?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
name?: string;
|
||||
schedule?: RuletypesScheduleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
updatedAt?: Date;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export type RuletypesGettableRuleDTOAnnotations = { [key: string]: string };
|
||||
|
||||
export type RuletypesGettableRuleDTOLabels = { [key: string]: string };
|
||||
|
||||
export interface RuletypesGettableRuleDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
alert: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
alertType?: string;
|
||||
/**
|
||||
* @type object
|
||||
*/
|
||||
annotations?: RuletypesGettableRuleDTOAnnotations;
|
||||
condition: RuletypesRuleConditionDTO;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
* @nullable true
|
||||
*/
|
||||
createAt?: Date | null;
|
||||
/**
|
||||
* @type string
|
||||
* @nullable true
|
||||
*/
|
||||
createBy?: string | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
evalWindow?: string;
|
||||
evaluation?: RuletypesEvaluationEnvelopeDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
frequency?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* @type object
|
||||
*/
|
||||
labels?: RuletypesGettableRuleDTOLabels;
|
||||
notificationSettings?: RuletypesNotificationSettingsDTO;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
preferredChannels?: string[];
|
||||
ruleType: RuletypesRuleTypeDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
schemaVersion?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
source?: string;
|
||||
state?: RuletypesAlertStateDTO;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
* @nullable true
|
||||
*/
|
||||
updateAt?: Date | null;
|
||||
/**
|
||||
* @type string
|
||||
* @nullable true
|
||||
*/
|
||||
updateBy?: string | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export interface RuletypesGettableRulesDTO {
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
rules?: RuletypesGettableRuleDTO[] | null;
|
||||
}
|
||||
|
||||
export interface RuletypesGettableTestRuleDTO {
|
||||
/**
|
||||
* @type integer
|
||||
*/
|
||||
alertCount?: number;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export enum RuletypesMatchTypeDTO {
|
||||
at_least_once = 'at_least_once',
|
||||
all_the_times = 'all_the_times',
|
||||
on_average = 'on_average',
|
||||
in_total = 'in_total',
|
||||
last = 'last',
|
||||
}
|
||||
export interface RuletypesNotificationSettingsDTO {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
groupBy?: string[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
newGroupEvalDelay?: string;
|
||||
renotify?: RuletypesRenotifyDTO;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
usePolicy?: boolean;
|
||||
}
|
||||
|
||||
export type RuletypesPostableRuleDTOAnnotations = { [key: string]: string };
|
||||
|
||||
export type RuletypesPostableRuleDTOLabels = { [key: string]: string };
|
||||
|
||||
export interface RuletypesPostableRuleDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
alert: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
alertType?: string;
|
||||
/**
|
||||
* @type object
|
||||
*/
|
||||
annotations?: RuletypesPostableRuleDTOAnnotations;
|
||||
condition: RuletypesRuleConditionDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
evalWindow?: string;
|
||||
evaluation?: RuletypesEvaluationEnvelopeDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
frequency?: string;
|
||||
/**
|
||||
* @type object
|
||||
*/
|
||||
labels?: RuletypesPostableRuleDTOLabels;
|
||||
notificationSettings?: RuletypesNotificationSettingsDTO;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
preferredChannels?: string[];
|
||||
ruleType: RuletypesRuleTypeDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
schemaVersion?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
source?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export interface RuletypesRecurrenceDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
duration?: string;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
* @nullable true
|
||||
*/
|
||||
endTime?: Date | null;
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
repeatOn?: string[] | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
repeatType?: string;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
startTime?: Date;
|
||||
}
|
||||
|
||||
export interface RuletypesRenotifyDTO {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
alertStates?: RuletypesAlertStateDTO[];
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
interval?: string;
|
||||
}
|
||||
|
||||
export interface RuletypesRollingWindowDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
evalWindow?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
frequency?: string;
|
||||
}
|
||||
|
||||
export interface RuletypesRuleConditionDTO {
|
||||
/**
|
||||
* @type integer
|
||||
* @minimum 0
|
||||
*/
|
||||
absentFor?: number;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
alertOnAbsent?: boolean;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
algorithm?: string;
|
||||
compositeQuery?: RuletypesAlertCompositeQueryDTO;
|
||||
matchType?: RuletypesMatchTypeDTO;
|
||||
op?: RuletypesCompareOperatorDTO;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
requireMinPoints?: boolean;
|
||||
/**
|
||||
* @type integer
|
||||
*/
|
||||
requiredNumPoints?: number;
|
||||
seasonality?: RuletypesSeasonalityDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
selectedQueryName?: string;
|
||||
/**
|
||||
* @type number
|
||||
* @nullable true
|
||||
*/
|
||||
target?: number | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
targetUnit?: string;
|
||||
thresholds?: RuletypesRuleThresholdDataDTO;
|
||||
}
|
||||
|
||||
export type RuletypesRuleThresholdDataDTO = RuletypesThresholdBasicDTO & {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
kind?: string;
|
||||
spec?: unknown;
|
||||
};
|
||||
|
||||
export enum RuletypesRuleTypeDTO {
|
||||
threshold_rule = 'threshold_rule',
|
||||
promql_rule = 'promql_rule',
|
||||
anomaly_rule = 'anomaly_rule',
|
||||
}
|
||||
export interface RuletypesScheduleDTO {
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
endTime?: Date;
|
||||
recurrence?: RuletypesRecurrenceDTO;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
startTime?: Date;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
timezone?: string;
|
||||
}
|
||||
|
||||
export enum RuletypesSeasonalityDTO {
|
||||
hourly = 'hourly',
|
||||
daily = 'daily',
|
||||
weekly = 'weekly',
|
||||
}
|
||||
export interface RuletypesThresholdBasicDTO {
|
||||
/**
|
||||
* @type string
|
||||
* @description The kind of threshold.
|
||||
*/
|
||||
kind?: string;
|
||||
spec?: RuletypesBasicRuleThresholdsDTO;
|
||||
}
|
||||
|
||||
export interface ServiceaccounttypesGettableFactorAPIKeyDTO {
|
||||
/**
|
||||
* @type string
|
||||
@@ -4837,6 +5346,10 @@ export interface TypesChangePasswordRequestDTO {
|
||||
* @type string
|
||||
*/
|
||||
oldPassword?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
export interface TypesDeprecatedUserDTO {
|
||||
@@ -5200,6 +5713,9 @@ export type AuthzResources200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ChangePasswordPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type ListChannels200 = {
|
||||
/**
|
||||
* @type array
|
||||
@@ -5456,6 +5972,49 @@ export type DeleteAuthDomainPathParameters = {
|
||||
export type UpdateAuthDomainPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type ListDowntimeSchedulesParams = {
|
||||
/**
|
||||
* @type boolean
|
||||
* @nullable true
|
||||
* @description undefined
|
||||
*/
|
||||
active?: boolean | null;
|
||||
/**
|
||||
* @type boolean
|
||||
* @nullable true
|
||||
* @description undefined
|
||||
*/
|
||||
recurring?: boolean | null;
|
||||
};
|
||||
|
||||
export type ListDowntimeSchedules200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data: RuletypesGettablePlannedMaintenanceDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteDowntimeScheduleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetDowntimeScheduleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetDowntimeScheduleByID200 = {
|
||||
data: RuletypesGettablePlannedMaintenanceDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateDowntimeScheduleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type HandleExportRawDataPOSTParams = {
|
||||
/**
|
||||
* @enum csv,jsonl
|
||||
@@ -5597,10 +6156,10 @@ export type GetFieldsValues200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetResetPasswordTokenDeprecatedPathParameters = {
|
||||
export type GetResetPasswordTokenPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetResetPasswordTokenDeprecated200 = {
|
||||
export type GetResetPasswordToken200 = {
|
||||
data: TypesResetPasswordTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
@@ -5783,6 +6342,58 @@ export type UpdateRoutePolicy200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListRules200 = {
|
||||
data: RuletypesGettableRulesDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateRule200 = {
|
||||
data: RuletypesGettableRuleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteRuleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetRuleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetRuleByID200 = {
|
||||
data: RuletypesGettableRuleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type PatchRuleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type PatchRuleByID200 = {
|
||||
data: RuletypesGettableRuleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateRuleByIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type TestRule200 = {
|
||||
data: RuletypesGettableTestRuleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListServiceAccounts200 = {
|
||||
/**
|
||||
* @type array
|
||||
@@ -5890,6 +6501,14 @@ export type GetMyServiceAccount200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type TestRuleDeprecated200 = {
|
||||
data: RuletypesGettableTestRuleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListUsersDeprecated200 = {
|
||||
/**
|
||||
* @type array
|
||||
@@ -6572,28 +7191,6 @@ export type GetUser200 = {
|
||||
export type UpdateUserPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetResetPasswordTokenPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetResetPasswordToken200 = {
|
||||
data: TypesResetPasswordTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateResetPasswordTokenPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type CreateResetPasswordToken201 = {
|
||||
data: TypesResetPasswordTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetRolesByUserIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
@@ -20,15 +20,12 @@ import { useMutation, useQuery } from 'react-query';
|
||||
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
|
||||
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
|
||||
import type {
|
||||
ChangePasswordPathParameters,
|
||||
CreateInvite201,
|
||||
CreateResetPasswordToken201,
|
||||
CreateResetPasswordTokenPathParameters,
|
||||
DeleteUserPathParameters,
|
||||
GetMyUser200,
|
||||
GetMyUserDeprecated200,
|
||||
GetResetPasswordToken200,
|
||||
GetResetPasswordTokenDeprecated200,
|
||||
GetResetPasswordTokenDeprecatedPathParameters,
|
||||
GetResetPasswordTokenPathParameters,
|
||||
GetRolesByUserID200,
|
||||
GetRolesByUserIDPathParameters,
|
||||
@@ -57,35 +54,133 @@ import type {
|
||||
} from '../sigNoz.schemas';
|
||||
|
||||
/**
|
||||
* This endpoint returns the reset password token by id
|
||||
* @deprecated
|
||||
* @summary Get reset password token
|
||||
* This endpoint changes the password by id
|
||||
* @summary Change password
|
||||
*/
|
||||
export const getResetPasswordTokenDeprecated = (
|
||||
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
|
||||
export const changePassword = (
|
||||
{ id }: ChangePasswordPathParameters,
|
||||
typesChangePasswordRequestDTO: BodyType<TypesChangePasswordRequestDTO>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetResetPasswordTokenDeprecated200>({
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v1/changePassword/${id}`,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: typesChangePasswordRequestDTO,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getChangePasswordMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof changePassword>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: ChangePasswordPathParameters;
|
||||
data: BodyType<TypesChangePasswordRequestDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof changePassword>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: ChangePasswordPathParameters;
|
||||
data: BodyType<TypesChangePasswordRequestDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['changePassword'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof changePassword>>,
|
||||
{
|
||||
pathParams: ChangePasswordPathParameters;
|
||||
data: BodyType<TypesChangePasswordRequestDTO>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { pathParams, data } = props ?? {};
|
||||
|
||||
return changePassword(pathParams, data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type ChangePasswordMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof changePassword>>
|
||||
>;
|
||||
export type ChangePasswordMutationBody = BodyType<TypesChangePasswordRequestDTO>;
|
||||
export type ChangePasswordMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Change password
|
||||
*/
|
||||
export const useChangePassword = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof changePassword>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: ChangePasswordPathParameters;
|
||||
data: BodyType<TypesChangePasswordRequestDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof changePassword>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: ChangePasswordPathParameters;
|
||||
data: BodyType<TypesChangePasswordRequestDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getChangePasswordMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns the reset password token by id
|
||||
* @summary Get reset password token
|
||||
*/
|
||||
export const getResetPasswordToken = (
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetResetPasswordToken200>({
|
||||
url: `/api/v1/getResetPasswordToken/${id}`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetResetPasswordTokenDeprecatedQueryKey = ({
|
||||
export const getGetResetPasswordTokenQueryKey = ({
|
||||
id,
|
||||
}: GetResetPasswordTokenDeprecatedPathParameters) => {
|
||||
}: GetResetPasswordTokenPathParameters) => {
|
||||
return [`/api/v1/getResetPasswordToken/${id}`] as const;
|
||||
};
|
||||
|
||||
export const getGetResetPasswordTokenDeprecatedQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
|
||||
export const getGetResetPasswordTokenQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
@@ -94,11 +189,11 @@ export const getGetResetPasswordTokenDeprecatedQueryOptions = <
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ?? getGetResetPasswordTokenDeprecatedQueryKey({ id });
|
||||
queryOptions?.queryKey ?? getGetResetPasswordTokenQueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>
|
||||
> = ({ signal }) => getResetPasswordTokenDeprecated({ id }, signal);
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>
|
||||
> = ({ signal }) => getResetPasswordToken({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
@@ -106,39 +201,35 @@ export const getGetResetPasswordTokenDeprecatedQueryOptions = <
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetResetPasswordTokenDeprecatedQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>
|
||||
export type GetResetPasswordTokenQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>
|
||||
>;
|
||||
export type GetResetPasswordTokenDeprecatedQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
export type GetResetPasswordTokenQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @summary Get reset password token
|
||||
*/
|
||||
|
||||
export function useGetResetPasswordTokenDeprecated<
|
||||
TData = Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
|
||||
export function useGetResetPasswordToken<
|
||||
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetResetPasswordTokenDeprecatedQueryOptions(
|
||||
{ id },
|
||||
options,
|
||||
);
|
||||
const queryOptions = getGetResetPasswordTokenQueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
@@ -150,16 +241,15 @@ export function useGetResetPasswordTokenDeprecated<
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @summary Get reset password token
|
||||
*/
|
||||
export const invalidateGetResetPasswordTokenDeprecated = async (
|
||||
export const invalidateGetResetPasswordToken = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetResetPasswordTokenDeprecatedQueryKey({ id }) },
|
||||
{ queryKey: getGetResetPasswordTokenQueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
@@ -1317,189 +1407,6 @@ export const useUpdateUser = <
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns the existing reset password token for a user.
|
||||
* @summary Get reset password token for a user
|
||||
*/
|
||||
export const getResetPasswordToken = (
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetResetPasswordToken200>({
|
||||
url: `/api/v2/users/${id}/reset_password_tokens`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetResetPasswordTokenQueryKey = ({
|
||||
id,
|
||||
}: GetResetPasswordTokenPathParameters) => {
|
||||
return [`/api/v2/users/${id}/reset_password_tokens`] as const;
|
||||
};
|
||||
|
||||
export const getGetResetPasswordTokenQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ?? getGetResetPasswordTokenQueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>
|
||||
> = ({ signal }) => getResetPasswordToken({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetResetPasswordTokenQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>
|
||||
>;
|
||||
export type GetResetPasswordTokenQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get reset password token for a user
|
||||
*/
|
||||
|
||||
export function useGetResetPasswordToken<
|
||||
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResetPasswordToken>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetResetPasswordTokenQueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get reset password token for a user
|
||||
*/
|
||||
export const invalidateGetResetPasswordToken = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetResetPasswordTokenPathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetResetPasswordTokenQueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint creates or regenerates a reset password token for a user. If a valid token exists, it is returned. If expired, a new one is created.
|
||||
* @summary Create or regenerate reset password token for a user
|
||||
*/
|
||||
export const createResetPasswordToken = ({
|
||||
id,
|
||||
}: CreateResetPasswordTokenPathParameters) => {
|
||||
return GeneratedAPIInstance<CreateResetPasswordToken201>({
|
||||
url: `/api/v2/users/${id}/reset_password_tokens`,
|
||||
method: 'PUT',
|
||||
});
|
||||
};
|
||||
|
||||
export const getCreateResetPasswordTokenMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createResetPasswordToken>>,
|
||||
TError,
|
||||
{ pathParams: CreateResetPasswordTokenPathParameters },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createResetPasswordToken>>,
|
||||
TError,
|
||||
{ pathParams: CreateResetPasswordTokenPathParameters },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['createResetPasswordToken'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof createResetPasswordToken>>,
|
||||
{ pathParams: CreateResetPasswordTokenPathParameters }
|
||||
> = (props) => {
|
||||
const { pathParams } = props ?? {};
|
||||
|
||||
return createResetPasswordToken(pathParams);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type CreateResetPasswordTokenMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof createResetPasswordToken>>
|
||||
>;
|
||||
|
||||
export type CreateResetPasswordTokenMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Create or regenerate reset password token for a user
|
||||
*/
|
||||
export const useCreateResetPasswordToken = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createResetPasswordToken>>,
|
||||
TError,
|
||||
{ pathParams: CreateResetPasswordTokenPathParameters },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof createResetPasswordToken>>,
|
||||
TError,
|
||||
{ pathParams: CreateResetPasswordTokenPathParameters },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getCreateResetPasswordTokenMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns the user roles by user id
|
||||
* @summary Get user roles
|
||||
@@ -1943,84 +1850,3 @@ export const useUpdateMyUserV2 = <
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint updates the password of the user I belong to
|
||||
* @summary Updates my password
|
||||
*/
|
||||
export const updateMyPassword = (
|
||||
typesChangePasswordRequestDTO: BodyType<TypesChangePasswordRequestDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v2/users/me/factor_password`,
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: typesChangePasswordRequestDTO,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUpdateMyPasswordMutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateMyPassword>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesChangePasswordRequestDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateMyPassword>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesChangePasswordRequestDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['updateMyPassword'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof updateMyPassword>>,
|
||||
{ data: BodyType<TypesChangePasswordRequestDTO> }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return updateMyPassword(data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateMyPasswordMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof updateMyPassword>>
|
||||
>;
|
||||
export type UpdateMyPasswordMutationBody = BodyType<TypesChangePasswordRequestDTO>;
|
||||
export type UpdateMyPasswordMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Updates my password
|
||||
*/
|
||||
export const useUpdateMyPassword = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateMyPassword>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesChangePasswordRequestDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof updateMyPassword>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesChangePasswordRequestDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getUpdateMyPasswordMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Dayjs } from 'dayjs';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
|
||||
import { Recurrence } from './getAllDowntimeSchedules';
|
||||
|
||||
export interface DowntimeSchedulePayload {
|
||||
name: string;
|
||||
description?: string;
|
||||
alertIds: string[];
|
||||
schedule: {
|
||||
timezone?: string;
|
||||
startTime?: string | Dayjs;
|
||||
endTime?: string | Dayjs;
|
||||
recurrence?: Recurrence;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PayloadProps {
|
||||
status: string;
|
||||
data: string;
|
||||
}
|
||||
|
||||
const createDowntimeSchedule = async (
|
||||
props: DowntimeSchedulePayload,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post('/downtime_schedules', {
|
||||
...props,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default createDowntimeSchedule;
|
||||
@@ -1,19 +0,0 @@
|
||||
import { useMutation, UseMutationResult } from 'react-query';
|
||||
import axios from 'api';
|
||||
|
||||
export interface DeleteDowntimeScheduleProps {
|
||||
id?: number;
|
||||
}
|
||||
|
||||
export interface DeleteSchedulePayloadProps {
|
||||
status: string;
|
||||
data: string;
|
||||
}
|
||||
|
||||
export const useDeleteDowntimeSchedule = (
|
||||
props: DeleteDowntimeScheduleProps,
|
||||
): UseMutationResult<DeleteSchedulePayloadProps, Error, number> =>
|
||||
useMutation({
|
||||
mutationKey: [props.id],
|
||||
mutationFn: () => axios.delete(`/downtime_schedules/${props.id}`),
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import { useQuery, UseQueryResult } from 'react-query';
|
||||
import axios from 'api';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { Option } from 'container/PlannedDowntime/PlannedDowntimeutils';
|
||||
|
||||
export type Recurrence = {
|
||||
startTime?: string | null;
|
||||
endTime?: string | null;
|
||||
duration?: number | string | null;
|
||||
repeatType?: string | Option | null;
|
||||
repeatOn?: string[] | null;
|
||||
};
|
||||
|
||||
type Schedule = {
|
||||
timezone: string | null;
|
||||
startTime: string | null;
|
||||
endTime: string | null;
|
||||
recurrence: Recurrence | null;
|
||||
};
|
||||
|
||||
export interface DowntimeSchedules {
|
||||
id: number;
|
||||
name: string | null;
|
||||
description: string | null;
|
||||
schedule: Schedule | null;
|
||||
alertIds: string[] | null;
|
||||
createdAt: string | null;
|
||||
createdBy: string | null;
|
||||
updatedAt: string | null;
|
||||
updatedBy: string | null;
|
||||
kind: string | null;
|
||||
}
|
||||
export type PayloadProps = { data: DowntimeSchedules[] };
|
||||
|
||||
export const getAllDowntimeSchedules = async (
|
||||
props?: GetAllDowntimeSchedulesPayloadProps,
|
||||
): Promise<AxiosResponse<PayloadProps>> =>
|
||||
axios.get('/downtime_schedules', { params: props });
|
||||
|
||||
export interface GetAllDowntimeSchedulesPayloadProps {
|
||||
active?: boolean;
|
||||
recurrence?: boolean;
|
||||
}
|
||||
|
||||
export const useGetAllDowntimeSchedules = (
|
||||
props?: GetAllDowntimeSchedulesPayloadProps,
|
||||
): UseQueryResult<AxiosResponse<PayloadProps>, AxiosError> =>
|
||||
useQuery<AxiosResponse<PayloadProps>, AxiosError>({
|
||||
queryKey: ['getAllDowntimeSchedules', props],
|
||||
queryFn: () => getAllDowntimeSchedules(props),
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
|
||||
import { DowntimeSchedulePayload } from './createDowntimeSchedule';
|
||||
|
||||
export interface DowntimeScheduleUpdatePayload {
|
||||
data: DowntimeSchedulePayload;
|
||||
id?: number;
|
||||
}
|
||||
|
||||
export interface PayloadProps {
|
||||
status: string;
|
||||
data: string;
|
||||
}
|
||||
|
||||
const updateDowntimeSchedule = async (
|
||||
props: DowntimeScheduleUpdatePayload,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.put(`/downtime_schedules/${props.id}`, {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default updateDowntimeSchedule;
|
||||
27
frontend/src/api/v1/factor_password/changeMyPassword.ts
Normal file
27
frontend/src/api/v1/factor_password/changeMyPassword.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/user/changeMyPassword';
|
||||
|
||||
const changeMyPassword = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponseV2<PayloadProps>> => {
|
||||
try {
|
||||
const response = await axios.post<PayloadProps>(
|
||||
`/changePassword/${props.userId}`,
|
||||
{
|
||||
...props,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
httpStatusCode: response.status,
|
||||
data: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
|
||||
}
|
||||
};
|
||||
|
||||
export default changeMyPassword;
|
||||
28
frontend/src/api/v1/factor_password/getResetPasswordToken.ts
Normal file
28
frontend/src/api/v1/factor_password/getResetPasswordToken.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
|
||||
import {
|
||||
GetResetPasswordToken,
|
||||
PayloadProps,
|
||||
Props,
|
||||
} from 'types/api/user/getResetPasswordToken';
|
||||
|
||||
const getResetPasswordToken = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponseV2<GetResetPasswordToken>> => {
|
||||
try {
|
||||
const response = await axios.get<PayloadProps>(
|
||||
`/getResetPasswordToken/${props.userId}`,
|
||||
);
|
||||
|
||||
return {
|
||||
httpStatusCode: response.status,
|
||||
data: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
|
||||
}
|
||||
};
|
||||
|
||||
export default getResetPasswordToken;
|
||||
@@ -10,9 +10,8 @@ import { Skeleton, Tooltip } from 'antd';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import type { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import {
|
||||
useCreateResetPasswordToken,
|
||||
getResetPasswordToken,
|
||||
useDeleteUser,
|
||||
useGetResetPasswordToken,
|
||||
useGetUser,
|
||||
useUpdateMyUserV2,
|
||||
useUpdateUser,
|
||||
@@ -56,27 +55,6 @@ function getDeleteTooltip(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getInviteButtonLabel(
|
||||
isLoading: boolean,
|
||||
existingToken: { expiresAt?: Date } | undefined,
|
||||
isExpired: boolean,
|
||||
notFound: boolean,
|
||||
): string {
|
||||
if (isLoading) {
|
||||
return 'Checking invite...';
|
||||
}
|
||||
if (existingToken && !isExpired) {
|
||||
return 'Copy Invite Link';
|
||||
}
|
||||
if (isExpired) {
|
||||
return 'Regenerate Invite Link';
|
||||
}
|
||||
if (notFound) {
|
||||
return 'Generate Invite Link';
|
||||
}
|
||||
return 'Copy Invite Link';
|
||||
}
|
||||
|
||||
function toSaveApiError(err: unknown): APIError {
|
||||
return (
|
||||
convertToApiError(err as AxiosError<RenderErrorResponseDTO>) ??
|
||||
@@ -105,11 +83,9 @@ function EditMemberDrawer({
|
||||
const [localRole, setLocalRole] = useState('');
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [saveErrors, setSaveErrors] = useState<SaveError[]>([]);
|
||||
const [isGeneratingLink, setIsGeneratingLink] = useState(false);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [resetLink, setResetLink] = useState<string | null>(null);
|
||||
const [resetLinkExpiresAt, setResetLinkExpiresAt] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
const [showResetLinkDialog, setShowResetLinkDialog] = useState(false);
|
||||
const [hasCopiedResetLink, setHasCopiedResetLink] = useState(false);
|
||||
const [linkType, setLinkType] = useState<'invite' | 'reset' | null>(null);
|
||||
@@ -145,27 +121,6 @@ function EditMemberDrawer({
|
||||
applyDiff,
|
||||
} = useMemberRoleManager(member?.id ?? '', open && !!member?.id);
|
||||
|
||||
// Token status query for invited users
|
||||
const {
|
||||
data: tokenQueryData,
|
||||
isLoading: isLoadingTokenStatus,
|
||||
isError: tokenNotFound,
|
||||
} = useGetResetPasswordToken(
|
||||
{ id: member?.id ?? '' },
|
||||
{ query: { enabled: open && !!member?.id && isInvited } },
|
||||
);
|
||||
|
||||
const existingToken = tokenQueryData?.data;
|
||||
const isTokenExpired =
|
||||
existingToken != null &&
|
||||
new Date(String(existingToken.expiresAt)) < new Date();
|
||||
|
||||
// Create/regenerate token mutation
|
||||
const {
|
||||
mutateAsync: createTokenMutation,
|
||||
isLoading: isGeneratingLink,
|
||||
} = useCreateResetPasswordToken();
|
||||
|
||||
const fetchedDisplayName =
|
||||
fetchedUser?.data?.displayName ?? member?.name ?? '';
|
||||
const fetchedUserId = fetchedUser?.data?.id;
|
||||
@@ -383,21 +338,12 @@ function EditMemberDrawer({
|
||||
if (!member) {
|
||||
return;
|
||||
}
|
||||
setIsGeneratingLink(true);
|
||||
try {
|
||||
const response = await createTokenMutation({
|
||||
pathParams: { id: member.id },
|
||||
});
|
||||
const response = await getResetPasswordToken({ id: member.id });
|
||||
if (response?.data?.token) {
|
||||
const link = `${window.location.origin}/password-reset?token=${response.data.token}`;
|
||||
setResetLink(link);
|
||||
setResetLinkExpiresAt(
|
||||
response.data.expiresAt
|
||||
? formatTimezoneAdjustedTimestamp(
|
||||
String(response.data.expiresAt),
|
||||
DATE_TIME_FORMATS.DASH_DATETIME,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
setHasCopiedResetLink(false);
|
||||
setLinkType(isInvited ? 'invite' : 'reset');
|
||||
setShowResetLinkDialog(true);
|
||||
@@ -413,8 +359,10 @@ function EditMemberDrawer({
|
||||
err as AxiosError<RenderErrorResponseDTO, unknown> | null,
|
||||
);
|
||||
showErrorModal(errMsg as APIError);
|
||||
} finally {
|
||||
setIsGeneratingLink(false);
|
||||
}
|
||||
}, [member, isInvited, onClose, showErrorModal, createTokenMutation]);
|
||||
}, [member, isInvited, onClose, showErrorModal]);
|
||||
|
||||
const [copyState, copyToClipboard] = useCopyToClipboard();
|
||||
const handleCopyResetLink = useCallback((): void => {
|
||||
@@ -620,19 +568,12 @@ function EditMemberDrawer({
|
||||
<Button
|
||||
className="edit-member-drawer__footer-btn edit-member-drawer__footer-btn--warning"
|
||||
onClick={handleGenerateResetLink}
|
||||
disabled={isGeneratingLink || isRootUser || isLoadingTokenStatus}
|
||||
disabled={isGeneratingLink || isRootUser}
|
||||
>
|
||||
<RefreshCw size={12} />
|
||||
{isGeneratingLink
|
||||
? 'Generating...'
|
||||
: isInvited
|
||||
? getInviteButtonLabel(
|
||||
isLoadingTokenStatus,
|
||||
existingToken,
|
||||
isTokenExpired,
|
||||
tokenNotFound,
|
||||
)
|
||||
: 'Generate Password Reset Link'}
|
||||
{isGeneratingLink && 'Generating...'}
|
||||
{!isGeneratingLink && isInvited && 'Copy Invite Link'}
|
||||
{!isGeneratingLink && !isInvited && 'Generate Password Reset Link'}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
@@ -682,7 +623,6 @@ function EditMemberDrawer({
|
||||
open={showResetLinkDialog}
|
||||
linkType={linkType}
|
||||
resetLink={resetLink}
|
||||
expiresAt={resetLinkExpiresAt}
|
||||
hasCopied={hasCopiedResetLink}
|
||||
onClose={(): void => {
|
||||
setShowResetLinkDialog(false);
|
||||
|
||||
@@ -6,7 +6,6 @@ interface ResetLinkDialogProps {
|
||||
open: boolean;
|
||||
linkType: 'invite' | 'reset' | null;
|
||||
resetLink: string | null;
|
||||
expiresAt: string | null;
|
||||
hasCopied: boolean;
|
||||
onClose: () => void;
|
||||
onCopy: () => void;
|
||||
@@ -16,7 +15,6 @@ function ResetLinkDialog({
|
||||
open,
|
||||
linkType,
|
||||
resetLink,
|
||||
expiresAt,
|
||||
hasCopied,
|
||||
onClose,
|
||||
onCopy,
|
||||
@@ -55,11 +53,6 @@ function ResetLinkDialog({
|
||||
{hasCopied ? 'Copied!' : 'Copy'}
|
||||
</Button>
|
||||
</div>
|
||||
{expiresAt && (
|
||||
<p className="reset-link-dialog__description">
|
||||
This link expires on {expiresAt}.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</DialogWrapper>
|
||||
);
|
||||
|
||||
@@ -2,9 +2,8 @@ import type { ReactNode } from 'react';
|
||||
import { toast } from '@signozhq/sonner';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import {
|
||||
useCreateResetPasswordToken,
|
||||
getResetPasswordToken,
|
||||
useDeleteUser,
|
||||
useGetResetPasswordToken,
|
||||
useGetUser,
|
||||
useSetRoleByUserID,
|
||||
useUpdateMyUserV2,
|
||||
@@ -56,8 +55,7 @@ jest.mock('api/generated/services/users', () => ({
|
||||
useUpdateUser: jest.fn(),
|
||||
useUpdateMyUserV2: jest.fn(),
|
||||
useSetRoleByUserID: jest.fn(),
|
||||
useGetResetPasswordToken: jest.fn(),
|
||||
useCreateResetPasswordToken: jest.fn(),
|
||||
getResetPasswordToken: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('api/ErrorResponseHandlerForGeneratedAPIs', () => ({
|
||||
@@ -84,7 +82,7 @@ jest.mock('react-use', () => ({
|
||||
const ROLES_ENDPOINT = '*/api/v1/roles';
|
||||
|
||||
const mockDeleteMutate = jest.fn();
|
||||
const mockCreateTokenMutateAsync = jest.fn();
|
||||
const mockGetResetPasswordToken = jest.mocked(getResetPasswordToken);
|
||||
|
||||
const showErrorModal = jest.fn();
|
||||
jest.mock('providers/ErrorModalProvider', () => ({
|
||||
@@ -186,31 +184,6 @@ describe('EditMemberDrawer', () => {
|
||||
mutate: mockDeleteMutate,
|
||||
isLoading: false,
|
||||
});
|
||||
// Token query: valid token for invited members
|
||||
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
|
||||
data: {
|
||||
data: {
|
||||
token: 'invite-tok-valid',
|
||||
id: 'token-1',
|
||||
expiresAt: new Date(Date.now() + 86400000).toISOString(),
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
// Create token mutation
|
||||
mockCreateTokenMutateAsync.mockResolvedValue({
|
||||
status: 'success',
|
||||
data: {
|
||||
token: 'reset-tok-abc',
|
||||
id: 'user-1',
|
||||
expiresAt: new Date(Date.now() + 86400000).toISOString(),
|
||||
},
|
||||
});
|
||||
(useCreateResetPasswordToken as jest.Mock).mockReturnValue({
|
||||
mutateAsync: mockCreateTokenMutateAsync,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -384,40 +357,6 @@ describe('EditMemberDrawer', () => {
|
||||
expect(screen.queryByText('Last Modified')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows "Regenerate Invite Link" when token is expired', () => {
|
||||
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
|
||||
data: {
|
||||
data: {
|
||||
token: 'old-tok',
|
||||
id: 'token-1',
|
||||
expiresAt: new Date(Date.now() - 86400000).toISOString(), // expired yesterday
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
renderDrawer({ member: invitedMember });
|
||||
|
||||
expect(
|
||||
screen.getByRole('button', { name: /regenerate invite link/i }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows "Generate Invite Link" when no token exists', () => {
|
||||
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
isError: true,
|
||||
});
|
||||
|
||||
renderDrawer({ member: invitedMember });
|
||||
|
||||
expect(
|
||||
screen.getByRole('button', { name: /generate invite link/i }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls deleteUser after confirming revoke invite for invited members', async () => {
|
||||
const onComplete = jest.fn();
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
@@ -670,7 +609,7 @@ describe('EditMemberDrawer', () => {
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not call createResetPasswordToken when Reset Link is clicked while disabled (root)', async () => {
|
||||
it('does not call getResetPasswordToken when Reset Link is clicked while disabled (root)', async () => {
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
renderDrawer();
|
||||
|
||||
@@ -678,16 +617,20 @@ describe('EditMemberDrawer', () => {
|
||||
screen.getByRole('button', { name: /generate password reset link/i }),
|
||||
);
|
||||
|
||||
expect(mockCreateTokenMutateAsync).not.toHaveBeenCalled();
|
||||
expect(mockGetResetPasswordToken).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generate Password Reset Link', () => {
|
||||
beforeEach(() => {
|
||||
mockCopyToClipboard.mockClear();
|
||||
mockGetResetPasswordToken.mockResolvedValue({
|
||||
status: 'success',
|
||||
data: { token: 'reset-tok-abc', id: 'user-1' },
|
||||
});
|
||||
});
|
||||
|
||||
it('calls POST and opens the reset link dialog with the generated link and expiry', async () => {
|
||||
it('calls getResetPasswordToken and opens the reset link dialog with the generated link', async () => {
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
|
||||
renderDrawer();
|
||||
@@ -699,12 +642,11 @@ describe('EditMemberDrawer', () => {
|
||||
const dialog = await screen.findByRole('dialog', {
|
||||
name: /password reset link/i,
|
||||
});
|
||||
expect(mockCreateTokenMutateAsync).toHaveBeenCalledWith({
|
||||
pathParams: { id: 'user-1' },
|
||||
expect(mockGetResetPasswordToken).toHaveBeenCalledWith({
|
||||
id: 'user-1',
|
||||
});
|
||||
expect(dialog).toBeInTheDocument();
|
||||
expect(dialog).toHaveTextContent('reset-tok-abc');
|
||||
expect(dialog).toHaveTextContent(/this link expires on/i);
|
||||
});
|
||||
|
||||
it('copies the link to clipboard and shows "Copied!" on the button', async () => {
|
||||
|
||||
@@ -6,9 +6,7 @@ import { getCreateAlertLocalStateFromAlertDef } from 'container/CreateAlertV2/ut
|
||||
import * as useSafeNavigateHook from 'hooks/useSafeNavigate';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
|
||||
import * as useCreateAlertRuleHook from '../../../../hooks/alerts/useCreateAlertRule';
|
||||
import * as useTestAlertRuleHook from '../../../../hooks/alerts/useTestAlertRule';
|
||||
import * as useUpdateAlertRuleHook from '../../../../hooks/alerts/useUpdateAlertRule';
|
||||
import * as rulesHook from '../../../../api/generated/services/rules';
|
||||
import { CreateAlertProvider } from '../../context';
|
||||
import CreateAlertHeader from '../CreateAlertHeader';
|
||||
|
||||
@@ -17,15 +15,15 @@ jest.spyOn(useSafeNavigateHook, 'useSafeNavigate').mockReturnValue({
|
||||
safeNavigate: mockSafeNavigate,
|
||||
});
|
||||
|
||||
jest.spyOn(useCreateAlertRuleHook, 'useCreateAlertRule').mockReturnValue({
|
||||
jest.spyOn(rulesHook, 'useCreateRule').mockReturnValue({
|
||||
mutate: jest.fn(),
|
||||
isLoading: false,
|
||||
} as any);
|
||||
jest.spyOn(useTestAlertRuleHook, 'useTestAlertRule').mockReturnValue({
|
||||
jest.spyOn(rulesHook, 'useTestRule').mockReturnValue({
|
||||
mutate: jest.fn(),
|
||||
isLoading: false,
|
||||
} as any);
|
||||
jest.spyOn(useUpdateAlertRuleHook, 'useUpdateAlertRule').mockReturnValue({
|
||||
jest.spyOn(rulesHook, 'useUpdateRuleByID').mockReturnValue({
|
||||
mutate: jest.fn(),
|
||||
isLoading: false,
|
||||
} as any);
|
||||
|
||||
@@ -34,6 +34,7 @@ export const createMockAlertContextState = (
|
||||
isUpdatingAlertRule: false,
|
||||
updateAlertRule: jest.fn(),
|
||||
isEditMode: false,
|
||||
ruleId: '',
|
||||
...overrides,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { toast } from '@signozhq/sonner';
|
||||
import { Button, Tooltip, Typography } from 'antd';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import type {
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import { Check, Loader, Send, X } from 'lucide-react';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import APIError from 'types/api/error';
|
||||
import { isModifierKeyPressed } from 'utils/app';
|
||||
|
||||
import { useCreateAlertState } from '../context';
|
||||
@@ -30,9 +38,11 @@ function Footer(): JSX.Element {
|
||||
updateAlertRule,
|
||||
isUpdatingAlertRule,
|
||||
isEditMode,
|
||||
ruleId,
|
||||
} = useCreateAlertState();
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const handleDiscard = (e: React.MouseEvent): void => {
|
||||
discardAlertRule();
|
||||
@@ -71,20 +81,27 @@ function Footer(): JSX.Element {
|
||||
notificationSettings,
|
||||
query: currentQuery,
|
||||
});
|
||||
testAlertRule(payload, {
|
||||
onSuccess: (response) => {
|
||||
if (response.payload?.data?.alertCount === 0) {
|
||||
toast.error(
|
||||
'No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.',
|
||||
testAlertRule(
|
||||
{ data: (payload as unknown) as RuletypesPostableRuleDTO },
|
||||
{
|
||||
onSuccess: (response) => {
|
||||
if (response.data?.alertCount === 0) {
|
||||
toast.error(
|
||||
'No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
toast.success('Test notification sent successfully');
|
||||
},
|
||||
onError: (error) => {
|
||||
showErrorModal(
|
||||
convertToApiError(
|
||||
error as AxiosError<RenderErrorResponseDTO>,
|
||||
) as APIError,
|
||||
);
|
||||
return;
|
||||
}
|
||||
toast.success('Test notification sent successfully');
|
||||
},
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
);
|
||||
}, [
|
||||
alertType,
|
||||
basicAlertState,
|
||||
@@ -107,25 +124,34 @@ function Footer(): JSX.Element {
|
||||
query: currentQuery,
|
||||
});
|
||||
if (isEditMode) {
|
||||
updateAlertRule(payload, {
|
||||
onSuccess: () => {
|
||||
toast.success('Alert rule updated successfully');
|
||||
safeNavigate('/alerts');
|
||||
updateAlertRule(
|
||||
{
|
||||
pathParams: { id: ruleId },
|
||||
data: (payload as unknown) as RuletypesPostableRuleDTO,
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success('Alert rule updated successfully');
|
||||
safeNavigate('/alerts');
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
} else {
|
||||
createAlertRule(payload, {
|
||||
onSuccess: () => {
|
||||
toast.success('Alert rule created successfully');
|
||||
safeNavigate('/alerts');
|
||||
createAlertRule(
|
||||
{ data: (payload as unknown) as RuletypesPostableRuleDTO },
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success('Alert rule created successfully');
|
||||
safeNavigate('/alerts');
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
}, [
|
||||
alertType,
|
||||
@@ -136,9 +162,11 @@ function Footer(): JSX.Element {
|
||||
notificationSettings,
|
||||
currentQuery,
|
||||
isEditMode,
|
||||
ruleId,
|
||||
updateAlertRule,
|
||||
createAlertRule,
|
||||
safeNavigate,
|
||||
showErrorModal,
|
||||
]);
|
||||
|
||||
const disableButtons =
|
||||
|
||||
@@ -12,6 +12,11 @@ import Footer from '../Footer';
|
||||
jest.mock('hooks/queryBuilder/useQueryBuilder', () => ({
|
||||
useQueryBuilder: jest.fn(),
|
||||
}));
|
||||
jest.mock('providers/ErrorModalProvider', () => ({
|
||||
useErrorModal: (): { showErrorModal: jest.Mock } => ({
|
||||
showErrorModal: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('hooks/useSafeNavigate', () => ({
|
||||
useSafeNavigate: jest.fn(),
|
||||
|
||||
@@ -10,11 +10,13 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import {
|
||||
useCreateRule,
|
||||
useTestRule,
|
||||
useUpdateRuleByID,
|
||||
} from 'api/generated/services/rules';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { AlertDetectionTypes } from 'container/FormAlertRules';
|
||||
import { useCreateAlertRule } from 'hooks/alerts/useCreateAlertRule';
|
||||
import { useTestAlertRule } from 'hooks/alerts/useTestAlertRule';
|
||||
import { useUpdateAlertRule } from 'hooks/alerts/useUpdateAlertRule';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
@@ -215,17 +217,14 @@ export function CreateAlertProvider(
|
||||
const {
|
||||
mutate: createAlertRule,
|
||||
isLoading: isCreatingAlertRule,
|
||||
} = useCreateAlertRule();
|
||||
} = useCreateRule();
|
||||
|
||||
const {
|
||||
mutate: testAlertRule,
|
||||
isLoading: isTestingAlertRule,
|
||||
} = useTestAlertRule();
|
||||
const { mutate: testAlertRule, isLoading: isTestingAlertRule } = useTestRule();
|
||||
|
||||
const {
|
||||
mutate: updateAlertRule,
|
||||
isLoading: isUpdatingAlertRule,
|
||||
} = useUpdateAlertRule(ruleId || '');
|
||||
} = useUpdateRuleByID();
|
||||
|
||||
const contextValue: ICreateAlertContextProps = useMemo(
|
||||
() => ({
|
||||
@@ -249,6 +248,7 @@ export function CreateAlertProvider(
|
||||
updateAlertRule,
|
||||
isUpdatingAlertRule,
|
||||
isEditMode: isEditMode || false,
|
||||
ruleId: ruleId || '',
|
||||
}),
|
||||
[
|
||||
createAlertState,
|
||||
@@ -267,6 +267,7 @@ export function CreateAlertProvider(
|
||||
updateAlertRule,
|
||||
isUpdatingAlertRule,
|
||||
isEditMode,
|
||||
ruleId,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { Dispatch } from 'react';
|
||||
import { UseMutateFunction } from 'react-query';
|
||||
import { CreateAlertRuleResponse } from 'api/alerts/createAlertRule';
|
||||
import { TestAlertRuleResponse } from 'api/alerts/testAlertRule';
|
||||
import { UpdateAlertRuleResponse } from 'api/alerts/updateAlertRule';
|
||||
import type {
|
||||
CreateRule200,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
TestRule200,
|
||||
UpdateRuleByIDPathParameters,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { BodyType, ErrorType } from 'api/generatedAPIInstance';
|
||||
import { Dayjs } from 'dayjs';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
|
||||
import { Labels } from 'types/api/alerts/def';
|
||||
|
||||
export interface ICreateAlertContextProps {
|
||||
@@ -24,27 +27,33 @@ export interface ICreateAlertContextProps {
|
||||
setNotificationSettings: Dispatch<NotificationSettingsAction>;
|
||||
isCreatingAlertRule: boolean;
|
||||
createAlertRule: UseMutateFunction<
|
||||
SuccessResponse<CreateAlertRuleResponse, unknown> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2,
|
||||
CreateRule200,
|
||||
ErrorType<unknown>,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
unknown
|
||||
>;
|
||||
isTestingAlertRule: boolean;
|
||||
testAlertRule: UseMutateFunction<
|
||||
SuccessResponse<TestAlertRuleResponse, unknown> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2,
|
||||
TestRule200,
|
||||
ErrorType<unknown>,
|
||||
{ data: BodyType<RuletypesPostableRuleDTO> },
|
||||
unknown
|
||||
>;
|
||||
discardAlertRule: () => void;
|
||||
isUpdatingAlertRule: boolean;
|
||||
updateAlertRule: UseMutateFunction<
|
||||
SuccessResponse<UpdateAlertRuleResponse, unknown> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2,
|
||||
Awaited<
|
||||
ReturnType<typeof import('api/generated/services/rules').updateRuleByID>
|
||||
>,
|
||||
ErrorType<RenderErrorResponseDTO>,
|
||||
{
|
||||
pathParams: UpdateRuleByIDPathParameters;
|
||||
data: BodyType<RuletypesPostableRuleDTO>;
|
||||
},
|
||||
unknown
|
||||
>;
|
||||
isEditMode: boolean;
|
||||
ruleId: string;
|
||||
}
|
||||
|
||||
export interface ICreateAlertProviderProps {
|
||||
|
||||
@@ -6,9 +6,18 @@ import { useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { ExclamationCircleOutlined, SaveOutlined } from '@ant-design/icons';
|
||||
import { Button, FormInstance, Modal, SelectProps, Typography } from 'antd';
|
||||
import saveAlertApi from 'api/alerts/save';
|
||||
import testAlertApi from 'api/alerts/testAlert';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import {
|
||||
createRule,
|
||||
testRule,
|
||||
updateRuleByID,
|
||||
} from 'api/generated/services/rules';
|
||||
import type {
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { getInvolvedQueriesInTraceOperator } from 'components/QueryBuilderV2/QueryV2/TraceOperator/utils/utils';
|
||||
import YAxisUnitSelector from 'components/YAxisUnitSelector';
|
||||
import { YAxisSource } from 'components/YAxisUnitSelector/types';
|
||||
@@ -32,6 +41,7 @@ import { isEmpty, isEqual } from 'lodash-es';
|
||||
import { BellDot, ExternalLink } from 'lucide-react';
|
||||
import Tabs2 from 'periscope/components/Tabs2';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import {
|
||||
@@ -39,6 +49,7 @@ import {
|
||||
defaultEvalWindow,
|
||||
defaultMatchType,
|
||||
} from 'types/api/alerts/def';
|
||||
import APIError from 'types/api/error';
|
||||
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { QueryFunction } from 'types/api/v5/queryRange';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
@@ -368,6 +379,7 @@ function FormAlertRules({
|
||||
redirectWithQueryBuilderData(query);
|
||||
};
|
||||
const { notifications } = useNotifications();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const validatePromParams = useCallback((): boolean => {
|
||||
let retval = true;
|
||||
@@ -533,59 +545,47 @@ function FormAlertRules({
|
||||
};
|
||||
|
||||
try {
|
||||
const apiReq =
|
||||
ruleId && !isEmpty(ruleId)
|
||||
? { data: postableAlert, id: ruleId }
|
||||
: { data: postableAlert };
|
||||
|
||||
const response = await saveAlertApi(apiReq);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
logData = {
|
||||
status: 'success',
|
||||
statusMessage: isNewRule ? t('rule_created') : t('rule_edited'),
|
||||
};
|
||||
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: logData.statusMessage,
|
||||
});
|
||||
|
||||
// invalidate rule in cache
|
||||
ruleCache.invalidateQueries([
|
||||
REACT_QUERY_KEY.ALERT_RULE_DETAILS,
|
||||
`${ruleId}`,
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
setTimeout(() => {
|
||||
urlQuery.delete(QueryParams.compositeQuery);
|
||||
urlQuery.delete(QueryParams.panelTypes);
|
||||
urlQuery.delete(QueryParams.ruleId);
|
||||
urlQuery.delete(QueryParams.relativeTime);
|
||||
safeNavigate(`${ROUTES.LIST_ALL_ALERT}?${urlQuery.toString()}`);
|
||||
}, 2000);
|
||||
if (ruleId && !isEmpty(ruleId)) {
|
||||
await updateRuleByID(
|
||||
{ id: ruleId },
|
||||
(postableAlert as unknown) as RuletypesPostableRuleDTO,
|
||||
);
|
||||
} else {
|
||||
logData = {
|
||||
status: 'error',
|
||||
statusMessage: response.error || t('unexpected_error'),
|
||||
};
|
||||
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: logData.statusMessage,
|
||||
});
|
||||
await createRule((postableAlert as unknown) as RuletypesPostableRuleDTO);
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
logData = {
|
||||
status: 'error',
|
||||
statusMessage: t('unexpected_error'),
|
||||
status: 'success',
|
||||
statusMessage: isNewRule ? t('rule_created') : t('rule_edited'),
|
||||
};
|
||||
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: logData.statusMessage,
|
||||
});
|
||||
|
||||
// invalidate rule in cache
|
||||
ruleCache.invalidateQueries([
|
||||
REACT_QUERY_KEY.ALERT_RULE_DETAILS,
|
||||
`${ruleId}`,
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
setTimeout(() => {
|
||||
urlQuery.delete(QueryParams.compositeQuery);
|
||||
urlQuery.delete(QueryParams.panelTypes);
|
||||
urlQuery.delete(QueryParams.ruleId);
|
||||
urlQuery.delete(QueryParams.relativeTime);
|
||||
safeNavigate(`${ROUTES.LIST_ALL_ALERT}?${urlQuery.toString()}`);
|
||||
}, 2000);
|
||||
} catch (e) {
|
||||
const apiError = convertToApiError(e as AxiosError<RenderErrorResponseDTO>);
|
||||
logData = {
|
||||
status: 'error',
|
||||
statusMessage: apiError?.getErrorMessage() || t('unexpected_error'),
|
||||
};
|
||||
|
||||
showErrorModal(apiError as APIError);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
@@ -641,39 +641,30 @@ function FormAlertRules({
|
||||
let statusResponse = { status: 'failed', message: '' };
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await testAlertApi({ data: postableAlert });
|
||||
const response = await testRule(
|
||||
(postableAlert as unknown) as RuletypesPostableRuleDTO,
|
||||
);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
const { payload } = response;
|
||||
if (payload?.alertCount === 0) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('no_alerts_found'),
|
||||
});
|
||||
statusResponse = { status: 'failed', message: t('no_alerts_found') };
|
||||
} else {
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: t('rule_test_fired'),
|
||||
});
|
||||
statusResponse = { status: 'success', message: t('rule_test_fired') };
|
||||
}
|
||||
} else {
|
||||
if (response.data?.alertCount === 0) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: response.error || t('unexpected_error'),
|
||||
description: t('no_alerts_found'),
|
||||
});
|
||||
statusResponse = {
|
||||
status: 'failed',
|
||||
message: response.error || t('unexpected_error'),
|
||||
};
|
||||
statusResponse = { status: 'failed', message: t('no_alerts_found') };
|
||||
} else {
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: t('rule_test_fired'),
|
||||
});
|
||||
statusResponse = { status: 'success', message: t('rule_test_fired') };
|
||||
}
|
||||
} catch (e) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('unexpected_error'),
|
||||
});
|
||||
statusResponse = { status: 'failed', message: t('unexpected_error') };
|
||||
const apiError = convertToApiError(e as AxiosError<RenderErrorResponseDTO>);
|
||||
statusResponse = {
|
||||
status: 'failed',
|
||||
message: apiError?.getErrorMessage() || t('unexpected_error'),
|
||||
};
|
||||
showErrorModal(apiError as APIError);
|
||||
}
|
||||
setLoading(false);
|
||||
logEvent('Alert: Test notification', {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Button, Skeleton, Tag } from 'antd';
|
||||
import getAll from 'api/alerts/getAll';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { useListRules } from 'api/generated/services/rules';
|
||||
import type { RuletypesGettableRuleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
@@ -11,7 +11,7 @@ import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/map
|
||||
import { ArrowRight, ArrowUpRight, Plus } from 'lucide-react';
|
||||
import Card from 'periscope/components/Card/Card';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
import type { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
|
||||
import { USER_ROLES } from 'types/roles';
|
||||
|
||||
import beaconUrl from '@/assets/Icons/beacon.svg';
|
||||
@@ -28,22 +28,23 @@ export default function AlertRules({
|
||||
const { user } = useAppContext();
|
||||
const [rulesExist, setRulesExist] = useState(false);
|
||||
|
||||
const [sortedAlertRules, setSortedAlertRules] = useState<GettableAlert[]>([]);
|
||||
const [sortedAlertRules, setSortedAlertRules] = useState<
|
||||
RuletypesGettableRuleDTO[]
|
||||
>([]);
|
||||
|
||||
const location = useLocation();
|
||||
const params = new URLSearchParams(location.search);
|
||||
|
||||
// Fetch Alerts
|
||||
const { data: alerts, isError, isLoading } = useQuery('allAlerts', {
|
||||
queryFn: getAll,
|
||||
cacheTime: 0,
|
||||
const { data: alerts, isError, isLoading } = useListRules({
|
||||
query: { cacheTime: 0 },
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const rules = alerts?.payload || [];
|
||||
const rules = alerts?.data?.rules ?? [];
|
||||
setRulesExist(rules.length > 0);
|
||||
|
||||
const sortedRules = rules.sort((a, b) => {
|
||||
const sortedRules = [...rules].sort((a, b) => {
|
||||
// First, prioritize firing alerts
|
||||
if (a.state === 'firing' && b.state !== 'firing') {
|
||||
return -1;
|
||||
@@ -53,8 +54,8 @@ export default function AlertRules({
|
||||
}
|
||||
|
||||
// Then sort by updateAt timestamp
|
||||
const aUpdateAt = new Date(a.updateAt).getTime();
|
||||
const bUpdateAt = new Date(b.updateAt).getTime();
|
||||
const aUpdateAt = a.updateAt ? new Date(a.updateAt).getTime() : 0;
|
||||
const bUpdateAt = b.updateAt ? new Date(b.updateAt).getTime() : 0;
|
||||
return bUpdateAt - aUpdateAt;
|
||||
});
|
||||
|
||||
@@ -118,22 +119,27 @@ export default function AlertRules({
|
||||
</div>
|
||||
);
|
||||
|
||||
const onEditHandler = (record: GettableAlert) => (): void => {
|
||||
const onEditHandler = (record: RuletypesGettableRuleDTO) => (): void => {
|
||||
logEvent('Homepage: Alert clicked', {
|
||||
ruleId: record.id,
|
||||
ruleName: record.alert,
|
||||
ruleState: record.state,
|
||||
});
|
||||
|
||||
const compositeQuery = mapQueryDataFromApi(record.condition.compositeQuery);
|
||||
const compositeQuery = mapQueryDataFromApi(
|
||||
(record.condition?.compositeQuery as unknown) as ICompositeMetricQuery,
|
||||
);
|
||||
params.set(
|
||||
QueryParams.compositeQuery,
|
||||
encodeURIComponent(JSON.stringify(compositeQuery)),
|
||||
);
|
||||
|
||||
params.set(QueryParams.panelTypes, record.condition.compositeQuery.panelType);
|
||||
const panelType = record.condition?.compositeQuery?.panelType;
|
||||
if (panelType) {
|
||||
params.set(QueryParams.panelTypes, panelType);
|
||||
}
|
||||
|
||||
params.set(QueryParams.ruleId, record.id.toString());
|
||||
params.set(QueryParams.ruleId, record.id ?? '');
|
||||
|
||||
history.push(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`);
|
||||
};
|
||||
@@ -156,7 +162,7 @@ export default function AlertRules({
|
||||
>
|
||||
<div className="alert-rule-item-name-container home-data-item-name-container">
|
||||
<img
|
||||
src={getItemIcon(rule.id)}
|
||||
src={getItemIcon(rule.id ?? '')}
|
||||
alt="alert-rules"
|
||||
className="alert-rules-img"
|
||||
/>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { Dispatch, SetStateAction, useState } from 'react';
|
||||
import type { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import deleteAlerts from 'api/alerts/delete';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { deleteRuleByID } from 'api/generated/services/rules';
|
||||
import type {
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { State } from 'hooks/useFetch';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import { PayloadProps as DeleteAlertPayloadProps } from 'types/api/alerts/delete';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
import APIError from 'types/api/error';
|
||||
|
||||
import { ColumnButton } from './styles';
|
||||
|
||||
@@ -22,48 +29,31 @@ function DeleteAlert({
|
||||
payload: undefined,
|
||||
});
|
||||
|
||||
const defaultErrorMessage = 'Something went wrong';
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const onDeleteHandler = async (id: string): Promise<void> => {
|
||||
try {
|
||||
const response = await deleteAlerts({
|
||||
id,
|
||||
await deleteRuleByID({ id });
|
||||
|
||||
setData((state) => state.filter((alert) => alert.id !== id));
|
||||
|
||||
setDeleteAlertState((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
}));
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
});
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
setData((state) => state.filter((alert) => alert.id !== id));
|
||||
|
||||
setDeleteAlertState((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
payload: response.payload,
|
||||
}));
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
});
|
||||
} else {
|
||||
setDeleteAlertState((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
error: true,
|
||||
errorMessage: response.error || defaultErrorMessage,
|
||||
}));
|
||||
|
||||
notifications.error({
|
||||
message: response.error || defaultErrorMessage,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
setDeleteAlertState((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
error: true,
|
||||
errorMessage: defaultErrorMessage,
|
||||
}));
|
||||
|
||||
notifications.error({
|
||||
message: defaultErrorMessage,
|
||||
});
|
||||
showErrorModal(
|
||||
convertToApiError(error as AxiosError<RenderErrorResponseDTO>) as APIError,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,8 +78,8 @@ function DeleteAlert({
|
||||
}
|
||||
|
||||
interface DeleteAlertProps {
|
||||
id: GettableAlert['id'];
|
||||
setData: Dispatch<SetStateAction<GettableAlert[]>>;
|
||||
id: string;
|
||||
setData: Dispatch<SetStateAction<RuletypesGettableRuleDTO[]>>;
|
||||
notifications: NotificationInstance;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,17 @@ import { UseQueryResult } from 'react-query';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Button, Flex, Input, Typography } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table/interface';
|
||||
import saveAlertApi from 'api/alerts/save';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { createRule } from 'api/generated/services/rules';
|
||||
import type {
|
||||
ListRules200,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettableRuleDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { ErrorType } from 'api/generatedAPIInstance';
|
||||
import { AxiosError } from 'axios';
|
||||
import DropDown from 'components/DropDown/DropDown';
|
||||
import {
|
||||
DynamicColumnsKey,
|
||||
@@ -27,9 +36,10 @@ import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
import type { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
|
||||
import APIError from 'types/api/error';
|
||||
import { isModifierKeyPressed } from 'utils/app';
|
||||
|
||||
import DeleteAlert from './DeleteAlert';
|
||||
@@ -58,7 +68,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
const paginationParam = params.get('page');
|
||||
const searchParams = params.get('search');
|
||||
const [searchString, setSearchString] = useState<string>(searchParams || '');
|
||||
const [data, setData] = useState<GettableAlert[]>(() => {
|
||||
const [data, setData] = useState<RuletypesGettableRuleDTO[]>(() => {
|
||||
const value = searchString.toLowerCase();
|
||||
const filteredData = filterAlerts(allAlertRules, value);
|
||||
return filteredData || [];
|
||||
@@ -70,7 +80,10 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
? orderQueryParam
|
||||
: null;
|
||||
|
||||
const { sortedInfo, handleChange } = useSortableTable<GettableAlert>(
|
||||
const {
|
||||
sortedInfo,
|
||||
handleChange,
|
||||
} = useSortableTable<RuletypesGettableRuleDTO>(
|
||||
sortingOrder,
|
||||
orderColumnParam || '',
|
||||
searchString,
|
||||
@@ -83,7 +96,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
const { data: refetchData, status } = await refetch();
|
||||
if (status === 'success') {
|
||||
const value = searchString.toLowerCase();
|
||||
const filteredData = filterAlerts(refetchData.payload || [], value);
|
||||
const filteredData = filterAlerts(refetchData?.data?.rules ?? [], value);
|
||||
setData(filteredData || []);
|
||||
}
|
||||
if (status === 'error') {
|
||||
@@ -94,11 +107,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
})();
|
||||
}, 30000);
|
||||
|
||||
const handleError = useCallback((): void => {
|
||||
notificationsApi.error({
|
||||
message: t('something_went_wrong'),
|
||||
});
|
||||
}, [notificationsApi, t]);
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const onClickNewAlertHandler = useCallback(
|
||||
(e: React.MouseEvent): void => {
|
||||
@@ -115,11 +124,13 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
);
|
||||
|
||||
const onEditHandler = (
|
||||
record: GettableAlert,
|
||||
record: RuletypesGettableRuleDTO,
|
||||
options?: { newTab?: boolean },
|
||||
): void => {
|
||||
const compositeQuery = sanitizeDefaultAlertQuery(
|
||||
mapQueryDataFromApi(record.condition.compositeQuery),
|
||||
mapQueryDataFromApi(
|
||||
(record.condition?.compositeQuery as unknown) as ICompositeMetricQuery,
|
||||
),
|
||||
record.alertType as AlertTypes,
|
||||
);
|
||||
params.set(
|
||||
@@ -127,9 +138,12 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
encodeURIComponent(JSON.stringify(compositeQuery)),
|
||||
);
|
||||
|
||||
params.set(QueryParams.panelTypes, record.condition.compositeQuery.panelType);
|
||||
const panelType = record.condition?.compositeQuery?.panelType;
|
||||
if (panelType) {
|
||||
params.set(QueryParams.panelTypes, panelType);
|
||||
}
|
||||
|
||||
params.set(QueryParams.ruleId, record.id.toString());
|
||||
params.set(QueryParams.ruleId, record.id ?? '');
|
||||
|
||||
setEditLoader(false);
|
||||
|
||||
@@ -139,47 +153,41 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
};
|
||||
|
||||
const onCloneHandler = (
|
||||
originalAlert: GettableAlert,
|
||||
originalAlert: RuletypesGettableRuleDTO,
|
||||
) => async (): Promise<void> => {
|
||||
const copyAlert = {
|
||||
const copyAlert: RuletypesGettableRuleDTO = {
|
||||
...originalAlert,
|
||||
alert: originalAlert.alert.concat(' - Copy'),
|
||||
alert: `${originalAlert.alert ?? ''} - Copy`,
|
||||
};
|
||||
const apiReq = { data: copyAlert };
|
||||
|
||||
try {
|
||||
setCloneLoader(true);
|
||||
const response = await saveAlertApi(apiReq);
|
||||
await createRule((copyAlert as unknown) as RuletypesPostableRuleDTO);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
notificationsApi.success({
|
||||
message: 'Success',
|
||||
description: 'Alert cloned successfully',
|
||||
});
|
||||
notificationsApi.success({
|
||||
message: 'Success',
|
||||
description: 'Alert cloned successfully',
|
||||
});
|
||||
|
||||
const { data: refetchData, status } = await refetch();
|
||||
if (status === 'success' && refetchData.payload) {
|
||||
setData(refetchData.payload || []);
|
||||
setTimeout(() => {
|
||||
const clonedAlert = refetchData.payload[refetchData.payload.length - 1];
|
||||
params.set(QueryParams.ruleId, String(clonedAlert.id));
|
||||
safeNavigate(`${ROUTES.EDIT_ALERTS}?${params.toString()}`);
|
||||
}, 2000);
|
||||
}
|
||||
if (status === 'error') {
|
||||
notificationsApi.error({
|
||||
message: t('something_went_wrong'),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const { data: refetchData, status } = await refetch();
|
||||
const rules = refetchData?.data?.rules;
|
||||
if (status === 'success' && rules) {
|
||||
setData(rules);
|
||||
setTimeout(() => {
|
||||
const clonedAlert = rules[rules.length - 1];
|
||||
params.set(QueryParams.ruleId, String(clonedAlert.id));
|
||||
safeNavigate(`${ROUTES.EDIT_ALERTS}?${params.toString()}`);
|
||||
}, 2000);
|
||||
}
|
||||
if (status === 'error') {
|
||||
notificationsApi.error({
|
||||
message: 'Error',
|
||||
description: response.error || t('something_went_wrong'),
|
||||
message: t('something_went_wrong'),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
handleError();
|
||||
console.error(error);
|
||||
showErrorModal(
|
||||
convertToApiError(error as AxiosError<RenderErrorResponseDTO>) as APIError,
|
||||
);
|
||||
} finally {
|
||||
setCloneLoader(false);
|
||||
}
|
||||
@@ -192,16 +200,19 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
setData(filteredData);
|
||||
});
|
||||
|
||||
const dynamicColumns: ColumnsType<GettableAlert> = [
|
||||
const dynamicColumns: ColumnsType<RuletypesGettableRuleDTO> = [
|
||||
{
|
||||
title: 'Created At',
|
||||
dataIndex: 'createAt',
|
||||
width: 80,
|
||||
key: DynamicColumnsKey.CreatedAt,
|
||||
align: 'center',
|
||||
sorter: (a: GettableAlert, b: GettableAlert): number => {
|
||||
const prev = new Date(a.createAt).getTime();
|
||||
const next = new Date(b.createAt).getTime();
|
||||
sorter: (
|
||||
a: RuletypesGettableRuleDTO,
|
||||
b: RuletypesGettableRuleDTO,
|
||||
): number => {
|
||||
const prev = a.createAt ? new Date(a.createAt).getTime() : 0;
|
||||
const next = b.createAt ? new Date(b.createAt).getTime() : 0;
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
@@ -224,9 +235,12 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
width: 80,
|
||||
key: DynamicColumnsKey.UpdatedAt,
|
||||
align: 'center',
|
||||
sorter: (a: GettableAlert, b: GettableAlert): number => {
|
||||
const prev = new Date(a.updateAt).getTime();
|
||||
const next = new Date(b.updateAt).getTime();
|
||||
sorter: (
|
||||
a: RuletypesGettableRuleDTO,
|
||||
b: RuletypesGettableRuleDTO,
|
||||
): number => {
|
||||
const prev = a.updateAt ? new Date(a.updateAt).getTime() : 0;
|
||||
const next = b.updateAt ? new Date(b.updateAt).getTime() : 0;
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
@@ -245,7 +259,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
},
|
||||
];
|
||||
|
||||
const columns: ColumnsType<GettableAlert> = [
|
||||
const columns: ColumnsType<RuletypesGettableRuleDTO> = [
|
||||
{
|
||||
title: 'Status',
|
||||
dataIndex: 'state',
|
||||
@@ -322,7 +336,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
dataIndex: 'id',
|
||||
key: 'action',
|
||||
width: 10,
|
||||
render: (id: GettableAlert['id'], record): JSX.Element => (
|
||||
render: (id: RuletypesGettableRuleDTO['id'], record): JSX.Element => (
|
||||
<div data-testid="alert-actions">
|
||||
<DropDown
|
||||
onDropDownItemClick={(item): void =>
|
||||
@@ -331,9 +345,9 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
element={[
|
||||
<ToggleAlertState
|
||||
key="1"
|
||||
disabled={record.disabled}
|
||||
disabled={record.disabled ?? false}
|
||||
setData={setData}
|
||||
id={id}
|
||||
id={id ?? ''}
|
||||
/>,
|
||||
<ColumnButton
|
||||
key="2"
|
||||
@@ -365,7 +379,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
key="4"
|
||||
notifications={notificationsApi}
|
||||
setData={setData}
|
||||
id={id}
|
||||
id={id ?? ''}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
@@ -420,9 +434,10 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
}
|
||||
|
||||
interface ListAlertProps {
|
||||
allAlertRules: GettableAlert[];
|
||||
allAlertRules: RuletypesGettableRuleDTO[];
|
||||
refetch: UseQueryResult<
|
||||
ErrorResponse | SuccessResponse<GettableAlert[]>
|
||||
ListRules200,
|
||||
ErrorType<RenderErrorResponseDTO>
|
||||
>['refetch'];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Tag } from 'antd';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
import type { RuletypesGettableRuleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
function Status({ status }: StatusProps): JSX.Element {
|
||||
switch (status) {
|
||||
@@ -26,7 +26,7 @@ function Status({ status }: StatusProps): JSX.Element {
|
||||
}
|
||||
|
||||
interface StatusProps {
|
||||
status: GettableAlert['state'];
|
||||
status: RuletypesGettableRuleDTO['state'];
|
||||
}
|
||||
|
||||
export default Status;
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { Dispatch, SetStateAction, useState } from 'react';
|
||||
import patchAlert from 'api/alerts/patch';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { patchRuleByID } from 'api/generated/services/rules';
|
||||
import type {
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettableRuleDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { State } from 'hooks/useFetch';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
import { PayloadProps as PatchPayloadProps } from 'types/api/alerts/patch';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import APIError from 'types/api/error';
|
||||
|
||||
import { ColumnButton } from './styles';
|
||||
|
||||
@@ -12,7 +19,7 @@ function ToggleAlertState({
|
||||
disabled,
|
||||
setData,
|
||||
}: ToggleAlertStateProps): JSX.Element {
|
||||
const [apiStatus, setAPIStatus] = useState<State<PatchPayloadProps>>({
|
||||
const [apiStatus, setAPIStatus] = useState<State<RuletypesGettableRuleDTO>>({
|
||||
error: false,
|
||||
errorMessage: '',
|
||||
loading: false,
|
||||
@@ -21,8 +28,7 @@ function ToggleAlertState({
|
||||
});
|
||||
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const defaultErrorMessage = 'Something went wrong';
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const onToggleHandler = async (
|
||||
id: string,
|
||||
@@ -34,58 +40,42 @@ function ToggleAlertState({
|
||||
loading: true,
|
||||
}));
|
||||
|
||||
const response = await patchAlert({
|
||||
id,
|
||||
data: {
|
||||
disabled,
|
||||
},
|
||||
const response = await patchRuleByID({ id }, ({
|
||||
disabled,
|
||||
} as unknown) as RuletypesPostableRuleDTO);
|
||||
const { data: updatedRule } = response;
|
||||
|
||||
setData((state) =>
|
||||
state.map((alert) => {
|
||||
if (alert.id === id) {
|
||||
return {
|
||||
...alert,
|
||||
disabled: updatedRule.disabled,
|
||||
state: updatedRule.state,
|
||||
};
|
||||
}
|
||||
return alert;
|
||||
}),
|
||||
);
|
||||
|
||||
setAPIStatus((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
payload: updatedRule,
|
||||
}));
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
});
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
setData((state) =>
|
||||
state.map((alert) => {
|
||||
if (alert.id === id) {
|
||||
return {
|
||||
...alert,
|
||||
disabled: response.payload.disabled,
|
||||
state: response.payload.state,
|
||||
};
|
||||
}
|
||||
return alert;
|
||||
}),
|
||||
);
|
||||
|
||||
setAPIStatus((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
payload: response.payload,
|
||||
}));
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
});
|
||||
} else {
|
||||
setAPIStatus((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
error: true,
|
||||
errorMessage: response.error || defaultErrorMessage,
|
||||
}));
|
||||
|
||||
notifications.error({
|
||||
message: response.error || defaultErrorMessage,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
setAPIStatus((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
error: true,
|
||||
errorMessage: defaultErrorMessage,
|
||||
}));
|
||||
|
||||
notifications.error({
|
||||
message: defaultErrorMessage,
|
||||
});
|
||||
showErrorModal(
|
||||
convertToApiError(error as AxiosError<RenderErrorResponseDTO>) as APIError,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,9 +92,9 @@ function ToggleAlertState({
|
||||
}
|
||||
|
||||
interface ToggleAlertStateProps {
|
||||
id: GettableAlert['id'];
|
||||
id: string;
|
||||
disabled: boolean;
|
||||
setData: Dispatch<SetStateAction<GettableAlert[]>>;
|
||||
setData: Dispatch<SetStateAction<RuletypesGettableRuleDTO[]>>;
|
||||
}
|
||||
|
||||
export default ToggleAlertState;
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
import type {
|
||||
RuletypesAlertStateDTO,
|
||||
RuletypesGettableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
import { filterAlerts } from '../utils';
|
||||
|
||||
describe('filterAlerts', () => {
|
||||
const mockAlertBase: Partial<GettableAlert> = {
|
||||
state: 'active',
|
||||
const mockAlertBase: Partial<RuletypesGettableRuleDTO> = {
|
||||
state: 'active' as RuletypesAlertStateDTO,
|
||||
disabled: false,
|
||||
createAt: '2024-01-01T00:00:00Z',
|
||||
createAt: new Date('2024-01-01T00:00:00Z'),
|
||||
createBy: 'test-user',
|
||||
updateAt: '2024-01-01T00:00:00Z',
|
||||
updateAt: new Date('2024-01-01T00:00:00Z'),
|
||||
updateBy: 'test-user',
|
||||
version: '1',
|
||||
condition: {},
|
||||
ruleType: 'threshold_rule' as RuletypesGettableRuleDTO['ruleType'],
|
||||
};
|
||||
|
||||
const mockAlerts: GettableAlert[] = [
|
||||
const mockAlerts: RuletypesGettableRuleDTO[] = [
|
||||
{
|
||||
...mockAlertBase,
|
||||
id: '1',
|
||||
@@ -24,7 +29,7 @@ describe('filterAlerts', () => {
|
||||
status: 'ok',
|
||||
environment: 'production',
|
||||
},
|
||||
} as GettableAlert,
|
||||
} as RuletypesGettableRuleDTO,
|
||||
{
|
||||
...mockAlertBase,
|
||||
id: '2',
|
||||
@@ -35,7 +40,7 @@ describe('filterAlerts', () => {
|
||||
status: 'firing',
|
||||
environment: 'staging',
|
||||
},
|
||||
} as GettableAlert,
|
||||
} as RuletypesGettableRuleDTO,
|
||||
{
|
||||
...mockAlertBase,
|
||||
id: '3',
|
||||
@@ -46,7 +51,7 @@ describe('filterAlerts', () => {
|
||||
status: 'pending',
|
||||
environment: 'production',
|
||||
},
|
||||
} as GettableAlert,
|
||||
} as RuletypesGettableRuleDTO,
|
||||
];
|
||||
|
||||
it('should return all alerts when filter is empty', () => {
|
||||
@@ -97,14 +102,14 @@ describe('filterAlerts', () => {
|
||||
});
|
||||
|
||||
it('should handle alerts with missing labels', () => {
|
||||
const alertsWithMissingLabels: GettableAlert[] = [
|
||||
const alertsWithMissingLabels: RuletypesGettableRuleDTO[] = [
|
||||
{
|
||||
...mockAlertBase,
|
||||
id: '4',
|
||||
alert: 'Test Alert',
|
||||
alertType: 'metrics',
|
||||
labels: undefined,
|
||||
} as GettableAlert,
|
||||
} as RuletypesGettableRuleDTO,
|
||||
];
|
||||
const result = filterAlerts(alertsWithMissingLabels, 'test');
|
||||
expect(result).toHaveLength(1);
|
||||
@@ -112,7 +117,7 @@ describe('filterAlerts', () => {
|
||||
});
|
||||
|
||||
it('should handle alerts with missing alert name', () => {
|
||||
const alertsWithMissingName: GettableAlert[] = [
|
||||
const alertsWithMissingName: RuletypesGettableRuleDTO[] = [
|
||||
{
|
||||
...mockAlertBase,
|
||||
id: '5',
|
||||
@@ -121,7 +126,7 @@ describe('filterAlerts', () => {
|
||||
labels: {
|
||||
severity: 'warning',
|
||||
},
|
||||
} as GettableAlert,
|
||||
} as RuletypesGettableRuleDTO,
|
||||
];
|
||||
const result = filterAlerts(alertsWithMissingName, 'warning');
|
||||
expect(result).toHaveLength(1);
|
||||
|
||||
@@ -1,78 +1,66 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Space } from 'antd';
|
||||
import getAll from 'api/alerts/getAll';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { useListRules } from 'api/generated/services/rules';
|
||||
import { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { isUndefined } from 'lodash-es';
|
||||
|
||||
import { AlertsEmptyState } from './AlertsEmptyState/AlertsEmptyState';
|
||||
import ListAlert from './ListAlert';
|
||||
|
||||
function ListAlertRules(): JSX.Element {
|
||||
const { t } = useTranslation('common');
|
||||
const { data, isError, isLoading, refetch, status } = useQuery('allAlerts', {
|
||||
queryFn: getAll,
|
||||
cacheTime: 0,
|
||||
const { data, isError, isLoading, refetch, error } = useListRules({
|
||||
query: { cacheTime: 0 },
|
||||
});
|
||||
|
||||
const rules = data?.data?.rules ?? [];
|
||||
const hasLoaded = !isLoading && data !== undefined;
|
||||
const logEventCalledRef = useRef(false);
|
||||
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const apiError = useMemo(
|
||||
() => convertToApiError(error as AxiosError<RenderErrorResponseDTO> | null),
|
||||
[error],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!logEventCalledRef.current && !isUndefined(data?.payload)) {
|
||||
if (!logEventCalledRef.current && hasLoaded) {
|
||||
logEvent('Alert: List page visited', {
|
||||
number: data?.payload?.length,
|
||||
number: rules.length,
|
||||
});
|
||||
logEventCalledRef.current = true;
|
||||
}
|
||||
}, [data?.payload]);
|
||||
}, [hasLoaded, rules.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'error' || (status === 'success' && data.statusCode >= 400)) {
|
||||
if (isError) {
|
||||
notifications.error({
|
||||
message: data?.error || t('something_went_wrong'),
|
||||
message: apiError?.getErrorMessage() || t('something_went_wrong'),
|
||||
});
|
||||
}
|
||||
}, [data?.error, data?.statusCode, status, t, notifications]);
|
||||
}, [isError, apiError, t, notifications]);
|
||||
|
||||
// api failed to load the data
|
||||
if (isError) {
|
||||
return <div>{data?.error || t('something_went_wrong')}</div>;
|
||||
return <div>{apiError?.getErrorMessage() || t('something_went_wrong')}</div>;
|
||||
}
|
||||
|
||||
// api is successful but error is present
|
||||
if (status === 'success' && data.statusCode >= 400) {
|
||||
return (
|
||||
<ListAlert
|
||||
{...{
|
||||
allAlertRules: [],
|
||||
refetch,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === 'success' && !data.payload?.length) {
|
||||
return <AlertsEmptyState />;
|
||||
}
|
||||
|
||||
// in case of loading
|
||||
if (isLoading || !data?.payload) {
|
||||
if (isLoading || !data) {
|
||||
return <Spinner height="75vh" tip="Loading Rules..." />;
|
||||
}
|
||||
|
||||
if (rules.length === 0) {
|
||||
return <AlertsEmptyState />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size="large" style={{ width: '100%' }}>
|
||||
<ListAlert
|
||||
{...{
|
||||
allAlertRules: data.payload,
|
||||
refetch,
|
||||
}}
|
||||
/>
|
||||
<ListAlert allAlertRules={rules} refetch={refetch} />
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import type { RuletypesGettableRuleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
|
||||
export const filterAlerts = (
|
||||
allAlertRules: GettableAlert[],
|
||||
allAlertRules: RuletypesGettableRuleDTO[],
|
||||
filter: string,
|
||||
): GettableAlert[] => {
|
||||
): RuletypesGettableRuleDTO[] => {
|
||||
if (!filter.trim()) {
|
||||
return allAlertRules;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export const filterAlerts = (
|
||||
|
||||
export const alertActionLogEvent = (
|
||||
action: string,
|
||||
record: GettableAlert,
|
||||
record: RuletypesGettableRuleDTO,
|
||||
): void => {
|
||||
let actionValue = '';
|
||||
switch (action) {
|
||||
|
||||
@@ -2,10 +2,8 @@ import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Input, Modal, Typography } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import {
|
||||
updateMyPassword,
|
||||
useUpdateMyUserV2,
|
||||
} from 'api/generated/services/users';
|
||||
import { useUpdateMyUserV2 } from 'api/generated/services/users';
|
||||
import changeMyPassword from 'api/v1/factor_password/changeMyPassword';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { Check, FileTerminal, MailIcon, UserIcon } from 'lucide-react';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
@@ -55,9 +53,10 @@ function UserInfo(): JSX.Element {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
await updateMyPassword({
|
||||
await changeMyPassword({
|
||||
newPassword: updatePassword,
|
||||
oldPassword: currentPassword,
|
||||
userId: user.id,
|
||||
});
|
||||
notifications.success({
|
||||
message: t('success', {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import React, { ChangeEvent, useEffect, useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Flex, Form, Input, Tooltip, Typography } from 'antd';
|
||||
import getAll from 'api/alerts/getAll';
|
||||
import { useDeleteDowntimeSchedule } from 'api/plannedDowntime/deleteDowntimeSchedule';
|
||||
import {
|
||||
DowntimeSchedules,
|
||||
useGetAllDowntimeSchedules,
|
||||
} from 'api/plannedDowntime/getAllDowntimeSchedules';
|
||||
useDeleteDowntimeScheduleByID,
|
||||
useListDowntimeSchedules,
|
||||
} from 'api/generated/services/downtimeschedules';
|
||||
import { useListRules } from 'api/generated/services/rules';
|
||||
import type { RuletypesGettablePlannedMaintenanceDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import dayjs from 'dayjs';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { Search } from 'lucide-react';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import { USER_ROLES } from 'types/roles';
|
||||
|
||||
import 'dayjs/locale/en';
|
||||
@@ -33,28 +33,28 @@ import './PlannedDowntime.styles.scss';
|
||||
dayjs.locale('en');
|
||||
|
||||
export function PlannedDowntime(): JSX.Element {
|
||||
const { data, isError, isLoading } = useQuery('allAlerts', {
|
||||
queryFn: getAll,
|
||||
cacheTime: 0,
|
||||
const { data: alertsData, isError, isLoading } = useListRules({
|
||||
query: { cacheTime: 0 },
|
||||
});
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const { user } = useAppContext();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
const history = useHistory();
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const [initialValues, setInitialValues] = useState<
|
||||
Partial<DowntimeSchedules & { editMode: boolean }>
|
||||
Partial<RuletypesGettablePlannedMaintenanceDTO & { editMode: boolean }>
|
||||
>(defautlInitialValues);
|
||||
|
||||
const downtimeSchedules = useGetAllDowntimeSchedules();
|
||||
const downtimeSchedules = useListDowntimeSchedules();
|
||||
const alertOptions = React.useMemo(
|
||||
() =>
|
||||
data?.payload?.map((i) => ({
|
||||
alertsData?.data?.rules?.map((i: any) => ({
|
||||
label: i.alert,
|
||||
value: i.id,
|
||||
})),
|
||||
[data],
|
||||
[alertsData],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -66,7 +66,7 @@ export function PlannedDowntime(): JSX.Element {
|
||||
const [searchValue, setSearchValue] = React.useState<string | number>(
|
||||
urlQuery.get('search') || '',
|
||||
);
|
||||
const [deleteData, setDeleteData] = useState<{ id: number; name: string }>();
|
||||
const [deleteData, setDeleteData] = useState<{ id: string; name: string }>();
|
||||
const [isEditMode, setEditMode] = useState<boolean>(false);
|
||||
|
||||
const updateUrlWithSearch = useDebouncedFn((value) => {
|
||||
@@ -105,12 +105,13 @@ export function PlannedDowntime(): JSX.Element {
|
||||
const {
|
||||
mutateAsync: deleteDowntimeScheduleAsync,
|
||||
isLoading: isDeleteLoading,
|
||||
} = useDeleteDowntimeSchedule({ id: deleteData?.id });
|
||||
} = useDeleteDowntimeScheduleByID();
|
||||
|
||||
const onDeleteHandler = (): void => {
|
||||
deleteDowntimeHandler({
|
||||
deleteDowntimeScheduleAsync,
|
||||
notifications,
|
||||
showErrorModal,
|
||||
refetchAllSchedules,
|
||||
deleteId: deleteData?.id,
|
||||
hideDeleteDowntimeScheduleModal,
|
||||
|
||||
@@ -14,11 +14,17 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import {
|
||||
DowntimeSchedules,
|
||||
Recurrence,
|
||||
} from 'api/plannedDowntime/getAllDowntimeSchedules';
|
||||
import { DowntimeScheduleUpdatePayload } from 'api/plannedDowntime/updateDowntimeSchedule';
|
||||
createDowntimeSchedule,
|
||||
updateDowntimeScheduleByID,
|
||||
} from 'api/generated/services/downtimeschedules';
|
||||
import type {
|
||||
RuletypesGettablePlannedMaintenanceDTO,
|
||||
RuletypesRecurrenceDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import {
|
||||
ModalButtonWrapper,
|
||||
@@ -29,15 +35,14 @@ import timezone from 'dayjs/plugin/timezone';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { defaultTo, isEmpty } from 'lodash-es';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import APIError from 'types/api/error';
|
||||
import { ALL_TIME_ZONES } from 'utils/timeZoneUtil';
|
||||
|
||||
import 'dayjs/locale/en';
|
||||
|
||||
import { SOMETHING_WENT_WRONG } from '../../constants/api';
|
||||
import { showErrorNotification } from '../../utils/error';
|
||||
import { AlertRuleTags } from './PlannedDowntimeList';
|
||||
import {
|
||||
createEditDowntimeSchedule,
|
||||
getAlertOptionsFromIds,
|
||||
getDurationInfo,
|
||||
getEndTime,
|
||||
@@ -62,9 +67,9 @@ interface PlannedDowntimeFormData {
|
||||
name: string;
|
||||
startTime: dayjs.Dayjs | string;
|
||||
endTime: dayjs.Dayjs | string;
|
||||
recurrence?: Recurrence | null;
|
||||
recurrence?: RuletypesRecurrenceDTO | null;
|
||||
alertRules: DefaultOptionType[];
|
||||
recurrenceSelect?: Recurrence;
|
||||
recurrenceSelect?: RuletypesRecurrenceDTO;
|
||||
timezone?: string;
|
||||
}
|
||||
|
||||
@@ -72,7 +77,7 @@ const customFormat = DATE_TIME_FORMATS.ORDINAL_DATETIME;
|
||||
|
||||
interface PlannedDowntimeFormProps {
|
||||
initialValues: Partial<
|
||||
DowntimeSchedules & {
|
||||
RuletypesGettablePlannedMaintenanceDTO & {
|
||||
editMode: boolean;
|
||||
}
|
||||
>;
|
||||
@@ -112,7 +117,7 @@ export function PlannedDowntimeForm(
|
||||
);
|
||||
|
||||
const [formData, setFormData] = useState<PlannedDowntimeFormData>(
|
||||
initialValues?.schedule as PlannedDowntimeFormData,
|
||||
(initialValues?.schedule as unknown) as PlannedDowntimeFormData,
|
||||
);
|
||||
|
||||
const [recurrenceType, setRecurrenceType] = useState<string | null>(
|
||||
@@ -125,6 +130,7 @@ export function PlannedDowntimeForm(
|
||||
: undefined;
|
||||
|
||||
const { notifications } = useNotifications();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const datePickerFooter = (mode: any): any =>
|
||||
mode === 'time' ? (
|
||||
@@ -134,57 +140,54 @@ export function PlannedDowntimeForm(
|
||||
const saveHanlder = useCallback(
|
||||
async (values: PlannedDowntimeFormData) => {
|
||||
const shouldKeepLocalTime = !isEditMode;
|
||||
const createEditProps: DowntimeScheduleUpdatePayload = {
|
||||
data: {
|
||||
alertIds: values.alertRules
|
||||
.map((alert) => alert.value)
|
||||
.filter((alert) => alert !== undefined) as string[],
|
||||
name: values.name,
|
||||
schedule: {
|
||||
startTime: handleTimeConversion(
|
||||
const data: RuletypesGettablePlannedMaintenanceDTO = {
|
||||
alertIds: values.alertRules
|
||||
.map((alert) => alert.value)
|
||||
.filter((alert) => alert !== undefined) as string[],
|
||||
name: values.name,
|
||||
schedule: {
|
||||
startTime: new Date(
|
||||
handleTimeConversion(
|
||||
values.startTime,
|
||||
timezoneInitialValue,
|
||||
values.timezone,
|
||||
shouldKeepLocalTime,
|
||||
),
|
||||
timezone: values.timezone,
|
||||
endTime: values.endTime
|
||||
? handleTimeConversion(
|
||||
),
|
||||
timezone: values.timezone,
|
||||
endTime: values.endTime
|
||||
? new Date(
|
||||
handleTimeConversion(
|
||||
values.endTime,
|
||||
timezoneInitialValue,
|
||||
values.timezone,
|
||||
shouldKeepLocalTime,
|
||||
)
|
||||
: undefined,
|
||||
recurrence: values.recurrence as Recurrence,
|
||||
},
|
||||
),
|
||||
)
|
||||
: undefined,
|
||||
recurrence: values.recurrence as RuletypesRecurrenceDTO,
|
||||
},
|
||||
id: isEditMode ? initialValues.id : undefined,
|
||||
};
|
||||
|
||||
setSaveLoading(true);
|
||||
try {
|
||||
const response = await createEditDowntimeSchedule({ ...createEditProps });
|
||||
if (response.message === 'success') {
|
||||
setIsOpen(false);
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: isEditMode
|
||||
? 'Schedule updated successfully'
|
||||
: 'Schedule created successfully',
|
||||
});
|
||||
refetchAllSchedules();
|
||||
if (isEditMode && initialValues.id) {
|
||||
await updateDowntimeScheduleByID({ id: initialValues.id }, data);
|
||||
} else {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description:
|
||||
typeof response.error === 'string'
|
||||
? response.error
|
||||
: response.error?.message || SOMETHING_WENT_WRONG,
|
||||
});
|
||||
await createDowntimeSchedule(data);
|
||||
}
|
||||
setIsOpen(false);
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: isEditMode
|
||||
? 'Schedule updated successfully'
|
||||
: 'Schedule created successfully',
|
||||
});
|
||||
refetchAllSchedules();
|
||||
} catch (e: unknown) {
|
||||
showErrorNotification(notifications, e as Error);
|
||||
showErrorModal(
|
||||
convertToApiError(e as AxiosError<RenderErrorResponseDTO>) as APIError,
|
||||
);
|
||||
}
|
||||
setSaveLoading(false);
|
||||
},
|
||||
@@ -195,10 +198,11 @@ export function PlannedDowntimeForm(
|
||||
refetchAllSchedules,
|
||||
setIsOpen,
|
||||
timezoneInitialValue,
|
||||
showErrorModal,
|
||||
],
|
||||
);
|
||||
const onFinish = async (values: PlannedDowntimeFormData): Promise<void> => {
|
||||
const recurrenceData: Recurrence | undefined =
|
||||
const recurrenceData =
|
||||
values?.recurrence?.repeatType === recurrenceOptions.doesNotRepeat.value
|
||||
? undefined
|
||||
: {
|
||||
@@ -225,7 +229,10 @@ export function PlannedDowntimeForm(
|
||||
repeatType: values.recurrence?.repeatType,
|
||||
};
|
||||
|
||||
const payloadValues = { ...values, recurrence: recurrenceData };
|
||||
const payloadValues = {
|
||||
...values,
|
||||
recurrence: recurrenceData as RuletypesRecurrenceDTO | undefined,
|
||||
};
|
||||
await saveHanlder(payloadValues);
|
||||
};
|
||||
|
||||
@@ -280,13 +287,14 @@ export function PlannedDowntimeForm(
|
||||
? dayjs(initialValues.schedule?.startTime)
|
||||
: '',
|
||||
recurrence: {
|
||||
...initialValues.schedule?.recurrence,
|
||||
...(initialValues.schedule?.recurrence as Record<string, unknown>),
|
||||
repeatType: !isScheduleRecurring(initialValues?.schedule)
|
||||
? recurrenceOptions.doesNotRepeat.value
|
||||
: (initialValues.schedule?.recurrence?.repeatType as string),
|
||||
duration: getDurationInfo(
|
||||
initialValues.schedule?.recurrence?.duration as string,
|
||||
)?.value,
|
||||
duration: String(
|
||||
getDurationInfo(initialValues.schedule?.recurrence?.duration as string)
|
||||
?.value ?? '',
|
||||
),
|
||||
},
|
||||
timezone: initialValues.schedule?.timezone as string,
|
||||
};
|
||||
@@ -325,7 +333,12 @@ export function PlannedDowntimeForm(
|
||||
const startTimeText = useMemo((): string => {
|
||||
let startTime = formData?.startTime;
|
||||
if (recurrenceType !== recurrenceOptions.doesNotRepeat.value) {
|
||||
startTime = formData?.recurrence?.startTime || formData?.startTime || '';
|
||||
startTime =
|
||||
(formData?.recurrence?.startTime
|
||||
? dayjs(formData.recurrence.startTime).toISOString()
|
||||
: '') ||
|
||||
formData?.startTime ||
|
||||
'';
|
||||
}
|
||||
|
||||
if (!startTime) {
|
||||
@@ -381,7 +394,10 @@ export function PlannedDowntimeForm(
|
||||
const endTimeText = useMemo((): string => {
|
||||
let endTime = formData?.endTime;
|
||||
if (recurrenceType !== recurrenceOptions.doesNotRepeat.value) {
|
||||
endTime = formData?.recurrence?.endTime || '';
|
||||
endTime =
|
||||
(formData?.recurrence?.endTime
|
||||
? dayjs(formData.recurrence.endTime).toISOString()
|
||||
: '') || '';
|
||||
|
||||
if (!isEditMode && !endTime) {
|
||||
endTime = formData?.endTime || '';
|
||||
|
||||
@@ -12,13 +12,15 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import {
|
||||
DowntimeSchedules,
|
||||
PayloadProps,
|
||||
Recurrence,
|
||||
} from 'api/plannedDowntime/getAllDowntimeSchedules';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import type {
|
||||
ListDowntimeSchedules200,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettablePlannedMaintenanceDTO,
|
||||
RuletypesRecurrenceDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { ErrorType } from 'api/generatedAPIInstance';
|
||||
import cx from 'classnames';
|
||||
import dayjs from 'dayjs';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { defaultTo } from 'lodash-es';
|
||||
import { CalendarClock, PenLine, Trash2 } from 'lucide-react';
|
||||
@@ -143,7 +145,7 @@ export function CollapseListContent({
|
||||
created_by_name?: string;
|
||||
created_by_email?: string;
|
||||
timeframe: [string | undefined | null, string | undefined | null];
|
||||
repeats?: Recurrence | null;
|
||||
repeats?: RuletypesRecurrenceDTO | null;
|
||||
updated_at?: string;
|
||||
updated_by_name?: string;
|
||||
alertOptions?: DefaultOptionType[];
|
||||
@@ -218,10 +220,10 @@ export function CollapseListContent({
|
||||
export function CustomCollapseList(
|
||||
props: DowntimeSchedulesTableData & {
|
||||
setInitialValues: React.Dispatch<
|
||||
React.SetStateAction<Partial<DowntimeSchedules>>
|
||||
React.SetStateAction<Partial<RuletypesGettablePlannedMaintenanceDTO>>
|
||||
>;
|
||||
setModalOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
handleDeleteDowntime: (id: number, name: string) => void;
|
||||
handleDeleteDowntime: (id: string, name: string) => void;
|
||||
setEditMode: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
},
|
||||
): JSX.Element {
|
||||
@@ -241,12 +243,19 @@ export function CustomCollapseList(
|
||||
kind,
|
||||
} = props;
|
||||
|
||||
const scheduleTime = schedule?.startTime ? schedule.startTime : createdAt;
|
||||
const scheduleTime = schedule?.startTime
|
||||
? dayjs(schedule.startTime).toISOString()
|
||||
: createdAt
|
||||
? dayjs(createdAt).toISOString()
|
||||
: '';
|
||||
// Combine time and date
|
||||
const formattedDateAndTime = `Start time ⎯ ${formatDateTime(
|
||||
defaultTo(scheduleTime, ''),
|
||||
)} ${schedule?.timezone}`;
|
||||
const endTime = getEndTime({ kind, schedule });
|
||||
const endTime = getEndTime({
|
||||
kind,
|
||||
schedule,
|
||||
} as Partial<RuletypesGettablePlannedMaintenanceDTO>);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -257,7 +266,10 @@ export function CustomCollapseList(
|
||||
duration={
|
||||
schedule?.recurrence?.duration
|
||||
? (schedule?.recurrence?.duration as string)
|
||||
: getDuration(schedule?.startTime, schedule?.endTime)
|
||||
: getDuration(
|
||||
schedule?.startTime ? dayjs(schedule.startTime).toISOString() : '',
|
||||
schedule?.endTime ? dayjs(schedule.endTime).toISOString() : '',
|
||||
)
|
||||
}
|
||||
name={defaultTo(name, '')}
|
||||
handleEdit={(): void => {
|
||||
@@ -266,21 +278,23 @@ export function CustomCollapseList(
|
||||
setEditMode(true);
|
||||
}}
|
||||
handleDelete={(): void => {
|
||||
handleDeleteDowntime(id, name || '');
|
||||
handleDeleteDowntime(id ?? '', name || '');
|
||||
}}
|
||||
/>
|
||||
}
|
||||
key={id}
|
||||
key={id ?? ''}
|
||||
>
|
||||
<CollapseListContent
|
||||
created_at={defaultTo(createdAt, '')}
|
||||
created_at={createdAt ? dayjs(createdAt).toISOString() : ''}
|
||||
created_by_name={defaultTo(createdBy, '')}
|
||||
timeframe={[
|
||||
schedule?.startTime?.toString(),
|
||||
typeof endTime === 'string' ? endTime : endTime?.toString(),
|
||||
]}
|
||||
repeats={schedule?.recurrence}
|
||||
updated_at={defaultTo(updatedAt, '')}
|
||||
repeats={
|
||||
schedule?.recurrence as RuletypesRecurrenceDTO | null | undefined
|
||||
}
|
||||
updated_at={updatedAt ? dayjs(updatedAt).toISOString() : ''}
|
||||
updated_by_name={defaultTo(updatedBy, '')}
|
||||
alertOptions={alertOptions}
|
||||
timezone={defaultTo(schedule?.timezone, '')}
|
||||
@@ -295,7 +309,7 @@ export function CustomCollapseList(
|
||||
);
|
||||
}
|
||||
|
||||
export type DowntimeSchedulesTableData = DowntimeSchedules & {
|
||||
export type DowntimeSchedulesTableData = RuletypesGettablePlannedMaintenanceDTO & {
|
||||
alertOptions: DefaultOptionType[];
|
||||
};
|
||||
|
||||
@@ -309,15 +323,15 @@ export function PlannedDowntimeList({
|
||||
searchValue,
|
||||
}: {
|
||||
downtimeSchedules: UseQueryResult<
|
||||
AxiosResponse<PayloadProps, any>,
|
||||
AxiosError<unknown, any>
|
||||
ListDowntimeSchedules200,
|
||||
ErrorType<RenderErrorResponseDTO>
|
||||
>;
|
||||
alertOptions: DefaultOptionType[];
|
||||
setInitialValues: React.Dispatch<
|
||||
React.SetStateAction<Partial<DowntimeSchedules>>
|
||||
React.SetStateAction<Partial<RuletypesGettablePlannedMaintenanceDTO>>
|
||||
>;
|
||||
setModalOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
handleDeleteDowntime: (id: number, name: string) => void;
|
||||
handleDeleteDowntime: (id: string, name: string) => void;
|
||||
setEditMode: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
searchValue: string | number;
|
||||
}): JSX.Element {
|
||||
@@ -337,17 +351,17 @@ export function PlannedDowntimeList({
|
||||
];
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const tableData = (downtimeSchedules.data?.data?.data || [])
|
||||
const tableData = [...(downtimeSchedules.data?.data || [])]
|
||||
.sort((a, b): number => {
|
||||
if (a?.updatedAt && b?.updatedAt) {
|
||||
return b.updatedAt.localeCompare(a.updatedAt);
|
||||
return dayjs(b.updatedAt).diff(dayjs(a.updatedAt));
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
?.filter(
|
||||
(data) =>
|
||||
data?.name?.includes(searchValue.toLocaleString()) ||
|
||||
data?.id.toLocaleString() === searchValue.toLocaleString(),
|
||||
String(data?.id ?? '') === searchValue.toLocaleString(),
|
||||
)
|
||||
.map?.((data) => {
|
||||
const specificAlertOptions = getAlertOptionsFromIds(
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import { UseMutateAsyncFunction } from 'react-query';
|
||||
import type { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import createDowntimeSchedule from 'api/plannedDowntime/createDowntimeSchedule';
|
||||
import { DeleteSchedulePayloadProps } from 'api/plannedDowntime/deleteDowntimeSchedule';
|
||||
import {
|
||||
DowntimeSchedules,
|
||||
Recurrence,
|
||||
} from 'api/plannedDowntime/getAllDowntimeSchedules';
|
||||
import updateDowntimeSchedule, {
|
||||
DowntimeScheduleUpdatePayload,
|
||||
PayloadProps,
|
||||
} from 'api/plannedDowntime/updateDowntimeSchedule';
|
||||
import { showErrorNotification } from 'components/ExplorerCard/utils';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import type {
|
||||
DeleteDowntimeScheduleByIDPathParameters,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettablePlannedMaintenanceDTO,
|
||||
RuletypesRecurrenceDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { ErrorType } from 'api/generatedAPIInstance';
|
||||
import { AxiosError } from 'axios';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import dayjs from 'dayjs';
|
||||
import { isEmpty, isEqual } from 'lodash-es';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import APIError from 'types/api/error';
|
||||
|
||||
type DateTimeString = string | null | undefined;
|
||||
|
||||
@@ -61,47 +59,54 @@ export const getAlertOptionsFromIds = (
|
||||
alertIds?.includes(alert.value as string),
|
||||
);
|
||||
|
||||
export const recurrenceInfo = (recurrence?: Recurrence | null): string => {
|
||||
export const recurrenceInfo = (
|
||||
recurrence?: RuletypesRecurrenceDTO | null,
|
||||
): string => {
|
||||
if (!recurrence) {
|
||||
return 'No';
|
||||
}
|
||||
|
||||
const { startTime, duration, repeatOn, repeatType, endTime } = recurrence;
|
||||
|
||||
const formattedStartTime = startTime ? formatDateTime(startTime) : '';
|
||||
const formattedEndTime = endTime ? `to ${formatDateTime(endTime)}` : '';
|
||||
const formattedStartTime = startTime
|
||||
? formatDateTime(dayjs(startTime).toISOString())
|
||||
: '';
|
||||
const formattedEndTime = endTime
|
||||
? `to ${formatDateTime(dayjs(endTime).toISOString())}`
|
||||
: '';
|
||||
const weeklyRepeatString = repeatOn ? `on ${repeatOn.join(', ')}` : '';
|
||||
const durationString = duration ? `- Duration: ${duration}` : '';
|
||||
|
||||
return `Repeats - ${repeatType} ${weeklyRepeatString} from ${formattedStartTime} ${formattedEndTime} ${durationString}`;
|
||||
};
|
||||
|
||||
export const defautlInitialValues: Partial<
|
||||
DowntimeSchedules & { editMode: boolean }
|
||||
> = {
|
||||
export const defautlInitialValues = ({
|
||||
name: '',
|
||||
description: '',
|
||||
schedule: {
|
||||
timezone: '',
|
||||
endTime: '',
|
||||
recurrence: null,
|
||||
recurrence: undefined,
|
||||
startTime: '',
|
||||
},
|
||||
alertIds: [],
|
||||
alertIds: [] as string[],
|
||||
createdAt: '',
|
||||
createdBy: '',
|
||||
editMode: false,
|
||||
};
|
||||
} as unknown) as Partial<
|
||||
RuletypesGettablePlannedMaintenanceDTO & { editMode: boolean }
|
||||
>;
|
||||
|
||||
type DeleteDowntimeScheduleProps = {
|
||||
deleteDowntimeScheduleAsync: UseMutateAsyncFunction<
|
||||
DeleteSchedulePayloadProps,
|
||||
Error,
|
||||
number
|
||||
void,
|
||||
ErrorType<RenderErrorResponseDTO>,
|
||||
{ pathParams: DeleteDowntimeScheduleByIDPathParameters }
|
||||
>;
|
||||
notifications: NotificationInstance;
|
||||
showErrorModal: (error: APIError) => void;
|
||||
refetchAllSchedules: VoidFunction;
|
||||
deleteId?: number;
|
||||
deleteId?: string;
|
||||
hideDeleteDowntimeScheduleModal: () => void;
|
||||
clearSearch: () => void;
|
||||
};
|
||||
@@ -113,40 +118,33 @@ export const deleteDowntimeHandler = ({
|
||||
hideDeleteDowntimeScheduleModal,
|
||||
clearSearch,
|
||||
notifications,
|
||||
showErrorModal,
|
||||
}: DeleteDowntimeScheduleProps): void => {
|
||||
if (!deleteId) {
|
||||
const errorMsg = new Error('Something went wrong');
|
||||
console.error('Unable to delete, please provide correct deleteId');
|
||||
showErrorNotification(notifications, errorMsg);
|
||||
notifications.error({ message: 'Something went wrong' });
|
||||
} else {
|
||||
deleteDowntimeScheduleAsync(deleteId, {
|
||||
onSuccess: () => {
|
||||
hideDeleteDowntimeScheduleModal();
|
||||
clearSearch();
|
||||
notifications.success({
|
||||
message: 'Downtime schedule Deleted Successfully',
|
||||
});
|
||||
refetchAllSchedules();
|
||||
deleteDowntimeScheduleAsync(
|
||||
{ pathParams: { id: String(deleteId) } },
|
||||
{
|
||||
onSuccess: () => {
|
||||
hideDeleteDowntimeScheduleModal();
|
||||
clearSearch();
|
||||
notifications.success({
|
||||
message: 'Downtime schedule Deleted Successfully',
|
||||
});
|
||||
refetchAllSchedules();
|
||||
},
|
||||
onError: (err) => {
|
||||
showErrorModal(
|
||||
convertToApiError(err as AxiosError<RenderErrorResponseDTO>) as APIError,
|
||||
);
|
||||
},
|
||||
},
|
||||
onError: (err) => {
|
||||
showErrorNotification(notifications, err);
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const createEditDowntimeSchedule = async (
|
||||
props: DowntimeScheduleUpdatePayload,
|
||||
): Promise<
|
||||
| SuccessResponse<PayloadProps>
|
||||
| ErrorResponse<{ code: string; message: string } | string>
|
||||
> => {
|
||||
if (props.id) {
|
||||
return updateDowntimeSchedule({ ...props });
|
||||
}
|
||||
return createDowntimeSchedule({ ...props.data });
|
||||
};
|
||||
|
||||
export const recurrenceOptions = {
|
||||
doesNotRepeat: {
|
||||
label: 'Does not repeat',
|
||||
@@ -230,19 +228,21 @@ export const getEndTime = ({
|
||||
kind,
|
||||
schedule,
|
||||
}: Partial<
|
||||
DowntimeSchedules & {
|
||||
RuletypesGettablePlannedMaintenanceDTO & {
|
||||
editMode: boolean;
|
||||
}
|
||||
>): string | dayjs.Dayjs => {
|
||||
if (kind === 'fixed') {
|
||||
return schedule?.endTime || '';
|
||||
return schedule?.endTime ? dayjs(schedule.endTime).toISOString() : '';
|
||||
}
|
||||
|
||||
return schedule?.recurrence?.endTime || '';
|
||||
return schedule?.recurrence?.endTime
|
||||
? dayjs(schedule.recurrence.endTime).toISOString()
|
||||
: '';
|
||||
};
|
||||
|
||||
export const isScheduleRecurring = (
|
||||
schedule?: DowntimeSchedules['schedule'],
|
||||
schedule?: RuletypesGettablePlannedMaintenanceDTO['schedule'] | null,
|
||||
): boolean => (schedule ? !isEmpty(schedule?.recurrence) : false);
|
||||
|
||||
function convertUtcOffsetToTimezoneOffset(offsetMinutes: number): string {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { UseQueryResult } from 'react-query';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { PayloadProps } from 'api/plannedDowntime/getAllDowntimeSchedules';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import type {
|
||||
ListDowntimeSchedules200,
|
||||
RenderErrorResponseDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { ErrorType } from 'api/generatedAPIInstance';
|
||||
import {
|
||||
mockLocation,
|
||||
mockQueryParams,
|
||||
@@ -22,45 +25,53 @@ const MOCK_DATE_2 = '2024-01-02';
|
||||
const MOCK_DATE_3 = '2024-01-03';
|
||||
|
||||
const MOCK_DOWNTIME_1 = createMockDowntime({
|
||||
id: 1,
|
||||
id: '1',
|
||||
name: MOCK_DOWNTIME_1_NAME,
|
||||
createdAt: MOCK_DATE_1,
|
||||
updatedAt: MOCK_DATE_1,
|
||||
schedule: buildSchedule({ startTime: MOCK_DATE_1, timezone: 'UTC' }),
|
||||
createdAt: new Date(MOCK_DATE_1),
|
||||
updatedAt: new Date(MOCK_DATE_1),
|
||||
schedule: buildSchedule({
|
||||
startTime: new Date(MOCK_DATE_1),
|
||||
timezone: 'UTC',
|
||||
}),
|
||||
alertIds: [],
|
||||
});
|
||||
|
||||
const MOCK_DOWNTIME_2 = createMockDowntime({
|
||||
id: 2,
|
||||
id: '2',
|
||||
name: MOCK_DOWNTIME_2_NAME,
|
||||
createdAt: MOCK_DATE_2,
|
||||
updatedAt: MOCK_DATE_2,
|
||||
schedule: buildSchedule({ startTime: MOCK_DATE_2, timezone: 'UTC' }),
|
||||
createdAt: new Date(MOCK_DATE_2),
|
||||
updatedAt: new Date(MOCK_DATE_2),
|
||||
schedule: buildSchedule({
|
||||
startTime: new Date(MOCK_DATE_2),
|
||||
timezone: 'UTC',
|
||||
}),
|
||||
alertIds: [],
|
||||
});
|
||||
|
||||
const MOCK_DOWNTIME_3 = createMockDowntime({
|
||||
id: 3,
|
||||
id: '3',
|
||||
name: MOCK_DOWNTIME_3_NAME,
|
||||
createdAt: MOCK_DATE_3,
|
||||
updatedAt: MOCK_DATE_3,
|
||||
schedule: buildSchedule({ startTime: MOCK_DATE_3, timezone: 'UTC' }),
|
||||
createdAt: new Date(MOCK_DATE_3),
|
||||
updatedAt: new Date(MOCK_DATE_3),
|
||||
schedule: buildSchedule({
|
||||
startTime: new Date(MOCK_DATE_3),
|
||||
timezone: 'UTC',
|
||||
}),
|
||||
alertIds: [],
|
||||
});
|
||||
|
||||
const MOCK_DOWNTIME_RESPONSE: Partial<AxiosResponse<PayloadProps>> = {
|
||||
data: {
|
||||
data: [MOCK_DOWNTIME_1, MOCK_DOWNTIME_2, MOCK_DOWNTIME_3],
|
||||
},
|
||||
const MOCK_DOWNTIME_RESPONSE: ListDowntimeSchedules200 = {
|
||||
data: [MOCK_DOWNTIME_1, MOCK_DOWNTIME_2, MOCK_DOWNTIME_3],
|
||||
status: 'success',
|
||||
};
|
||||
|
||||
type DowntimeQueryResult = UseQueryResult<
|
||||
AxiosResponse<PayloadProps>,
|
||||
AxiosError
|
||||
ListDowntimeSchedules200,
|
||||
ErrorType<RenderErrorResponseDTO>
|
||||
>;
|
||||
|
||||
const mockDowntimeQueryResult: Partial<DowntimeQueryResult> = {
|
||||
data: MOCK_DOWNTIME_RESPONSE as AxiosResponse<PayloadProps>,
|
||||
data: MOCK_DOWNTIME_RESPONSE,
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
isError: false,
|
||||
@@ -89,13 +100,27 @@ jest.mock('hooks/useSafeNavigate', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('api/plannedDowntime/getAllDowntimeSchedules', () => ({
|
||||
useGetAllDowntimeSchedules: (): DowntimeQueryResult =>
|
||||
jest.mock('api/generated/services/downtimeschedules', () => ({
|
||||
useListDowntimeSchedules: (): DowntimeQueryResult =>
|
||||
mockDowntimeQueryResult as DowntimeQueryResult,
|
||||
useDeleteDowntimeScheduleByID: (): {
|
||||
mutateAsync: jest.Mock;
|
||||
isLoading: false;
|
||||
} => ({
|
||||
mutateAsync: jest.fn(),
|
||||
isLoading: false,
|
||||
}),
|
||||
}));
|
||||
jest.mock('api/alerts/getAll', () => ({
|
||||
__esModule: true,
|
||||
default: (): Promise<{ payload: [] }> => Promise.resolve({ payload: [] }),
|
||||
jest.mock('api/generated/services/rules', () => ({
|
||||
useListRules: (): {
|
||||
data: { data: { rules: [] } };
|
||||
isError: false;
|
||||
isLoading: false;
|
||||
} => ({
|
||||
data: { data: { rules: [] } },
|
||||
isError: false,
|
||||
isLoading: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('PlannedDowntime Component', () => {
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
import { DowntimeSchedules } from 'api/plannedDowntime/getAllDowntimeSchedules';
|
||||
import type {
|
||||
RuletypesGettablePlannedMaintenanceDTO,
|
||||
RuletypesScheduleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
export const buildSchedule = (
|
||||
schedule: Partial<DowntimeSchedules['schedule']>,
|
||||
): DowntimeSchedules['schedule'] => ({
|
||||
timezone: schedule?.timezone ?? null,
|
||||
startTime: schedule?.startTime ?? null,
|
||||
endTime: schedule?.endTime ?? null,
|
||||
recurrence: schedule?.recurrence ?? null,
|
||||
schedule: Partial<RuletypesScheduleDTO>,
|
||||
): RuletypesScheduleDTO => ({
|
||||
timezone: schedule?.timezone ?? '',
|
||||
startTime: schedule?.startTime,
|
||||
endTime: schedule?.endTime,
|
||||
recurrence: schedule?.recurrence,
|
||||
});
|
||||
|
||||
export const createMockDowntime = (
|
||||
overrides: Partial<DowntimeSchedules>,
|
||||
): DowntimeSchedules => ({
|
||||
id: overrides.id ?? 0,
|
||||
name: overrides.name ?? null,
|
||||
description: overrides.description ?? null,
|
||||
overrides: Partial<RuletypesGettablePlannedMaintenanceDTO>,
|
||||
): RuletypesGettablePlannedMaintenanceDTO => ({
|
||||
id: overrides.id ?? '0',
|
||||
name: overrides.name ?? '',
|
||||
description: overrides.description ?? '',
|
||||
schedule: buildSchedule({
|
||||
timezone: 'UTC',
|
||||
startTime: '2024-01-01',
|
||||
startTime: new Date('2024-01-01'),
|
||||
...overrides.schedule,
|
||||
}),
|
||||
alertIds: overrides.alertIds ?? null,
|
||||
createdAt: overrides.createdAt ?? null,
|
||||
createdBy: overrides.createdBy ?? null,
|
||||
updatedAt: overrides.updatedAt ?? null,
|
||||
updatedBy: overrides.updatedBy ?? null,
|
||||
kind: overrides.kind ?? null,
|
||||
alertIds: overrides.alertIds ?? [],
|
||||
createdAt: overrides.createdAt,
|
||||
createdBy: overrides.createdBy ?? '',
|
||||
updatedAt: overrides.updatedAt,
|
||||
updatedBy: overrides.updatedBy ?? '',
|
||||
kind: overrides.kind ?? '',
|
||||
});
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { useMutation, UseMutationResult } from 'react-query';
|
||||
import createAlertRule, {
|
||||
CreateAlertRuleResponse,
|
||||
} from 'api/alerts/createAlertRule';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
|
||||
|
||||
export function useCreateAlertRule(): UseMutationResult<
|
||||
SuccessResponse<CreateAlertRuleResponse> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2
|
||||
> {
|
||||
return useMutation<
|
||||
SuccessResponse<CreateAlertRuleResponse> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2
|
||||
>({
|
||||
mutationFn: (alertData) => createAlertRule(alertData),
|
||||
});
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { useMutation, UseMutationResult } from 'react-query';
|
||||
import testAlertRule, { TestAlertRuleResponse } from 'api/alerts/testAlertRule';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
|
||||
|
||||
export function useTestAlertRule(): UseMutationResult<
|
||||
SuccessResponse<TestAlertRuleResponse> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2
|
||||
> {
|
||||
return useMutation<
|
||||
SuccessResponse<TestAlertRuleResponse> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2
|
||||
>({
|
||||
mutationFn: (alertData) => testAlertRule(alertData),
|
||||
});
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { useMutation, UseMutationResult } from 'react-query';
|
||||
import updateAlertRule, {
|
||||
UpdateAlertRuleResponse,
|
||||
} from 'api/alerts/updateAlertRule';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PostableAlertRuleV2 } from 'types/api/alerts/alertTypesV2';
|
||||
|
||||
export function useUpdateAlertRule(
|
||||
id: string,
|
||||
): UseMutationResult<
|
||||
SuccessResponse<UpdateAlertRuleResponse> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2
|
||||
> {
|
||||
return useMutation<
|
||||
SuccessResponse<UpdateAlertRuleResponse> | ErrorResponse,
|
||||
Error,
|
||||
PostableAlertRuleV2
|
||||
>({
|
||||
mutationFn: (alertData) => updateAlertRule(id, alertData),
|
||||
});
|
||||
}
|
||||
@@ -191,6 +191,17 @@ export const handlers = [
|
||||
}),
|
||||
),
|
||||
),
|
||||
rest.post('http://localhost/api/v1/changePassword', (_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(403),
|
||||
ctx.json({
|
||||
status: 'error',
|
||||
errorType: 'forbidden',
|
||||
error: 'invalid credentials',
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
rest.get(
|
||||
'http://localhost/api/v3/autocomplete/aggregate_attributes',
|
||||
(req, res, ctx) =>
|
||||
|
||||
@@ -99,7 +99,7 @@ function AlertDetails(): JSX.Element {
|
||||
}, [params]);
|
||||
|
||||
const getDocumentTitle = useMemo(() => {
|
||||
const alertTitle = alertDetailsResponse?.payload?.data?.alert;
|
||||
const alertTitle = alertDetailsResponse?.data?.alert;
|
||||
if (alertTitle) {
|
||||
return alertTitle;
|
||||
}
|
||||
@@ -110,14 +110,15 @@ function AlertDetails(): JSX.Element {
|
||||
return document.title;
|
||||
}
|
||||
return 'Alert Not Found';
|
||||
}, [alertDetailsResponse?.payload?.data?.alert, isTestAlert, isLoading]);
|
||||
}, [alertDetailsResponse?.data?.alert, isTestAlert, isLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = getDocumentTitle;
|
||||
}, [getDocumentTitle]);
|
||||
|
||||
const alertRuleDetails = useMemo(
|
||||
() => alertDetailsResponse?.payload?.data as PostableAlertRuleV2 | undefined,
|
||||
() =>
|
||||
(alertDetailsResponse?.data as unknown) as PostableAlertRuleV2 | undefined,
|
||||
[alertDetailsResponse],
|
||||
);
|
||||
|
||||
@@ -126,12 +127,7 @@ function AlertDetails(): JSX.Element {
|
||||
[alertRuleDetails],
|
||||
);
|
||||
|
||||
if (
|
||||
isError ||
|
||||
!isValidRuleId ||
|
||||
(alertDetailsResponse && alertDetailsResponse.statusCode !== 200) ||
|
||||
(!isLoading && !alertRuleDetails)
|
||||
) {
|
||||
if (isError || !isValidRuleId || (!isLoading && !alertRuleDetails)) {
|
||||
return <AlertNotFound isTestAlert={isTestAlert} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import type { RuletypesGettableRuleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import CreateAlertV2Header from 'container/CreateAlertV2/CreateAlertHeader';
|
||||
import LineClampedText from 'periscope/components/LineClampedText/LineClampedText';
|
||||
import { useAlertRule } from 'providers/Alert';
|
||||
@@ -6,7 +7,6 @@ import {
|
||||
NEW_ALERT_SCHEMA_VERSION,
|
||||
PostableAlertRuleV2,
|
||||
} from 'types/api/alerts/alertTypesV2';
|
||||
import { GettableAlert } from 'types/api/alerts/get';
|
||||
|
||||
import AlertActionButtons from './ActionButtons/ActionButtons';
|
||||
import AlertLabels from './AlertLabels/AlertLabels';
|
||||
@@ -16,7 +16,7 @@ import AlertState from './AlertState/AlertState';
|
||||
import './AlertHeader.styles.scss';
|
||||
|
||||
export type AlertHeaderProps = {
|
||||
alertDetails: GettableAlert | PostableAlertRuleV2;
|
||||
alertDetails: RuletypesGettableRuleDTO | PostableAlertRuleV2;
|
||||
};
|
||||
function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
|
||||
const { state, alert: alertName, labels } = alertDetails;
|
||||
|
||||
@@ -3,15 +3,25 @@ import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||
import { generatePath, useLocation } from 'react-router-dom';
|
||||
import { TablePaginationConfig, TableProps } from 'antd';
|
||||
import type { FilterValue, SorterResult } from 'antd/es/table/interface';
|
||||
import deleteAlerts from 'api/alerts/delete';
|
||||
import get from 'api/alerts/get';
|
||||
import getAll from 'api/alerts/getAll';
|
||||
import patchAlert from 'api/alerts/patch';
|
||||
import ruleStats from 'api/alerts/ruleStats';
|
||||
import save from 'api/alerts/save';
|
||||
import timelineGraph from 'api/alerts/timelineGraph';
|
||||
import timelineTable from 'api/alerts/timelineTable';
|
||||
import topContributors from 'api/alerts/topContributors';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import {
|
||||
createRule,
|
||||
deleteRuleByID,
|
||||
patchRuleByID,
|
||||
updateRuleByID,
|
||||
useGetRuleByID,
|
||||
useListRules,
|
||||
} from 'api/generated/services/rules';
|
||||
import type {
|
||||
GetRuleByID200,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesPostableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { TabRoutes } from 'components/RouteTab/types';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
@@ -21,7 +31,6 @@ import { TIMELINE_TABLE_PAGE_SIZE } from 'container/AlertHistory/constants';
|
||||
import { AlertDetailsTab, TimelineFilter } from 'container/AlertHistory/types';
|
||||
import { urlKey } from 'container/AllError/utils';
|
||||
import { DEFAULT_TIME_RANGE } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import useAxiosError from 'hooks/useAxiosError';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
@@ -34,6 +43,7 @@ import { OrderPreferenceItems } from 'pages/Logs/config';
|
||||
import BetaTag from 'periscope/components/BetaTag/BetaTag';
|
||||
import PaginationInfoText from 'periscope/components/PaginationInfoText/PaginationInfoText';
|
||||
import { useAlertRule } from 'providers/Alert';
|
||||
import { useErrorModal } from 'providers/ErrorModalProvider';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import {
|
||||
AlertDef,
|
||||
@@ -43,7 +53,7 @@ import {
|
||||
AlertRuleTimelineTableResponsePayload,
|
||||
AlertRuleTopContributorsPayload,
|
||||
} from 'types/api/alerts/def';
|
||||
import { PayloadProps } from 'types/api/alerts/get';
|
||||
import APIError from 'types/api/error';
|
||||
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { nanoToMilli } from 'utils/timeUtils';
|
||||
|
||||
@@ -142,10 +152,7 @@ export const useRouteTabUtils = (): { routes: TabRoutes[] } => {
|
||||
type Props = {
|
||||
ruleId: string | null;
|
||||
isValidRuleId: boolean;
|
||||
alertDetailsResponse:
|
||||
| SuccessResponse<PayloadProps, unknown>
|
||||
| ErrorResponse
|
||||
| undefined;
|
||||
alertDetailsResponse: GetRuleByID200 | undefined;
|
||||
isLoading: boolean;
|
||||
isRefetching: boolean;
|
||||
isError: boolean;
|
||||
@@ -161,14 +168,15 @@ export const useGetAlertRuleDetails = (): Props => {
|
||||
data: alertDetailsResponse,
|
||||
isRefetching,
|
||||
isError,
|
||||
} = useQuery([REACT_QUERY_KEY.ALERT_RULE_DETAILS, ruleId], {
|
||||
queryFn: () =>
|
||||
get({
|
||||
id: ruleId || '',
|
||||
}),
|
||||
enabled: isValidRuleId,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
} = useGetRuleByID(
|
||||
{ id: ruleId || '' },
|
||||
{
|
||||
query: {
|
||||
enabled: isValidRuleId,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
ruleId,
|
||||
@@ -376,6 +384,15 @@ export const useTimelineTable = ({
|
||||
return { paginationConfig, onChangeHandler };
|
||||
};
|
||||
|
||||
const handleMutationError = (
|
||||
showErrorModal: (error: APIError) => void,
|
||||
error: unknown,
|
||||
): void => {
|
||||
showErrorModal(
|
||||
convertToApiError(error as AxiosError<RenderErrorResponseDTO>) as APIError,
|
||||
);
|
||||
};
|
||||
|
||||
export const useAlertRuleStatusToggle = ({
|
||||
ruleId,
|
||||
}: {
|
||||
@@ -387,24 +404,28 @@ export const useAlertRuleStatusToggle = ({
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const handleError = useAxiosError();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const { mutate: toggleAlertState } = useMutation(
|
||||
[REACT_QUERY_KEY.TOGGLE_ALERT_STATE, ruleId],
|
||||
patchAlert,
|
||||
(args: { id: string; data: Record<string, unknown> }) =>
|
||||
patchRuleByID(
|
||||
{ id: args.id },
|
||||
(args.data as unknown) as RuletypesPostableRuleDTO,
|
||||
),
|
||||
{
|
||||
onSuccess: (data) => {
|
||||
setAlertRuleState(data?.payload?.state);
|
||||
setAlertRuleState(data?.data?.state);
|
||||
queryClient.refetchQueries([REACT_QUERY_KEY.ALERT_RULE_DETAILS, ruleId]);
|
||||
notifications.success({
|
||||
message: `Alert has been ${
|
||||
data?.payload?.state === 'disabled' ? 'disabled' : 'enabled'
|
||||
data?.data?.state === 'disabled' ? 'disabled' : 'enabled'
|
||||
}.`,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
queryClient.refetchQueries([REACT_QUERY_KEY.ALERT_RULE_DETAILS, ruleId]);
|
||||
handleError(error);
|
||||
handleMutationError(showErrorModal, error);
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -431,14 +452,14 @@ export const useAlertRuleDuplicate = ({
|
||||
|
||||
const params = useUrlQuery();
|
||||
|
||||
const { refetch } = useQuery(REACT_QUERY_KEY.GET_ALL_ALLERTS, {
|
||||
queryFn: getAll,
|
||||
cacheTime: 0,
|
||||
const { refetch } = useListRules({
|
||||
query: { cacheTime: 0 },
|
||||
});
|
||||
const handleError = useAxiosError();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
const { mutate: duplicateAlert } = useMutation(
|
||||
[REACT_QUERY_KEY.DUPLICATE_ALERT_RULE],
|
||||
save,
|
||||
(args: { data: AlertDef }) =>
|
||||
createRule((args.data as unknown) as RuletypesPostableRuleDTO),
|
||||
{
|
||||
onSuccess: async () => {
|
||||
notifications.success({
|
||||
@@ -447,18 +468,14 @@ export const useAlertRuleDuplicate = ({
|
||||
|
||||
const { data: allAlertsData } = await refetch();
|
||||
|
||||
if (
|
||||
allAlertsData &&
|
||||
allAlertsData.payload &&
|
||||
allAlertsData.payload.length > 0
|
||||
) {
|
||||
const clonedAlert =
|
||||
allAlertsData.payload[allAlertsData.payload.length - 1];
|
||||
const rules = allAlertsData?.data?.rules;
|
||||
if (rules && rules.length > 0) {
|
||||
const clonedAlert = rules[rules.length - 1];
|
||||
params.set(QueryParams.ruleId, String(clonedAlert.id));
|
||||
history.push(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`);
|
||||
}
|
||||
},
|
||||
onError: handleError,
|
||||
onError: (error) => handleMutationError(showErrorModal, error),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -484,18 +501,22 @@ export const useAlertRuleUpdate = ({
|
||||
isLoading: boolean;
|
||||
} => {
|
||||
const { notifications } = useNotifications();
|
||||
const handleError = useAxiosError();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const { mutate: updateAlertRule, isLoading } = useMutation(
|
||||
[REACT_QUERY_KEY.UPDATE_ALERT_RULE, alertDetails.id],
|
||||
save,
|
||||
(args: { data: AlertDef; id: string }) =>
|
||||
updateRuleByID(
|
||||
{ id: args.id },
|
||||
(args.data as unknown) as RuletypesPostableRuleDTO,
|
||||
),
|
||||
{
|
||||
onMutate: () => setUpdatedName(intermediateName),
|
||||
onSuccess: () =>
|
||||
notifications.success({ message: 'Alert renamed successfully' }),
|
||||
onError: (error) => {
|
||||
setUpdatedName(alertDetails.alert);
|
||||
handleError(error);
|
||||
handleMutationError(showErrorModal, error);
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -503,7 +524,7 @@ export const useAlertRuleUpdate = ({
|
||||
const handleAlertUpdate = (): void => {
|
||||
updateAlertRule({
|
||||
data: { ...alertDetails, alert: intermediateName },
|
||||
id: alertDetails.id,
|
||||
id: alertDetails.id || '',
|
||||
});
|
||||
};
|
||||
|
||||
@@ -518,11 +539,11 @@ export const useAlertRuleDelete = ({
|
||||
handleAlertDelete: () => void;
|
||||
} => {
|
||||
const { notifications } = useNotifications();
|
||||
const handleError = useAxiosError();
|
||||
const { showErrorModal } = useErrorModal();
|
||||
|
||||
const { mutate: deleteAlert } = useMutation(
|
||||
[REACT_QUERY_KEY.REMOVE_ALERT_RULE, ruleId],
|
||||
deleteAlerts,
|
||||
(args: { id: string }) => deleteRuleByID({ id: args.id }),
|
||||
{
|
||||
onSuccess: async () => {
|
||||
notifications.success({
|
||||
@@ -531,7 +552,7 @@ export const useAlertRuleDelete = ({
|
||||
|
||||
history.push(ROUTES.LIST_ALL_ALERT);
|
||||
},
|
||||
onError: handleError,
|
||||
onError: (error) => handleMutationError(showErrorModal, error),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Button, Card } from 'antd';
|
||||
import get from 'api/alerts/get';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { useGetRuleByID } from 'api/generated/services/rules';
|
||||
import type {
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesGettableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import ROUTES from 'constants/routes';
|
||||
import EditRulesContainer from 'container/EditRules';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
@@ -16,6 +20,7 @@ import {
|
||||
NEW_ALERT_SCHEMA_VERSION,
|
||||
PostableAlertRuleV2,
|
||||
} from 'types/api/alerts/alertTypesV2';
|
||||
import { AlertDef } from 'types/api/alerts/def';
|
||||
|
||||
import {
|
||||
errorMessageReceivedFromBackend,
|
||||
@@ -33,16 +38,14 @@ function EditRules(): JSX.Element {
|
||||
|
||||
const isValidRuleId = ruleId !== null && String(ruleId).length !== 0;
|
||||
|
||||
const { isLoading, data, isRefetching, isError } = useQuery(
|
||||
[REACT_QUERY_KEY.ALERT_RULE_DETAILS, ruleId],
|
||||
const { isLoading, data, isRefetching, isError, error } = useGetRuleByID(
|
||||
{ id: ruleId || '' },
|
||||
{
|
||||
queryFn: () =>
|
||||
get({
|
||||
id: ruleId || '',
|
||||
}),
|
||||
enabled: isValidRuleId,
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
query: {
|
||||
enabled: isValidRuleId,
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -65,18 +68,26 @@ function EditRules(): JSX.Element {
|
||||
}
|
||||
}, [isValidRuleId, ruleId, notifications, safeNavigate]);
|
||||
|
||||
const ruleData: RuletypesGettableRuleDTO | undefined = data?.data;
|
||||
|
||||
const apiError = useMemo(
|
||||
() => convertToApiError(error as AxiosError<RenderErrorResponseDTO> | null),
|
||||
[error],
|
||||
);
|
||||
|
||||
if (
|
||||
(isError && !isValidRuleId) ||
|
||||
ruleId == null ||
|
||||
(data?.payload?.data === undefined && !isLoading)
|
||||
(ruleData === undefined && !isLoading)
|
||||
) {
|
||||
const errorMsg = apiError?.getErrorMessage() || '';
|
||||
return (
|
||||
<div className="edit-rules-container edit-rules-container--error">
|
||||
<Card size="small" className="edit-rules-card">
|
||||
<p className="content">
|
||||
{data?.message === errorMessageReceivedFromBackend
|
||||
{errorMsg === errorMessageReceivedFromBackend
|
||||
? improvedErrorMessage
|
||||
: data?.error || t('something_went_wrong')}
|
||||
: errorMsg || t('something_went_wrong')}
|
||||
</p>
|
||||
<div className="btn-container">
|
||||
<Button type="default" size="large" onClick={clickHandler}>
|
||||
@@ -88,20 +99,20 @@ function EditRules(): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading || isRefetching || !data?.payload) {
|
||||
if (isLoading || isRefetching || !ruleData) {
|
||||
return <Spinner tip="Loading Rules..." />;
|
||||
}
|
||||
|
||||
let initialV2AlertValue: PostableAlertRuleV2 | null = null;
|
||||
if (data.payload.data.schemaVersion === NEW_ALERT_SCHEMA_VERSION) {
|
||||
initialV2AlertValue = data.payload.data as PostableAlertRuleV2;
|
||||
if (ruleData.schemaVersion === NEW_ALERT_SCHEMA_VERSION) {
|
||||
initialV2AlertValue = (ruleData as unknown) as PostableAlertRuleV2;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="edit-rules-container">
|
||||
<EditRulesContainer
|
||||
ruleId={ruleId || ''}
|
||||
initialValue={data.payload.data}
|
||||
initialValue={(ruleData as unknown) as AlertDef}
|
||||
initialV2AlertValue={initialV2AlertValue}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { AlertDef } from './def';
|
||||
|
||||
export interface Props {
|
||||
id: AlertDef['id'];
|
||||
}
|
||||
|
||||
export interface GettableAlert extends AlertDef {
|
||||
id: string;
|
||||
alert: string;
|
||||
state: string;
|
||||
disabled: boolean;
|
||||
createAt: string;
|
||||
createBy: string;
|
||||
updateAt: string;
|
||||
updateBy: string;
|
||||
schemaVersion: string;
|
||||
}
|
||||
|
||||
export type PayloadProps = {
|
||||
data: GettableAlert;
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
import { GettableAlert } from './get';
|
||||
|
||||
export type PayloadProps = GettableAlert[];
|
||||
@@ -1,12 +0,0 @@
|
||||
import { GettableAlert } from './get';
|
||||
|
||||
export type PayloadProps = GettableAlert;
|
||||
|
||||
export interface PatchProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
id?: string;
|
||||
data: PatchProps;
|
||||
}
|
||||
12
frontend/src/types/api/user/changeMyPassword.ts
Normal file
12
frontend/src/types/api/user/changeMyPassword.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { User } from 'types/reducer/app';
|
||||
|
||||
export interface Props {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
userId: User['userId'];
|
||||
}
|
||||
|
||||
export interface PayloadProps {
|
||||
status: string;
|
||||
data: string;
|
||||
}
|
||||
15
frontend/src/types/api/user/getResetPasswordToken.ts
Normal file
15
frontend/src/types/api/user/getResetPasswordToken.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { User } from 'types/reducer/app';
|
||||
|
||||
export interface Props {
|
||||
userId: User['userId'];
|
||||
}
|
||||
|
||||
export interface GetResetPasswordToken {
|
||||
token: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface PayloadProps {
|
||||
data: GetResetPasswordToken;
|
||||
status: string;
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/session"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/zeus"
|
||||
@@ -59,6 +60,7 @@ type provider struct {
|
||||
cloudIntegrationHandler cloudintegration.Handler
|
||||
ruleStateHistoryHandler rulestatehistory.Handler
|
||||
alertmanagerHandler alertmanager.Handler
|
||||
rulerHandler ruler.Handler
|
||||
}
|
||||
|
||||
func NewFactory(
|
||||
@@ -86,6 +88,7 @@ func NewFactory(
|
||||
cloudIntegrationHandler cloudintegration.Handler,
|
||||
ruleStateHistoryHandler rulestatehistory.Handler,
|
||||
alertmanagerHandler alertmanager.Handler,
|
||||
rulerHandler ruler.Handler,
|
||||
) factory.ProviderFactory[apiserver.APIServer, apiserver.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, providerSettings factory.ProviderSettings, config apiserver.Config) (apiserver.APIServer, error) {
|
||||
return newProvider(
|
||||
@@ -116,6 +119,7 @@ func NewFactory(
|
||||
cloudIntegrationHandler,
|
||||
ruleStateHistoryHandler,
|
||||
alertmanagerHandler,
|
||||
rulerHandler,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -148,6 +152,7 @@ func newProvider(
|
||||
cloudIntegrationHandler cloudintegration.Handler,
|
||||
ruleStateHistoryHandler rulestatehistory.Handler,
|
||||
alertmanagerHandler alertmanager.Handler,
|
||||
rulerHandler ruler.Handler,
|
||||
) (apiserver.APIServer, error) {
|
||||
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/apiserver/signozapiserver")
|
||||
router := mux.NewRouter().UseEncodedPath()
|
||||
@@ -178,6 +183,7 @@ func newProvider(
|
||||
cloudIntegrationHandler: cloudIntegrationHandler,
|
||||
ruleStateHistoryHandler: ruleStateHistoryHandler,
|
||||
alertmanagerHandler: alertmanagerHandler,
|
||||
rulerHandler: rulerHandler,
|
||||
}
|
||||
|
||||
provider.authZ = middleware.NewAuthZ(settings.Logger(), orgGetter, authz)
|
||||
@@ -282,6 +288,10 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := provider.addRulerRoutes(router); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
200
pkg/apiserver/signozapiserver/ruler.go
Normal file
200
pkg/apiserver/signozapiserver/ruler.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package signozapiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/http/handler"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (provider *provider) addRulerRoutes(router *mux.Router) error {
|
||||
if err := router.Handle("/api/v1/rules", handler.New(provider.authZ.ViewAccess(provider.rulerHandler.ListRules), handler.OpenAPIDef{
|
||||
ID: "ListRules",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "List alert rules",
|
||||
Description: "This endpoint lists all alert rules with their current evaluation state",
|
||||
Response: new(ruletypes.GettableRules),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/rules/{id}", handler.New(provider.authZ.ViewAccess(provider.rulerHandler.GetRuleByID), handler.OpenAPIDef{
|
||||
ID: "GetRuleByID",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Get alert rule by ID",
|
||||
Description: "This endpoint returns an alert rule by ID",
|
||||
Response: new(ruletypes.GettableRule),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/rules", handler.New(provider.authZ.EditAccess(provider.rulerHandler.CreateRule), handler.OpenAPIDef{
|
||||
ID: "CreateRule",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Create alert rule",
|
||||
Description: "This endpoint creates a new alert rule",
|
||||
Request: new(ruletypes.PostableRule),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(ruletypes.GettableRule),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/rules/{id}", handler.New(provider.authZ.EditAccess(provider.rulerHandler.UpdateRuleByID), handler.OpenAPIDef{
|
||||
ID: "UpdateRuleByID",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Update alert rule",
|
||||
Description: "This endpoint updates an alert rule by ID",
|
||||
Request: new(ruletypes.PostableRule),
|
||||
RequestContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/rules/{id}", handler.New(provider.authZ.EditAccess(provider.rulerHandler.DeleteRuleByID), handler.OpenAPIDef{
|
||||
ID: "DeleteRuleByID",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Delete alert rule",
|
||||
Description: "This endpoint deletes an alert rule by ID",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodDelete).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/rules/{id}", handler.New(provider.authZ.EditAccess(provider.rulerHandler.PatchRuleByID), handler.OpenAPIDef{
|
||||
ID: "PatchRuleByID",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Patch alert rule",
|
||||
Description: "This endpoint applies a partial update to an alert rule by ID",
|
||||
Request: new(ruletypes.PostableRule),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(ruletypes.GettableRule),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPatch).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/rules/test", handler.New(provider.authZ.EditAccess(provider.rulerHandler.TestRule), handler.OpenAPIDef{
|
||||
ID: "TestRule",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Test alert rule",
|
||||
Description: "This endpoint fires a test notification for the given rule definition",
|
||||
Request: new(ruletypes.PostableRule),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(ruletypes.GettableTestRule),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/testRule", handler.New(provider.authZ.EditAccess(provider.rulerHandler.TestRule), handler.OpenAPIDef{
|
||||
ID: "TestRuleDeprecated",
|
||||
Tags: []string{"rules"},
|
||||
Summary: "Test alert rule (deprecated)",
|
||||
Description: "Deprecated: use /api/v1/rules/test instead",
|
||||
Request: new(ruletypes.PostableRule),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(ruletypes.GettableTestRule),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest},
|
||||
Deprecated: true,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/downtime_schedules", handler.New(provider.authZ.ViewAccess(provider.rulerHandler.ListDowntimeSchedules), handler.OpenAPIDef{
|
||||
ID: "ListDowntimeSchedules",
|
||||
Tags: []string{"downtimeschedules"},
|
||||
Summary: "List downtime schedules",
|
||||
Description: "This endpoint lists all planned maintenance / downtime schedules",
|
||||
RequestQuery: new(ruletypes.ListPlannedMaintenanceParams),
|
||||
Response: make([]*ruletypes.GettablePlannedMaintenance, 0),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/downtime_schedules/{id}", handler.New(provider.authZ.ViewAccess(provider.rulerHandler.GetDowntimeScheduleByID), handler.OpenAPIDef{
|
||||
ID: "GetDowntimeScheduleByID",
|
||||
Tags: []string{"downtimeschedules"},
|
||||
Summary: "Get downtime schedule by ID",
|
||||
Description: "This endpoint returns a downtime schedule by ID",
|
||||
Response: new(ruletypes.GettablePlannedMaintenance),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/downtime_schedules", handler.New(provider.authZ.EditAccess(provider.rulerHandler.CreateDowntimeSchedule), handler.OpenAPIDef{
|
||||
ID: "CreateDowntimeSchedule",
|
||||
Tags: []string{"downtimeschedules"},
|
||||
Summary: "Create downtime schedule",
|
||||
Description: "This endpoint creates a new planned maintenance / downtime schedule",
|
||||
Request: new(ruletypes.GettablePlannedMaintenance),
|
||||
RequestContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/downtime_schedules/{id}", handler.New(provider.authZ.EditAccess(provider.rulerHandler.UpdateDowntimeScheduleByID), handler.OpenAPIDef{
|
||||
ID: "UpdateDowntimeScheduleByID",
|
||||
Tags: []string{"downtimeschedules"},
|
||||
Summary: "Update downtime schedule",
|
||||
Description: "This endpoint updates a downtime schedule by ID",
|
||||
Request: new(ruletypes.GettablePlannedMaintenance),
|
||||
RequestContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/downtime_schedules/{id}", handler.New(provider.authZ.EditAccess(provider.rulerHandler.DeleteDowntimeScheduleByID), handler.OpenAPIDef{
|
||||
ID: "DeleteDowntimeScheduleByID",
|
||||
Tags: []string{"downtimeschedules"},
|
||||
Summary: "Delete downtime schedule",
|
||||
Description: "This endpoint deletes a downtime schedule by ID",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodDelete).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -213,8 +213,8 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/getResetPasswordToken/{id}", handler.New(provider.authZ.AdminAccess(provider.userHandler.GetResetPasswordTokenDeprecated), handler.OpenAPIDef{
|
||||
ID: "GetResetPasswordTokenDeprecated",
|
||||
if err := router.Handle("/api/v1/getResetPasswordToken/{id}", handler.New(provider.authZ.AdminAccess(provider.userHandler.GetResetPasswordToken), handler.OpenAPIDef{
|
||||
ID: "GetResetPasswordToken",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get reset password token",
|
||||
Description: "This endpoint returns the reset password token by id",
|
||||
@@ -224,46 +224,12 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
Deprecated: true,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/users/{id}/reset_password_tokens", handler.New(provider.authZ.AdminAccess(provider.userHandler.GetResetPasswordToken), handler.OpenAPIDef{
|
||||
ID: "GetResetPasswordToken",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get reset password token for a user",
|
||||
Description: "This endpoint returns the existing reset password token for a user.",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(types.ResetPasswordToken),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/users/{id}/reset_password_tokens", handler.New(provider.authZ.AdminAccess(provider.userHandler.CreateResetPasswordToken), handler.OpenAPIDef{
|
||||
ID: "CreateResetPasswordToken",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Create or regenerate reset password token for a user",
|
||||
Description: "This endpoint creates or regenerates a reset password token for a user. If a valid token exists, it is returned. If expired, a new one is created.",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(types.ResetPasswordToken),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusCreated,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/resetPassword", handler.New(provider.authZ.OpenAccess(provider.userHandler.ResetPassword), handler.OpenAPIDef{
|
||||
ID: "ResetPassword",
|
||||
Tags: []string{"users"},
|
||||
@@ -281,11 +247,11 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/users/me/factor_password", handler.New(provider.authZ.OpenAccess(provider.userHandler.ChangePassword), handler.OpenAPIDef{
|
||||
ID: "UpdateMyPassword",
|
||||
if err := router.Handle("/api/v1/changePassword/{id}", handler.New(provider.authZ.SelfAccess(provider.userHandler.ChangePassword), handler.OpenAPIDef{
|
||||
ID: "ChangePassword",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Updates my password",
|
||||
Description: "This endpoint updates the password of the user I belong to",
|
||||
Summary: "Change password",
|
||||
Description: "This endpoint changes the password by id",
|
||||
Request: new(types.ChangePasswordRequest),
|
||||
RequestContentType: "application/json",
|
||||
Response: nil,
|
||||
@@ -294,7 +260,7 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -218,10 +218,6 @@ func (module *getter) GetRolesByUserID(ctx context.Context, userID valuer.UUID)
|
||||
return userRoles, nil
|
||||
}
|
||||
|
||||
func (module *getter) GetResetPasswordTokenByOrgIDAndUserID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.ResetPasswordToken, error) {
|
||||
return module.store.GetResetPasswordTokenByOrgIDAndUserID(ctx, orgID, userID)
|
||||
}
|
||||
|
||||
func (module *getter) GetUsersByOrgIDAndRoleID(ctx context.Context, orgID valuer.UUID, roleID valuer.UUID) ([]*types.User, error) {
|
||||
return module.store.GetUsersByOrgIDAndRoleID(ctx, orgID, roleID)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func NewHandler(setter root.Setter, getter root.Getter) root.Handler {
|
||||
return &handler{setter: setter, getter: getter}
|
||||
}
|
||||
|
||||
func (handler *handler) CreateInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) CreateInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -41,7 +41,7 @@ func (handler *handler) CreateInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
invites, err := handler.setter.CreateBulkInvite(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.IdentityID()), valuer.MustNewEmail(claims.Email), &types.PostableBulkInviteRequest{
|
||||
invites, err := h.setter.CreateBulkInvite(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.IdentityID()), valuer.MustNewEmail(claims.Email), &types.PostableBulkInviteRequest{
|
||||
Invites: []types.PostableInvite{req},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -52,7 +52,7 @@ func (handler *handler) CreateInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
render.Success(rw, http.StatusCreated, invites[0])
|
||||
}
|
||||
|
||||
func (handler *handler) CreateBulkInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) CreateBulkInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -74,7 +74,7 @@ func (handler *handler) CreateBulkInvite(rw http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
_, err = handler.setter.CreateBulkInvite(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.IdentityID()), valuer.MustNewEmail(claims.Email), &req)
|
||||
_, err = h.setter.CreateBulkInvite(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.IdentityID()), valuer.MustNewEmail(claims.Email), &req)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
@@ -83,7 +83,7 @@ func (handler *handler) CreateBulkInvite(rw http.ResponseWriter, r *http.Request
|
||||
render.Success(rw, http.StatusCreated, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) GetUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -95,7 +95,7 @@ func (handler *handler) GetUserDeprecated(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.getter.GetDeprecatedUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(id))
|
||||
user, err := h.getter.GetDeprecatedUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(id))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -104,7 +104,7 @@ func (handler *handler) GetUserDeprecated(w http.ResponseWriter, r *http.Request
|
||||
render.Success(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (handler *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -116,13 +116,13 @@ func (handler *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID))
|
||||
user, err := h.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
userRoles, err := handler.getter.GetRolesByUserID(ctx, user.ID)
|
||||
userRoles, err := h.getter.GetRolesByUserID(ctx, user.ID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -136,7 +136,7 @@ func (handler *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, userWithRoles)
|
||||
}
|
||||
|
||||
func (handler *handler) GetMyUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetMyUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -146,7 +146,7 @@ func (handler *handler) GetMyUserDeprecated(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.getter.GetDeprecatedUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID))
|
||||
user, err := h.getter.GetDeprecatedUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -155,7 +155,7 @@ func (handler *handler) GetMyUserDeprecated(w http.ResponseWriter, r *http.Reque
|
||||
render.Success(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (handler *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -165,13 +165,13 @@ func (handler *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID))
|
||||
user, err := h.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
userRoles, err := handler.getter.GetRolesByUserID(ctx, user.ID)
|
||||
userRoles, err := h.getter.GetRolesByUserID(ctx, user.ID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -185,7 +185,7 @@ func (handler *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, userWithRoles)
|
||||
}
|
||||
|
||||
func (handler *handler) UpdateMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) UpdateMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -201,7 +201,7 @@ func (handler *handler) UpdateMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = handler.setter.UpdateUser(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID), updatableUser)
|
||||
_, err = h.setter.UpdateUser(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID), updatableUser)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -210,7 +210,7 @@ func (handler *handler) UpdateMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) ListUsersDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) ListUsersDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -220,7 +220,7 @@ func (handler *handler) ListUsersDeprecated(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
users, err := handler.getter.ListDeprecatedUsersByOrgID(ctx, valuer.MustNewUUID(claims.OrgID))
|
||||
users, err := h.getter.ListDeprecatedUsersByOrgID(ctx, valuer.MustNewUUID(claims.OrgID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -229,7 +229,7 @@ func (handler *handler) ListUsersDeprecated(w http.ResponseWriter, r *http.Reque
|
||||
render.Success(w, http.StatusOK, users)
|
||||
}
|
||||
|
||||
func (handler *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -239,7 +239,7 @@ func (handler *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
users, err := handler.getter.ListUsersByOrgID(ctx, valuer.MustNewUUID(claims.OrgID))
|
||||
users, err := h.getter.ListUsersByOrgID(ctx, valuer.MustNewUUID(claims.OrgID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -248,7 +248,7 @@ func (handler *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, users)
|
||||
}
|
||||
|
||||
func (handler *handler) UpdateUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) UpdateUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -266,7 +266,7 @@ func (handler *handler) UpdateUserDeprecated(w http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
updatedUser, err := handler.setter.UpdateUserDeprecated(ctx, valuer.MustNewUUID(claims.OrgID), id, &user)
|
||||
updatedUser, err := h.setter.UpdateUserDeprecated(ctx, valuer.MustNewUUID(claims.OrgID), id, &user)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -275,7 +275,7 @@ func (handler *handler) UpdateUserDeprecated(w http.ResponseWriter, r *http.Requ
|
||||
render.Success(w, http.StatusOK, updatedUser)
|
||||
}
|
||||
|
||||
func (handler *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -298,7 +298,7 @@ func (handler *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = handler.setter.UpdateUser(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), updatableUser)
|
||||
_, err = h.setter.UpdateUser(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), updatableUser)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -307,7 +307,7 @@ func (handler *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -319,7 +319,7 @@ func (handler *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := handler.setter.DeleteUser(ctx, valuer.MustNewUUID(claims.OrgID), id, claims.IdentityID()); err != nil {
|
||||
if err := h.setter.DeleteUser(ctx, valuer.MustNewUUID(claims.OrgID), id, claims.IdentityID()); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func (handler *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) GetResetPasswordTokenDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
func (handler *handler) GetResetPasswordToken(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -354,62 +354,6 @@ func (handler *handler) GetResetPasswordTokenDeprecated(w http.ResponseWriter, r
|
||||
render.Success(w, http.StatusOK, token)
|
||||
}
|
||||
|
||||
func (handler *handler) GetResetPasswordToken(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
userID, err := valuer.NewUUID(mux.Vars(r)["id"])
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := handler.getter.GetResetPasswordTokenByOrgIDAndUserID(ctx, valuer.MustNewUUID(claims.OrgID), userID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, token)
|
||||
}
|
||||
|
||||
func (handler *handler) CreateResetPasswordToken(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
userID, err := valuer.NewUUID(mux.Vars(r)["id"])
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), userID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := handler.setter.GetOrCreateResetPasswordToken(ctx, user.ID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusCreated, token)
|
||||
}
|
||||
|
||||
func (handler *handler) ResetPassword(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
@@ -433,19 +377,13 @@ func (handler *handler) ChangePassword(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
var req types.ChangePasswordRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.setter.UpdatePassword(ctx, valuer.MustNewUUID(claims.UserID), req.OldPassword, req.NewPassword)
|
||||
err := handler.setter.UpdatePassword(ctx, req.UserID, req.OldPassword, req.NewPassword)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -454,7 +392,7 @@ func (handler *handler) ChangePassword(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) ForgotPassword(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) ForgotPassword(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -464,7 +402,7 @@ func (handler *handler) ForgotPassword(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err := handler.setter.ForgotPassword(ctx, req.OrgID, req.Email, req.FrontendBaseURL)
|
||||
err := h.setter.ForgotPassword(ctx, req.OrgID, req.Email, req.FrontendBaseURL)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -473,7 +411,7 @@ func (handler *handler) ForgotPassword(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) GetRolesByUserID(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetRolesByUserID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -485,13 +423,13 @@ func (handler *handler) GetRolesByUserID(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID))
|
||||
user, err := h.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
userRoles, err := handler.getter.GetRolesByUserID(ctx, user.ID)
|
||||
userRoles, err := h.getter.GetRolesByUserID(ctx, user.ID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -505,7 +443,7 @@ func (handler *handler) GetRolesByUserID(w http.ResponseWriter, r *http.Request)
|
||||
render.Success(w, http.StatusOK, roles)
|
||||
}
|
||||
|
||||
func (handler *handler) SetRoleByUserID(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) SetRoleByUserID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -533,7 +471,7 @@ func (handler *handler) SetRoleByUserID(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
if err := handler.setter.AddUserRole(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), postableRole.Name); err != nil {
|
||||
if err := h.setter.AddUserRole(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), postableRole.Name); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
@@ -541,7 +479,7 @@ func (handler *handler) SetRoleByUserID(w http.ResponseWriter, r *http.Request)
|
||||
render.Success(w, http.StatusOK, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) RemoveUserRoleByRoleID(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) RemoveUserRoleByRoleID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -559,7 +497,7 @@ func (handler *handler) RemoveUserRoleByRoleID(w http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
|
||||
if err := handler.setter.RemoveUserRole(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), valuer.MustNewUUID(roleID)); err != nil {
|
||||
if err := h.setter.RemoveUserRole(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), valuer.MustNewUUID(roleID)); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
@@ -567,7 +505,7 @@ func (handler *handler) RemoveUserRoleByRoleID(w http.ResponseWriter, r *http.Re
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) GetUsersByRoleID(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetUsersByRoleID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -579,7 +517,7 @@ func (handler *handler) GetUsersByRoleID(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
users, err := handler.getter.GetUsersByOrgIDAndRoleID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(roleID))
|
||||
users, err := h.getter.GetUsersByOrgIDAndRoleID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(roleID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
|
||||
@@ -359,26 +359,6 @@ func (store *store) GetResetPasswordTokenByPasswordID(ctx context.Context, passw
|
||||
return resetPasswordToken, nil
|
||||
}
|
||||
|
||||
func (store *store) GetResetPasswordTokenByOrgIDAndUserID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.ResetPasswordToken, error) {
|
||||
resetPasswordToken := new(types.ResetPasswordToken)
|
||||
|
||||
err := store.
|
||||
sqlstore.
|
||||
BunDBCtx(ctx).
|
||||
NewSelect().
|
||||
Model(resetPasswordToken).
|
||||
Join("JOIN factor_password ON factor_password.id = reset_password_token.password_id").
|
||||
Join("JOIN users ON users.id = factor_password.user_id").
|
||||
Where("factor_password.user_id = ?", userID).
|
||||
Where("users.org_id = ?", orgID).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, store.sqlstore.WrapNotFoundErrf(err, types.ErrResetPasswordTokenNotFound, "reset password token for user %s does not exist", userID)
|
||||
}
|
||||
|
||||
return resetPasswordToken, nil
|
||||
}
|
||||
|
||||
func (store *store) DeleteResetPasswordTokenByPasswordID(ctx context.Context, passwordID valuer.UUID) error {
|
||||
_, err := store.sqlstore.BunDBCtx(ctx).NewDelete().
|
||||
Model(&types.ResetPasswordToken{}).
|
||||
|
||||
@@ -80,9 +80,6 @@ type Getter interface {
|
||||
// Get factor password by user id.
|
||||
GetFactorPasswordByUserID(context.Context, valuer.UUID) (*types.FactorPassword, error)
|
||||
|
||||
// Get reset password token by org id and user id.
|
||||
GetResetPasswordTokenByOrgIDAndUserID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.ResetPasswordToken, error)
|
||||
|
||||
// Gets single Non-Deleted user by email and org id
|
||||
GetNonDeletedUserByEmailAndOrgID(ctx context.Context, email valuer.Email, orgID valuer.UUID) (*types.User, error)
|
||||
|
||||
@@ -115,9 +112,7 @@ type Handler interface {
|
||||
GetUsersByRoleID(http.ResponseWriter, *http.Request)
|
||||
|
||||
// Reset Password
|
||||
GetResetPasswordTokenDeprecated(http.ResponseWriter, *http.Request)
|
||||
GetResetPasswordToken(http.ResponseWriter, *http.Request)
|
||||
CreateResetPasswordToken(http.ResponseWriter, *http.Request)
|
||||
ResetPassword(http.ResponseWriter, *http.Request)
|
||||
ChangePassword(http.ResponseWriter, *http.Request)
|
||||
ForgotPassword(http.ResponseWriter, *http.Request)
|
||||
|
||||
@@ -3,7 +3,6 @@ package app
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
@@ -12,7 +11,6 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/thirdpartyapi"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
|
||||
"io"
|
||||
"log/slog"
|
||||
"math"
|
||||
"net/http"
|
||||
@@ -78,7 +76,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/logparsingpipeline"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/interfaces"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/rules"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/version"
|
||||
)
|
||||
|
||||
@@ -98,7 +96,7 @@ func NewRouter() *mux.Router {
|
||||
type APIHandler struct {
|
||||
logger *slog.Logger
|
||||
reader interfaces.Reader
|
||||
ruleManager *rules.Manager
|
||||
ruleManager ruler.Ruler
|
||||
querier interfaces.Querier
|
||||
querierV2 interfaces.Querier
|
||||
queryBuilder *queryBuilder.QueryBuilder
|
||||
@@ -150,9 +148,6 @@ type APIHandlerOpts struct {
|
||||
// business data reader e.g. clickhouse
|
||||
Reader interfaces.Reader
|
||||
|
||||
// rule manager handles rule crud operations
|
||||
RuleManager *rules.Manager
|
||||
|
||||
// Integrations
|
||||
IntegrationsController *integrations.Controller
|
||||
|
||||
@@ -208,7 +203,7 @@ func NewAPIHandler(opts APIHandlerOpts, config signoz.Config) (*APIHandler, erro
|
||||
logger: slog.Default(),
|
||||
reader: opts.Reader,
|
||||
temporalityMap: make(map[string]map[v3.Temporality]bool),
|
||||
ruleManager: opts.RuleManager,
|
||||
ruleManager: opts.Signoz.Ruler,
|
||||
IntegrationsController: opts.IntegrationsController,
|
||||
CloudIntegrationsController: opts.CloudIntegrationsController,
|
||||
LogsParsingPipelineController: opts.LogsParsingPipelineController,
|
||||
@@ -496,24 +491,11 @@ func (aH *APIHandler) Respond(w http.ResponseWriter, data interface{}) {
|
||||
func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *middleware.AuthZ) {
|
||||
router.HandleFunc("/api/v1/query_range", am.ViewAccess(aH.queryRangeMetrics)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/query", am.ViewAccess(aH.queryMetrics)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/rules", am.ViewAccess(aH.listRules)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/rules/{id}", am.ViewAccess(aH.getRule)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/rules", am.EditAccess(aH.createRule)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/rules/{id}", am.EditAccess(aH.editRule)).Methods(http.MethodPut)
|
||||
router.HandleFunc("/api/v1/rules/{id}", am.EditAccess(aH.deleteRule)).Methods(http.MethodDelete)
|
||||
router.HandleFunc("/api/v1/rules/{id}", am.EditAccess(aH.patchRule)).Methods(http.MethodPatch)
|
||||
router.HandleFunc("/api/v1/testRule", am.EditAccess(aH.testRule)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/rules/{id}/history/stats", am.ViewAccess(aH.getRuleStats)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/rules/{id}/history/timeline", am.ViewAccess(aH.getRuleStateHistory)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/rules/{id}/history/top_contributors", am.ViewAccess(aH.getRuleStateHistoryTopContributors)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/rules/{id}/history/overall_status", am.ViewAccess(aH.getOverallStateTransitions)).Methods(http.MethodPost)
|
||||
|
||||
router.HandleFunc("/api/v1/downtime_schedules", am.ViewAccess(aH.listDowntimeSchedules)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/downtime_schedules/{id}", am.ViewAccess(aH.getDowntimeSchedule)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/downtime_schedules", am.EditAccess(aH.createDowntimeSchedule)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/downtime_schedules/{id}", am.EditAccess(aH.editDowntimeSchedule)).Methods(http.MethodPut)
|
||||
router.HandleFunc("/api/v1/downtime_schedules/{id}", am.EditAccess(aH.deleteDowntimeSchedule)).Methods(http.MethodDelete)
|
||||
|
||||
router.HandleFunc("/api/v1/dashboards", am.ViewAccess(aH.List)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/dashboards", am.EditAccess(aH.Signoz.Handlers.Dashboard.Create)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/dashboards/{id}", am.ViewAccess(aH.Get)).Methods(http.MethodGet)
|
||||
@@ -603,26 +585,6 @@ func Intersection(a, b []int) (c []int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getRule(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := mux.Vars(r)["id"]
|
||||
id, err := valuer.NewUUID(idStr)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
ruleResponse, err := aH.ruleManager.GetRule(r.Context(), id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("rule not found")}, nil)
|
||||
return
|
||||
}
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
aH.Respond(w, ruleResponse)
|
||||
}
|
||||
|
||||
// populateTemporality adds the temporality to the query if it is not present
|
||||
func (aH *APIHandler) PopulateTemporality(ctx context.Context, orgID valuer.UUID, qp *v3.QueryRangeParamsV3) error {
|
||||
|
||||
@@ -678,129 +640,6 @@ func (aH *APIHandler) PopulateTemporality(ctx context.Context, orgID valuer.UUID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (aH *APIHandler) listDowntimeSchedules(w http.ResponseWriter, r *http.Request) {
|
||||
claims, errv2 := authtypes.ClaimsFromContext(r.Context())
|
||||
if errv2 != nil {
|
||||
render.Error(w, errv2)
|
||||
return
|
||||
}
|
||||
|
||||
schedules, err := aH.ruleManager.MaintenanceStore().GetAllPlannedMaintenance(r.Context(), claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
// The schedules are stored as JSON in the database, so we need to filter them here
|
||||
// Since the number of schedules is expected to be small, this should be fine
|
||||
|
||||
if r.URL.Query().Get("active") != "" {
|
||||
activeSchedules := make([]*ruletypes.GettablePlannedMaintenance, 0)
|
||||
active, _ := strconv.ParseBool(r.URL.Query().Get("active"))
|
||||
for _, schedule := range schedules {
|
||||
now := time.Now().In(time.FixedZone(schedule.Schedule.Timezone, 0))
|
||||
if schedule.IsActive(now) == active {
|
||||
activeSchedules = append(activeSchedules, schedule)
|
||||
}
|
||||
}
|
||||
schedules = activeSchedules
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("recurring") != "" {
|
||||
recurringSchedules := make([]*ruletypes.GettablePlannedMaintenance, 0)
|
||||
recurring, _ := strconv.ParseBool(r.URL.Query().Get("recurring"))
|
||||
for _, schedule := range schedules {
|
||||
if schedule.IsRecurring() == recurring {
|
||||
recurringSchedules = append(recurringSchedules, schedule)
|
||||
}
|
||||
}
|
||||
schedules = recurringSchedules
|
||||
}
|
||||
|
||||
aH.Respond(w, schedules)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := mux.Vars(r)["id"]
|
||||
id, err := valuer.NewUUID(idStr)
|
||||
if err != nil {
|
||||
render.Error(w, errorsV2.New(errorsV2.TypeInvalidInput, errorsV2.CodeInvalidInput, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
schedule, err := aH.ruleManager.MaintenanceStore().GetPlannedMaintenanceByID(r.Context(), id)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
aH.Respond(w, schedule)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) createDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
var schedule ruletypes.GettablePlannedMaintenance
|
||||
err := json.NewDecoder(r.Body).Decode(&schedule)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
if err := schedule.Validate(); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = aH.ruleManager.MaintenanceStore().CreatePlannedMaintenance(r.Context(), schedule)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
aH.Respond(w, nil)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) editDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := mux.Vars(r)["id"]
|
||||
id, err := valuer.NewUUID(idStr)
|
||||
if err != nil {
|
||||
render.Error(w, errorsV2.New(errorsV2.TypeInvalidInput, errorsV2.CodeInvalidInput, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
var schedule ruletypes.GettablePlannedMaintenance
|
||||
err = json.NewDecoder(r.Body).Decode(&schedule)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
if err := schedule.Validate(); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = aH.ruleManager.MaintenanceStore().EditPlannedMaintenance(r.Context(), schedule, id)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
aH.Respond(w, nil)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) deleteDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := mux.Vars(r)["id"]
|
||||
id, err := valuer.NewUUID(idStr)
|
||||
if err != nil {
|
||||
render.Error(w, errorsV2.New(errorsV2.TypeInvalidInput, errorsV2.CodeInvalidInput, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = aH.ruleManager.MaintenanceStore().DeletePlannedMaintenance(r.Context(), id)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
aH.Respond(w, nil)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getRuleStats(w http.ResponseWriter, r *http.Request) {
|
||||
ruleID := mux.Vars(r)["id"]
|
||||
params := model.QueryRuleStateHistory{}
|
||||
@@ -1012,19 +851,6 @@ func (aH *APIHandler) getRuleStateHistoryTopContributors(w http.ResponseWriter,
|
||||
aH.Respond(w, res)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) listRules(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rules, err := aH.ruleManager.ListRuleStates(r.Context())
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// todo(amol): need to add sorter
|
||||
|
||||
aH.Respond(w, rules)
|
||||
}
|
||||
|
||||
func prepareQuery(r *http.Request) (string, error) {
|
||||
var postData *model.DashboardVars
|
||||
|
||||
@@ -1226,142 +1052,6 @@ func (aH *APIHandler) queryDashboardVarsV2(w http.ResponseWriter, r *http.Reques
|
||||
aH.Respond(w, dashboardVars)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) testRule(w http.ResponseWriter, r *http.Request) {
|
||||
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
orgID, err := valuer.NewUUID(claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
aH.logger.ErrorContext(r.Context(), "error reading request body for test rule", errors.Attr(err))
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
alertCount, err := aH.ruleManager.TestNotification(ctx, orgID, string(body))
|
||||
if err != nil {
|
||||
RespondError(w, toApiError(err), nil)
|
||||
return
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"alertCount": alertCount,
|
||||
"message": "notification sent",
|
||||
}
|
||||
aH.Respond(w, response)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) deleteRule(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
id := mux.Vars(r)["id"]
|
||||
|
||||
err := aH.ruleManager.DeleteRule(r.Context(), id)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("rule not found")}, nil)
|
||||
return
|
||||
}
|
||||
RespondError(w, toApiError(err), nil)
|
||||
return
|
||||
}
|
||||
|
||||
aH.Respond(w, "rule successfully deleted")
|
||||
|
||||
}
|
||||
|
||||
// patchRule updates only requested changes in the rule
|
||||
func (aH *APIHandler) patchRule(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := mux.Vars(r)["id"]
|
||||
id, err := valuer.NewUUID(idStr)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
aH.logger.ErrorContext(r.Context(), "error reading request body for patch rule", errors.Attr(err))
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
gettableRule, err := aH.ruleManager.PatchRule(r.Context(), string(body), id)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("rule not found")}, nil)
|
||||
return
|
||||
}
|
||||
RespondError(w, toApiError(err), nil)
|
||||
return
|
||||
}
|
||||
|
||||
aH.Respond(w, gettableRule)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) editRule(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := mux.Vars(r)["id"]
|
||||
id, err := valuer.NewUUID(idStr)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
aH.logger.ErrorContext(r.Context(), "error reading request body for edit rule", errors.Attr(err))
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
err = aH.ruleManager.EditRule(r.Context(), string(body), id)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("rule not found")}, nil)
|
||||
return
|
||||
}
|
||||
RespondError(w, toApiError(err), nil)
|
||||
return
|
||||
}
|
||||
|
||||
aH.Respond(w, "rule successfully edited")
|
||||
|
||||
}
|
||||
|
||||
func (aH *APIHandler) createRule(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
defer r.Body.Close()
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
aH.logger.ErrorContext(r.Context(), "error reading request body for create rule", errors.Attr(err))
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
rule, err := aH.ruleManager.CreateRule(r.Context(), string(body))
|
||||
if err != nil {
|
||||
RespondError(w, toApiError(err), nil)
|
||||
return
|
||||
}
|
||||
|
||||
aH.Respond(w, rule)
|
||||
|
||||
}
|
||||
|
||||
func (aH *APIHandler) queryRangeMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
query, apiErrorObj := parseQueryRangeRequest(r)
|
||||
|
||||
@@ -9,24 +9,16 @@ import (
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/cache/memorycache"
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/rulestore/sqlrulestore"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
|
||||
"github.com/rs/cors"
|
||||
"github.com/soheilhy/cmux"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/cache"
|
||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/agentConf"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/clickhouseReader"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/cloudintegrations"
|
||||
@@ -34,10 +26,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/logparsingpipeline"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/opamp"
|
||||
opAmpModel "github.com/SigNoz/signoz/pkg/query-service/app/opamp/model"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/interfaces"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/web"
|
||||
|
||||
"log/slog"
|
||||
@@ -47,15 +36,13 @@ import (
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/query-service/constants"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/healthcheck"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/rules"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
||||
)
|
||||
|
||||
// Server runs HTTP, Mux and a grpc server
|
||||
type Server struct {
|
||||
config signoz.Config
|
||||
signoz *signoz.SigNoz
|
||||
ruleManager *rules.Manager
|
||||
config signoz.Config
|
||||
signoz *signoz.SigNoz
|
||||
|
||||
// public http router
|
||||
httpConn net.Listener
|
||||
@@ -102,24 +89,6 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
nil,
|
||||
)
|
||||
|
||||
rm, err := makeRulesManager(
|
||||
reader,
|
||||
signoz.Cache,
|
||||
signoz.Alertmanager,
|
||||
signoz.SQLStore,
|
||||
signoz.TelemetryStore,
|
||||
signoz.TelemetryMetadataStore,
|
||||
signoz.Prometheus,
|
||||
signoz.Modules.OrgGetter,
|
||||
signoz.Modules.RuleStateHistory,
|
||||
signoz.Querier,
|
||||
signoz.Instrumentation.ToProviderSettings(),
|
||||
signoz.QueryParser,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(
|
||||
signoz.SQLStore,
|
||||
integrationsController.GetPipelinesForInstalledIntegrations,
|
||||
@@ -131,7 +100,6 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
|
||||
apiHandler, err := NewAPIHandler(APIHandlerOpts{
|
||||
Reader: reader,
|
||||
RuleManager: rm,
|
||||
IntegrationsController: integrationsController,
|
||||
CloudIntegrationsController: cloudIntegrationsController,
|
||||
LogsParsingPipelineController: logParsingPipelineController,
|
||||
@@ -146,8 +114,7 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
|
||||
s := &Server{
|
||||
config: config,
|
||||
signoz: signoz,
|
||||
ruleManager: rm,
|
||||
signoz: signoz,
|
||||
httpHostPort: constants.HTTPHostPort,
|
||||
unavailableChannel: make(chan healthcheck.Status),
|
||||
}
|
||||
@@ -270,8 +237,6 @@ func (s *Server) initListeners() error {
|
||||
|
||||
// Start listening on http and private http port concurrently
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
s.ruleManager.Start(ctx)
|
||||
|
||||
err := s.initListeners()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -315,55 +280,6 @@ func (s *Server) Stop(ctx context.Context) error {
|
||||
|
||||
s.opampServer.Stop()
|
||||
|
||||
if s.ruleManager != nil {
|
||||
s.ruleManager.Stop(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeRulesManager(
|
||||
ch interfaces.Reader,
|
||||
cache cache.Cache,
|
||||
alertmanager alertmanager.Alertmanager,
|
||||
sqlstore sqlstore.SQLStore,
|
||||
telemetryStore telemetrystore.TelemetryStore,
|
||||
metadataStore telemetrytypes.MetadataStore,
|
||||
prometheus prometheus.Prometheus,
|
||||
orgGetter organization.Getter,
|
||||
ruleStateHistoryModule rulestatehistory.Module,
|
||||
querier querier.Querier,
|
||||
providerSettings factory.ProviderSettings,
|
||||
queryParser queryparser.QueryParser,
|
||||
) (*rules.Manager, error) {
|
||||
ruleStore := sqlrulestore.NewRuleStore(sqlstore, queryParser, providerSettings)
|
||||
maintenanceStore := sqlrulestore.NewMaintenanceStore(sqlstore)
|
||||
// create manager opts
|
||||
managerOpts := &rules.ManagerOptions{
|
||||
TelemetryStore: telemetryStore,
|
||||
MetadataStore: metadataStore,
|
||||
Prometheus: prometheus,
|
||||
Context: context.Background(),
|
||||
Querier: querier,
|
||||
Logger: providerSettings.Logger,
|
||||
Cache: cache,
|
||||
EvalDelay: constants.GetEvalDelay(),
|
||||
OrgGetter: orgGetter,
|
||||
Alertmanager: alertmanager,
|
||||
RuleStore: ruleStore,
|
||||
MaintenanceStore: maintenanceStore,
|
||||
SQLStore: sqlstore,
|
||||
QueryParser: queryParser,
|
||||
RuleStateHistoryModule: ruleStateHistoryModule,
|
||||
}
|
||||
|
||||
// create Manager
|
||||
manager, err := rules.NewManager(managerOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rule manager error: %v", err)
|
||||
}
|
||||
|
||||
slog.Info("rules manager is ready")
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package ruler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
EvalDelay time.Duration `mapstructure:"eval_delay"`
|
||||
}
|
||||
|
||||
func NewConfigFactory() factory.ConfigFactory {
|
||||
@@ -12,7 +15,9 @@ func NewConfigFactory() factory.ConfigFactory {
|
||||
}
|
||||
|
||||
func newConfig() factory.Config {
|
||||
return Config{}
|
||||
return Config{
|
||||
EvalDelay: 2 * time.Minute,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Config) Validate() error {
|
||||
|
||||
19
pkg/ruler/handler.go
Normal file
19
pkg/ruler/handler.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package ruler
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Handler interface {
|
||||
ListRules(http.ResponseWriter, *http.Request)
|
||||
GetRuleByID(http.ResponseWriter, *http.Request)
|
||||
CreateRule(http.ResponseWriter, *http.Request)
|
||||
UpdateRuleByID(http.ResponseWriter, *http.Request)
|
||||
DeleteRuleByID(http.ResponseWriter, *http.Request)
|
||||
PatchRuleByID(http.ResponseWriter, *http.Request)
|
||||
TestRule(http.ResponseWriter, *http.Request)
|
||||
|
||||
ListDowntimeSchedules(http.ResponseWriter, *http.Request)
|
||||
GetDowntimeScheduleByID(http.ResponseWriter, *http.Request)
|
||||
CreateDowntimeSchedule(http.ResponseWriter, *http.Request)
|
||||
UpdateDowntimeScheduleByID(http.ResponseWriter, *http.Request)
|
||||
DeleteDowntimeScheduleByID(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
@@ -1,7 +1,48 @@
|
||||
package ruler
|
||||
|
||||
import "github.com/SigNoz/signoz/pkg/statsreporter"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/statsreporter"
|
||||
"github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type Ruler interface {
|
||||
factory.Service
|
||||
statsreporter.StatsCollector
|
||||
|
||||
// ListRuleStates returns all rules with their current evaluation state.
|
||||
ListRuleStates(ctx context.Context) (*ruletypes.GettableRules, error)
|
||||
|
||||
// GetRule returns a single rule by ID.
|
||||
GetRule(ctx context.Context, id valuer.UUID) (*ruletypes.GettableRule, error)
|
||||
|
||||
// CreateRule persists a new rule from a JSON string and starts its evaluator.
|
||||
// TODO: accept PostableRule instead of raw string; the manager currently unmarshals
|
||||
// internally because it stores the raw JSON as Data. Requires changing the storage
|
||||
// model to store structured data.
|
||||
CreateRule(ctx context.Context, ruleStr string) (*ruletypes.GettableRule, error)
|
||||
|
||||
// EditRule replaces the rule identified by id with the given JSON string.
|
||||
// TODO: same as CreateRule — accept PostableRule instead of raw string.
|
||||
EditRule(ctx context.Context, ruleStr string, id valuer.UUID) error
|
||||
|
||||
// DeleteRule removes the rule identified by the string ID.
|
||||
// TODO: accept valuer.UUID instead of string for consistency with other methods.
|
||||
DeleteRule(ctx context.Context, idStr string) error
|
||||
|
||||
// PatchRule applies a partial update to the rule identified by id.
|
||||
// TODO: same as CreateRule — accept PostableRule instead of raw string.
|
||||
PatchRule(ctx context.Context, ruleStr string, id valuer.UUID) (*ruletypes.GettableRule, error)
|
||||
|
||||
// TestNotification fires a test alert for the rule defined in ruleStr.
|
||||
// TODO: same as CreateRule — accept PostableRule instead of raw string.
|
||||
TestNotification(ctx context.Context, orgID valuer.UUID, ruleStr string) (int, error)
|
||||
|
||||
// MaintenanceStore returns the store for planned maintenance / downtime schedules.
|
||||
// TODO: expose downtime CRUD as methods on Ruler directly instead of leaking the
|
||||
// store interface. The handler should not call store methods directly.
|
||||
MaintenanceStore() ruletypes.MaintenanceStore
|
||||
}
|
||||
|
||||
314
pkg/ruler/signozruler/handler.go
Normal file
314
pkg/ruler/signozruler/handler.go
Normal file
@@ -0,0 +1,314 @@
|
||||
package signozruler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/http/binding"
|
||||
"github.com/SigNoz/signoz/pkg/http/render"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
ruler ruler.Ruler
|
||||
}
|
||||
|
||||
func NewHandler(ruler ruler.Ruler) ruler.Handler {
|
||||
return &handler{ruler: ruler}
|
||||
}
|
||||
|
||||
func (handler *handler) ListRules(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
rules, err := handler.ruler.ListRuleStates(ctx)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, rules)
|
||||
}
|
||||
|
||||
func (handler *handler) GetRuleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid-v7"))
|
||||
return
|
||||
}
|
||||
|
||||
rule, err := handler.ruler.GetRule(ctx, id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, rule)
|
||||
}
|
||||
|
||||
func (handler *handler) CreateRule(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
defer req.Body.Close() //nolint:errcheck
|
||||
|
||||
rule, err := handler.ruler.CreateRule(ctx, string(body))
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, rule)
|
||||
}
|
||||
|
||||
func (handler *handler) UpdateRuleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid-v7"))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
defer req.Body.Close() //nolint:errcheck
|
||||
|
||||
err = handler.ruler.EditRule(ctx, string(body), id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) DeleteRuleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
idStr := mux.Vars(req)["id"]
|
||||
|
||||
err := handler.ruler.DeleteRule(ctx, idStr)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) PatchRuleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid-v7"))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
defer req.Body.Close() //nolint:errcheck
|
||||
|
||||
rule, err := handler.ruler.PatchRule(ctx, string(body), id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, rule)
|
||||
}
|
||||
|
||||
func (handler *handler) TestRule(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 1*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
orgID, err := valuer.NewUUID(claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
defer req.Body.Close() //nolint:errcheck
|
||||
|
||||
alertCount, err := handler.ruler.TestNotification(ctx, orgID, string(body))
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, ruletypes.GettableTestRule{AlertCount: alertCount, Message: "notification sent"})
|
||||
}
|
||||
|
||||
func (handler *handler) ListDowntimeSchedules(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
var params ruletypes.ListPlannedMaintenanceParams
|
||||
if err := binding.Query.BindQuery(req.URL.Query(), ¶ms); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
schedules, err := handler.ruler.MaintenanceStore().GetAllPlannedMaintenance(ctx, claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
if params.Active != nil {
|
||||
activeSchedules := make([]*ruletypes.GettablePlannedMaintenance, 0)
|
||||
for _, schedule := range schedules {
|
||||
now := time.Now().In(time.FixedZone(schedule.Schedule.Timezone, 0))
|
||||
if schedule.IsActive(now) == *params.Active {
|
||||
activeSchedules = append(activeSchedules, schedule)
|
||||
}
|
||||
}
|
||||
schedules = activeSchedules
|
||||
}
|
||||
|
||||
if params.Recurring != nil {
|
||||
recurringSchedules := make([]*ruletypes.GettablePlannedMaintenance, 0)
|
||||
for _, schedule := range schedules {
|
||||
if schedule.IsRecurring() == *params.Recurring {
|
||||
recurringSchedules = append(recurringSchedules, schedule)
|
||||
}
|
||||
}
|
||||
schedules = recurringSchedules
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, schedules)
|
||||
}
|
||||
|
||||
func (handler *handler) GetDowntimeScheduleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid-v7"))
|
||||
return
|
||||
}
|
||||
|
||||
schedule, err := handler.ruler.MaintenanceStore().GetPlannedMaintenanceByID(ctx, id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, schedule)
|
||||
}
|
||||
|
||||
func (handler *handler) CreateDowntimeSchedule(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var schedule ruletypes.GettablePlannedMaintenance
|
||||
if err := binding.JSON.BindBody(req.Body, &schedule); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := schedule.Validate(); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := handler.ruler.MaintenanceStore().CreatePlannedMaintenance(ctx, schedule)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) UpdateDowntimeScheduleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid-v7"))
|
||||
return
|
||||
}
|
||||
|
||||
var schedule ruletypes.GettablePlannedMaintenance
|
||||
if err := binding.JSON.BindBody(req.Body, &schedule); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := schedule.Validate(); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.ruler.MaintenanceStore().EditPlannedMaintenance(ctx, schedule, id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (handler *handler) DeleteDowntimeScheduleByID(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid-v7"))
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.ruler.MaintenanceStore().DeletePlannedMaintenance(ctx, id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusNoContent, nil)
|
||||
}
|
||||
@@ -3,27 +3,87 @@ package signozruler
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/cache"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/rules"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/rulestore/sqlrulestore"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
manager *rules.Manager
|
||||
ruleStore ruletypes.RuleStore
|
||||
stopC chan struct{}
|
||||
}
|
||||
|
||||
func NewFactory(sqlstore sqlstore.SQLStore, queryParser queryparser.QueryParser) factory.ProviderFactory[ruler.Ruler, ruler.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, settings factory.ProviderSettings, config ruler.Config) (ruler.Ruler, error) {
|
||||
return New(ctx, settings, config, sqlstore, queryParser)
|
||||
func NewFactory(
|
||||
cache cache.Cache,
|
||||
alertmanager alertmanager.Alertmanager,
|
||||
sqlstore sqlstore.SQLStore,
|
||||
telemetryStore telemetrystore.TelemetryStore,
|
||||
metadataStore telemetrytypes.MetadataStore,
|
||||
prometheus prometheus.Prometheus,
|
||||
orgGetter organization.Getter,
|
||||
ruleStateHistoryModule rulestatehistory.Module,
|
||||
querier querier.Querier,
|
||||
queryParser queryparser.QueryParser,
|
||||
prepareTaskFunc func(rules.PrepareTaskOptions) (rules.Task, error),
|
||||
prepareTestRuleFunc func(rules.PrepareTestRuleOptions) (int, error),
|
||||
) factory.ProviderFactory[ruler.Ruler, ruler.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, providerSettings factory.ProviderSettings, config ruler.Config) (ruler.Ruler, error) {
|
||||
ruleStore := sqlrulestore.NewRuleStore(sqlstore, queryParser, providerSettings)
|
||||
maintenanceStore := sqlrulestore.NewMaintenanceStore(sqlstore)
|
||||
|
||||
managerOpts := &rules.ManagerOptions{
|
||||
TelemetryStore: telemetryStore,
|
||||
MetadataStore: metadataStore,
|
||||
Prometheus: prometheus,
|
||||
Context: context.Background(),
|
||||
Querier: querier,
|
||||
Logger: providerSettings.Logger,
|
||||
Cache: cache,
|
||||
EvalDelay: valuer.MustParseTextDuration(config.EvalDelay.String()),
|
||||
PrepareTaskFunc: prepareTaskFunc,
|
||||
PrepareTestRuleFunc: prepareTestRuleFunc,
|
||||
Alertmanager: alertmanager,
|
||||
OrgGetter: orgGetter,
|
||||
RuleStore: ruleStore,
|
||||
MaintenanceStore: maintenanceStore,
|
||||
SQLStore: sqlstore,
|
||||
QueryParser: queryParser,
|
||||
RuleStateHistoryModule: ruleStateHistoryModule,
|
||||
}
|
||||
|
||||
manager, err := rules.NewManager(managerOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &provider{manager: manager, ruleStore: ruleStore, stopC: make(chan struct{})}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func New(ctx context.Context, settings factory.ProviderSettings, config ruler.Config, sqlstore sqlstore.SQLStore, queryParser queryparser.QueryParser) (ruler.Ruler, error) {
|
||||
return &provider{ruleStore: sqlrulestore.NewRuleStore(sqlstore, queryParser, settings)}, nil
|
||||
func (provider *provider) Start(ctx context.Context) error {
|
||||
provider.manager.Start(ctx)
|
||||
<-provider.stopC
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *provider) Stop(ctx context.Context) error {
|
||||
close(provider.stopC)
|
||||
provider.manager.Stop(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *provider) Collect(ctx context.Context, orgID valuer.UUID) (map[string]any, error) {
|
||||
@@ -34,3 +94,35 @@ func (provider *provider) Collect(ctx context.Context, orgID valuer.UUID) (map[s
|
||||
|
||||
return ruletypes.NewStatsFromRules(rules), nil
|
||||
}
|
||||
|
||||
func (provider *provider) ListRuleStates(ctx context.Context) (*ruletypes.GettableRules, error) {
|
||||
return provider.manager.ListRuleStates(ctx)
|
||||
}
|
||||
|
||||
func (provider *provider) GetRule(ctx context.Context, id valuer.UUID) (*ruletypes.GettableRule, error) {
|
||||
return provider.manager.GetRule(ctx, id)
|
||||
}
|
||||
|
||||
func (provider *provider) CreateRule(ctx context.Context, ruleStr string) (*ruletypes.GettableRule, error) {
|
||||
return provider.manager.CreateRule(ctx, ruleStr)
|
||||
}
|
||||
|
||||
func (provider *provider) EditRule(ctx context.Context, ruleStr string, id valuer.UUID) error {
|
||||
return provider.manager.EditRule(ctx, ruleStr, id)
|
||||
}
|
||||
|
||||
func (provider *provider) DeleteRule(ctx context.Context, idStr string) error {
|
||||
return provider.manager.DeleteRule(ctx, idStr)
|
||||
}
|
||||
|
||||
func (provider *provider) PatchRule(ctx context.Context, ruleStr string, id valuer.UUID) (*ruletypes.GettableRule, error) {
|
||||
return provider.manager.PatchRule(ctx, ruleStr, id)
|
||||
}
|
||||
|
||||
func (provider *provider) TestNotification(ctx context.Context, orgID valuer.UUID, ruleStr string) (int, error) {
|
||||
return provider.manager.TestNotification(ctx, orgID, ruleStr)
|
||||
}
|
||||
|
||||
func (provider *provider) MaintenanceStore() ruletypes.MaintenanceStore {
|
||||
return provider.manager.MaintenanceStore()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package signoz
|
||||
import (
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/signozruler"
|
||||
"github.com/SigNoz/signoz/pkg/analytics"
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/signozauthzapi"
|
||||
@@ -65,6 +67,7 @@ type Handlers struct {
|
||||
CloudIntegrationHandler cloudintegration.Handler
|
||||
RuleStateHistory rulestatehistory.Handler
|
||||
AlertmanagerHandler alertmanager.Handler
|
||||
RulerHandler ruler.Handler
|
||||
}
|
||||
|
||||
func NewHandlers(
|
||||
@@ -81,6 +84,7 @@ func NewHandlers(
|
||||
zeusService zeus.Zeus,
|
||||
registryHandler factory.Handler,
|
||||
alertmanagerService alertmanager.Alertmanager,
|
||||
rulerService ruler.Ruler,
|
||||
) Handlers {
|
||||
return Handlers{
|
||||
SavedView: implsavedview.NewHandler(modules.SavedView),
|
||||
@@ -104,5 +108,6 @@ func NewHandlers(
|
||||
RuleStateHistory: implrulestatehistory.NewHandler(modules.RuleStateHistory),
|
||||
CloudIntegrationHandler: implcloudintegration.NewHandler(modules.CloudIntegration),
|
||||
AlertmanagerHandler: signozalertmanager.NewHandler(alertmanagerService),
|
||||
RulerHandler: signozruler.NewHandler(rulerService),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestNewHandlers(t *testing.T) {
|
||||
|
||||
querierHandler := querier.NewHandler(providerSettings, nil, nil)
|
||||
registryHandler := factory.NewHandler(nil)
|
||||
handlers := NewHandlers(modules, providerSettings, nil, querierHandler, nil, nil, nil, nil, nil, nil, nil, registryHandler, alertmanager)
|
||||
handlers := NewHandlers(modules, providerSettings, nil, querierHandler, nil, nil, nil, nil, nil, nil, nil, registryHandler, alertmanager, nil)
|
||||
reflectVal := reflect.ValueOf(handlers)
|
||||
for i := 0; i < reflectVal.NumField(); i++ {
|
||||
f := reflectVal.Field(i)
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/session"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/zeus"
|
||||
"github.com/swaggest/jsonschema-go"
|
||||
@@ -71,6 +72,7 @@ func NewOpenAPI(ctx context.Context, instrumentation instrumentation.Instrumenta
|
||||
struct{ cloudintegration.Handler }{},
|
||||
struct{ rulestatehistory.Handler }{},
|
||||
struct{ alertmanager.Handler }{},
|
||||
struct{ ruler.Handler }{},
|
||||
).New(ctx, instrumentation.ToProviderSettings(), apiserver.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -44,9 +44,6 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/prometheus/clickhouseprometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/querier/signozquerier"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/ruler/signozruler"
|
||||
"github.com/SigNoz/signoz/pkg/sharder"
|
||||
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||
"github.com/SigNoz/signoz/pkg/sharder/singlesharder"
|
||||
@@ -229,11 +226,7 @@ func NewAlertmanagerProviderFactories(sqlstore sqlstore.SQLStore, orgGetter orga
|
||||
)
|
||||
}
|
||||
|
||||
func NewRulerProviderFactories(sqlstore sqlstore.SQLStore, queryParser queryparser.QueryParser) factory.NamedMap[factory.ProviderFactory[ruler.Ruler, ruler.Config]] {
|
||||
return factory.MustNewNamedMap(
|
||||
signozruler.NewFactory(sqlstore, queryParser),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
func NewEmailingProviderFactories() factory.NamedMap[factory.ProviderFactory[emailing.Emailing, emailing.Config]] {
|
||||
return factory.MustNewNamedMap(
|
||||
@@ -289,6 +282,7 @@ func NewAPIServerProviderFactories(orgGetter organization.Getter, authz authz.Au
|
||||
handlers.CloudIntegrationHandler,
|
||||
handlers.RuleStateHistory,
|
||||
handlers.AlertmanagerHandler,
|
||||
handlers.RulerHandler,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema/sqlschematest"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
@@ -64,11 +63,6 @@ func TestNewProviderFactories(t *testing.T) {
|
||||
NewAlertmanagerProviderFactories(sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual), orgGetter, notificationManager)
|
||||
})
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
queryParser := queryparser.New(instrumentationtest.New().ToProviderSettings())
|
||||
NewRulerProviderFactories(sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual), queryParser)
|
||||
})
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
NewEmailingProviderFactories()
|
||||
})
|
||||
|
||||
@@ -26,12 +26,14 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
|
||||
"github.com/SigNoz/signoz/pkg/modules/serviceaccount/implserviceaccount"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/queryparser"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
"github.com/SigNoz/signoz/pkg/sharder"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigrator"
|
||||
@@ -75,6 +77,7 @@ type SigNoz struct {
|
||||
Tokenizer pkgtokenizer.Tokenizer
|
||||
IdentNResolver identn.IdentNResolver
|
||||
Authz authz.AuthZ
|
||||
Ruler ruler.Ruler
|
||||
Modules Modules
|
||||
Handlers Handlers
|
||||
QueryParser queryparser.QueryParser
|
||||
@@ -103,6 +106,7 @@ func New(
|
||||
auditorProviderFactories func(licensing.Licensing) factory.NamedMap[factory.ProviderFactory[auditor.Auditor, auditor.Config]],
|
||||
querierHandlerCallback func(factory.ProviderSettings, querier.Querier, analytics.Analytics) querier.Handler,
|
||||
cloudIntegrationCallback func(sqlstore.SQLStore, global.Global, zeus.Zeus, gateway.Gateway, licensing.Licensing, serviceaccount.Module, cloudintegration.Config) (cloudintegration.Module, error),
|
||||
rulerProviderFactories func(cache.Cache, alertmanager.Alertmanager, sqlstore.SQLStore, telemetrystore.TelemetryStore, telemetrytypes.MetadataStore, prometheus.Prometheus, organization.Getter, rulestatehistory.Module, querier.Querier, queryparser.QueryParser) factory.NamedMap[factory.ProviderFactory[ruler.Ruler, ruler.Config]],
|
||||
) (*SigNoz, error) {
|
||||
// Initialize instrumentation
|
||||
instrumentation, err := instrumentation.New(ctx, config.Instrumentation, version.Info, "signoz")
|
||||
@@ -361,18 +365,6 @@ func New(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize ruler from the available ruler provider factories
|
||||
ruler, err := factory.NewProviderFromNamedMap(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.Ruler,
|
||||
NewRulerProviderFactories(sqlstore, queryParser),
|
||||
"signoz",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gatewayFactory := gatewayProviderFactory(licensing)
|
||||
gateway, err := gatewayFactory.New(ctx, providerSettings, config.Gateway)
|
||||
if err != nil {
|
||||
@@ -441,6 +433,12 @@ func New(
|
||||
// Initialize all modules
|
||||
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, analytics, querier, telemetrystore, telemetryMetadataStore, authNs, authz, cache, queryParser, config, dashboard, userGetter, userRoleStore, serviceAccount, cloudIntegrationModule)
|
||||
|
||||
// Initialize ruler from the variant-specific provider factories
|
||||
rulerInstance, err := factory.NewProviderFromNamedMap(ctx, providerSettings, config.Ruler, rulerProviderFactories(cache, alertmanager, sqlstore, telemetrystore, telemetryMetadataStore, prometheus, orgGetter, modules.RuleStateHistory, querier, queryParser), "signoz")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize identN resolver
|
||||
identNFactories := NewIdentNProviderFactories(tokenizer, serviceAccount, orgGetter, userGetter, config.User)
|
||||
identNResolver, err := identn.NewIdentNResolver(ctx, providerSettings, config.IdentN, identNFactories)
|
||||
@@ -456,7 +454,7 @@ func New(
|
||||
// Create a list of all stats collectors
|
||||
statsCollectors := []statsreporter.StatsCollector{
|
||||
alertmanager,
|
||||
ruler,
|
||||
rulerInstance,
|
||||
modules.Dashboard,
|
||||
modules.SavedView,
|
||||
modules.UserSetter,
|
||||
@@ -493,6 +491,7 @@ func New(
|
||||
factory.NewNamedService(factory.MustNewName("authz"), authz),
|
||||
factory.NewNamedService(factory.MustNewName("user"), userService, factory.MustNewName("authz")),
|
||||
factory.NewNamedService(factory.MustNewName("auditor"), auditor),
|
||||
factory.NewNamedService(factory.MustNewName("ruler"), rulerInstance),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -500,7 +499,7 @@ func New(
|
||||
|
||||
// Initialize all handlers for the modules
|
||||
registryHandler := factory.NewHandler(registry)
|
||||
handlers := NewHandlers(modules, providerSettings, analytics, querierHandler, licensing, global, flagger, gateway, telemetryMetadataStore, authz, zeus, registryHandler, alertmanager)
|
||||
handlers := NewHandlers(modules, providerSettings, analytics, querierHandler, licensing, global, flagger, gateway, telemetryMetadataStore, authz, zeus, registryHandler, alertmanager, rulerInstance)
|
||||
|
||||
// Initialize the API server (after registry so it can access service health)
|
||||
apiserverInstance, err := factory.NewProviderFromNamedMap(
|
||||
@@ -534,6 +533,7 @@ func New(
|
||||
Tokenizer: tokenizer,
|
||||
IdentNResolver: identNResolver,
|
||||
Authz: authz,
|
||||
Ruler: rulerInstance,
|
||||
Modules: modules,
|
||||
Handlers: handlers,
|
||||
QueryParser: queryParser,
|
||||
|
||||
@@ -31,8 +31,9 @@ type PostableResetPassword struct {
|
||||
}
|
||||
|
||||
type ChangePasswordRequest struct {
|
||||
OldPassword string `json:"oldPassword"`
|
||||
NewPassword string `json:"newPassword"`
|
||||
UserID valuer.UUID `json:"userId"`
|
||||
OldPassword string `json:"oldPassword"`
|
||||
NewPassword string `json:"newPassword"`
|
||||
}
|
||||
|
||||
type PostableForgotPassword struct {
|
||||
|
||||
@@ -38,14 +38,14 @@ const (
|
||||
|
||||
// PostableRule is used to create alerting rule from HTTP api.
|
||||
type PostableRule struct {
|
||||
AlertName string `json:"alert"`
|
||||
AlertName string `json:"alert" required:"true"`
|
||||
AlertType AlertType `json:"alertType,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
RuleType RuleType `json:"ruleType,omitzero"`
|
||||
RuleType RuleType `json:"ruleType,omitzero" required:"true"`
|
||||
EvalWindow valuer.TextDuration `json:"evalWindow,omitzero"`
|
||||
Frequency valuer.TextDuration `json:"frequency,omitzero"`
|
||||
|
||||
RuleCondition *RuleCondition `json:"condition,omitempty"`
|
||||
RuleCondition *RuleCondition `json:"condition,omitempty" required:"true"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
||||
@@ -586,6 +586,11 @@ func testTemplateParsing(rl *PostableRule) (errs []error) {
|
||||
}
|
||||
|
||||
// GettableRules has info for all stored rules.
|
||||
type GettableTestRule struct {
|
||||
AlertCount int `json:"alertCount"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type GettableRules struct {
|
||||
Rules []*GettableRule `json:"rules"`
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/swaggest/jsonschema-go"
|
||||
)
|
||||
|
||||
type EvaluationKind struct {
|
||||
@@ -229,6 +230,29 @@ type EvaluationEnvelope struct {
|
||||
Spec any `json:"spec"`
|
||||
}
|
||||
|
||||
// evaluationRolling is the OpenAPI schema for an EvaluationEnvelope with kind=rolling.
|
||||
type evaluationRolling struct {
|
||||
Kind EvaluationKind `json:"kind" description:"The kind of evaluation."`
|
||||
Spec RollingWindow `json:"spec" description:"The rolling window evaluation specification."`
|
||||
}
|
||||
|
||||
// evaluationCumulative is the OpenAPI schema for an EvaluationEnvelope with kind=cumulative.
|
||||
type evaluationCumulative struct {
|
||||
Kind EvaluationKind `json:"kind" description:"The kind of evaluation."`
|
||||
Spec CumulativeWindow `json:"spec" description:"The cumulative window evaluation specification."`
|
||||
}
|
||||
|
||||
var _ jsonschema.OneOfExposer = EvaluationEnvelope{}
|
||||
|
||||
// JSONSchemaOneOf returns the oneOf variants for the EvaluationEnvelope discriminated union.
|
||||
// Each variant represents a different evaluation kind with its corresponding spec schema.
|
||||
func (EvaluationEnvelope) JSONSchemaOneOf() []any {
|
||||
return []any{
|
||||
evaluationRolling{},
|
||||
evaluationCumulative{},
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvaluationEnvelope) UnmarshalJSON(data []byte) error {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
|
||||
@@ -331,6 +331,11 @@ func (m *GettablePlannedMaintenanceRule) ConvertGettableMaintenanceRuleToGettabl
|
||||
}
|
||||
}
|
||||
|
||||
type ListPlannedMaintenanceParams struct {
|
||||
Active *bool `query:"active"`
|
||||
Recurring *bool `query:"recurring"`
|
||||
}
|
||||
|
||||
type MaintenanceStore interface {
|
||||
CreatePlannedMaintenance(context.Context, GettablePlannedMaintenance) (valuer.UUID, error)
|
||||
DeletePlannedMaintenance(context.Context, valuer.UUID) error
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/SigNoz/signoz/pkg/units"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/swaggest/jsonschema-go"
|
||||
)
|
||||
|
||||
type ThresholdKind struct {
|
||||
@@ -26,6 +27,22 @@ type RuleThresholdData struct {
|
||||
Spec any `json:"spec"`
|
||||
}
|
||||
|
||||
// thresholdBasic is the OpenAPI schema for a RuleThresholdData with kind=basic.
|
||||
type thresholdBasic struct {
|
||||
Kind ThresholdKind `json:"kind" description:"The kind of threshold."`
|
||||
Spec BasicRuleThresholds `json:"spec" description:"The basic threshold specification (array of thresholds)."`
|
||||
}
|
||||
|
||||
var _ jsonschema.OneOfExposer = RuleThresholdData{}
|
||||
|
||||
// JSONSchemaOneOf returns the oneOf variants for the RuleThresholdData discriminated union.
|
||||
// Each variant represents a different threshold kind with its corresponding spec schema.
|
||||
func (RuleThresholdData) JSONSchemaOneOf() []any {
|
||||
return []any{
|
||||
thresholdBasic{},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RuleThresholdData) UnmarshalJSON(data []byte) error {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
|
||||
@@ -284,7 +284,6 @@ type UserStore interface {
|
||||
GetPasswordByUserID(ctx context.Context, userID valuer.UUID) (*FactorPassword, error)
|
||||
GetResetPasswordToken(ctx context.Context, token string) (*ResetPasswordToken, error)
|
||||
GetResetPasswordTokenByPasswordID(ctx context.Context, passwordID valuer.UUID) (*ResetPasswordToken, error)
|
||||
GetResetPasswordTokenByOrgIDAndUserID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*ResetPasswordToken, error)
|
||||
DeleteResetPasswordTokenByPasswordID(ctx context.Context, passwordID valuer.UUID) error
|
||||
UpdatePassword(ctx context.Context, password *FactorPassword) error
|
||||
|
||||
|
||||
@@ -39,14 +39,20 @@ def test_change_password(
|
||||
)
|
||||
assert response.status_code == HTTPStatus.NO_CONTENT
|
||||
|
||||
# Get the user id via v2
|
||||
found_user = find_user_by_email(signoz, admin_token, PASSWORD_USER_EMAIL)
|
||||
|
||||
# Try logging in with the password
|
||||
token = get_token(PASSWORD_USER_EMAIL, PASSWORD_USER_PASSWORD)
|
||||
assert token is not None
|
||||
|
||||
# Try changing the password with a bad old password which should fail
|
||||
response = requests.put(
|
||||
signoz.self.host_configs["8080"].get("/api/v2/users/me/factor_password"),
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v1/changePassword/{found_user['id']}"
|
||||
),
|
||||
json={
|
||||
"userId": f"{found_user['id']}",
|
||||
"oldPassword": "password",
|
||||
"newPassword": PASSWORD_USER_PASSWORD,
|
||||
},
|
||||
@@ -57,9 +63,12 @@ def test_change_password(
|
||||
assert response.status_code == HTTPStatus.BAD_REQUEST
|
||||
|
||||
# Try changing the password with a good old password
|
||||
response = requests.put(
|
||||
signoz.self.host_configs["8080"].get("/api/v2/users/me/factor_password"),
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v1/changePassword/{found_user['id']}"
|
||||
),
|
||||
json={
|
||||
"userId": f"{found_user['id']}",
|
||||
"oldPassword": PASSWORD_USER_PASSWORD,
|
||||
"newPassword": "password123Znew$",
|
||||
},
|
||||
@@ -82,42 +91,17 @@ def test_reset_password(
|
||||
# Get the user id via v2
|
||||
found_user = find_user_by_email(signoz, admin_token, PASSWORD_USER_EMAIL)
|
||||
|
||||
# Create a reset password token via v2 PUT
|
||||
response = requests.put(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/users/{found_user['id']}/reset_password_tokens"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=2,
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.CREATED, response.text
|
||||
token_data = response.json()["data"]
|
||||
assert "token" in token_data
|
||||
assert "expiresAt" in token_data
|
||||
token = token_data["token"]
|
||||
|
||||
# Calling PUT again should return the same token (still valid)
|
||||
response = requests.put(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/users/{found_user['id']}/reset_password_tokens"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=2,
|
||||
)
|
||||
assert response.status_code == HTTPStatus.CREATED, response.text
|
||||
assert response.json()["data"]["token"] == token
|
||||
|
||||
# GET should also return the same token
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/users/{found_user['id']}/reset_password_tokens"
|
||||
f"/api/v1/getResetPasswordToken/{found_user['id']}"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=2,
|
||||
)
|
||||
assert response.status_code == HTTPStatus.OK, response.text
|
||||
assert response.json()["data"]["token"] == token
|
||||
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
|
||||
token = response.json()["data"]["token"]
|
||||
|
||||
# Reset the password with a bad password which should fail
|
||||
response = requests.post(
|
||||
@@ -156,29 +140,18 @@ def test_reset_password_with_no_password(
|
||||
)
|
||||
assert result.rowcount == 1
|
||||
|
||||
# GET should return 404 since there's no password (and thus no token)
|
||||
# Generate a new reset password token
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/users/{found_user['id']}/reset_password_tokens"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=2,
|
||||
)
|
||||
assert response.status_code == HTTPStatus.NOT_FOUND, response.text
|
||||
|
||||
# Generate a new reset password token via v2 PUT
|
||||
response = requests.put(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/users/{found_user['id']}/reset_password_tokens"
|
||||
f"/api/v1/getResetPasswordToken/{found_user['id']}"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=2,
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.CREATED, response.text
|
||||
token_data = response.json()["data"]
|
||||
assert "expiresAt" in token_data
|
||||
token = token_data["token"]
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
|
||||
token = response.json()["data"]["token"]
|
||||
|
||||
# Reset the password with a good password
|
||||
response = requests.post(
|
||||
@@ -289,22 +262,32 @@ def test_forgot_password_creates_reset_token(
|
||||
)
|
||||
assert response.status_code == HTTPStatus.NO_CONTENT
|
||||
|
||||
# Verify reset password token was created via the v2 GET endpoint
|
||||
# Verify reset password token was created by querying the database
|
||||
found_user = find_user_by_email(signoz, admin_token, forgot_email)
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/users/{found_user['id']}/reset_password_tokens"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=2,
|
||||
)
|
||||
assert response.status_code == HTTPStatus.OK, response.text
|
||||
token_data = response.json()["data"]
|
||||
reset_token = token_data["token"]
|
||||
reset_token = None
|
||||
# Query the database directly to get the reset password token
|
||||
# First get the password_id from factor_password, then get the token
|
||||
with signoz.sqlstore.conn.connect() as conn:
|
||||
result = conn.execute(
|
||||
sql.text(
|
||||
"""
|
||||
SELECT rpt.token
|
||||
FROM reset_password_token rpt
|
||||
JOIN factor_password fp ON rpt.password_id = fp.id
|
||||
WHERE fp.user_id = :user_id
|
||||
"""
|
||||
),
|
||||
{"user_id": found_user["id"]},
|
||||
)
|
||||
row = result.fetchone()
|
||||
assert (
|
||||
row is not None
|
||||
), "Reset password token should exist after calling forgotPassword"
|
||||
reset_token = row[0]
|
||||
|
||||
assert reset_token is not None
|
||||
assert reset_token != ""
|
||||
assert "expiresAt" in token_data
|
||||
|
||||
# Reset password with a valid strong password
|
||||
response = requests.post(
|
||||
|
||||
Reference in New Issue
Block a user