mirror of
https://github.com/SigNoz/signoz.git
synced 2026-05-07 11:00:31 +01:00
Compare commits
7 Commits
fix/lint-s
...
ns/scope
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23da5e22ec | ||
|
|
078b82e957 | ||
|
|
4c1b479149 | ||
|
|
f72204a8b2 | ||
|
|
deb3f385fa | ||
|
|
77ce5f86b1 | ||
|
|
ff211de441 |
@@ -8,7 +8,7 @@ import afterLogin from 'AppRoutes/utils';
|
||||
import AuthError from 'components/AuthError/AuthError';
|
||||
import AuthPageContainer from 'components/AuthPageContainer';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { ArrowRight, CircleAlert } from 'lucide-react';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
import APIError from 'types/api/error';
|
||||
|
||||
import tvUrl from '@/assets/svgs/tv.svg';
|
||||
@@ -28,9 +28,8 @@ type FormValues = {
|
||||
|
||||
function SignUp(): JSX.Element {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [confirmPasswordTouched, setConfirmPasswordTouched] = useState(false);
|
||||
|
||||
const [confirmPasswordError, setConfirmPasswordError] =
|
||||
useState<boolean>(false);
|
||||
const [formError, setFormError] = useState<APIError | null>();
|
||||
|
||||
const { notifications } = useNotifications();
|
||||
@@ -84,35 +83,10 @@ function SignUp(): JSX.Element {
|
||||
})();
|
||||
};
|
||||
|
||||
const handleValuesChange: (changedValues: Partial<FormValues>) => void = (
|
||||
changedValues,
|
||||
) => {
|
||||
// Clear error if passwords match while typing (but don't set error until blur)
|
||||
if ('password' in changedValues || 'confirmPassword' in changedValues) {
|
||||
const { password, confirmPassword } = form.getFieldsValue();
|
||||
const isPasswordMismatch =
|
||||
Boolean(confirmPassword) && password !== confirmPassword;
|
||||
|
||||
if (password && confirmPassword && password === confirmPassword) {
|
||||
setConfirmPasswordError(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handlePasswordBlur = (): void => {
|
||||
const { password, confirmPassword } = form.getFieldsValue();
|
||||
// Only validate if confirm password has a value
|
||||
if (confirmPassword) {
|
||||
const isSamePassword = password === confirmPassword;
|
||||
setConfirmPasswordError(!isSamePassword);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmPasswordBlur = (): void => {
|
||||
const { password, confirmPassword } = form.getFieldsValue();
|
||||
if (password && confirmPassword) {
|
||||
const isSamePassword = password === confirmPassword;
|
||||
setConfirmPasswordError(!isSamePassword);
|
||||
}
|
||||
};
|
||||
const showPasswordMismatchError = confirmPasswordTouched && isPasswordMismatch;
|
||||
|
||||
const isValidForm = useMemo(
|
||||
(): boolean =>
|
||||
@@ -120,8 +94,8 @@ function SignUp(): JSX.Element {
|
||||
Boolean(email?.trim()) &&
|
||||
Boolean(password?.trim()) &&
|
||||
Boolean(confirmPassword?.trim()) &&
|
||||
!confirmPasswordError,
|
||||
[loading, email, password, confirmPassword, confirmPasswordError],
|
||||
password === confirmPassword,
|
||||
[loading, email, password, confirmPassword],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -140,12 +114,7 @@ function SignUp(): JSX.Element {
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
|
||||
<FormContainer
|
||||
onFinish={handleSubmit}
|
||||
onValuesChange={handleValuesChange}
|
||||
form={form}
|
||||
className="signup-form"
|
||||
>
|
||||
<FormContainer onFinish={handleSubmit} form={form} className="signup-form">
|
||||
<div className="signup-form-container">
|
||||
<div className="signup-form-fields">
|
||||
<div className="signup-field-container">
|
||||
@@ -175,7 +144,6 @@ function SignUp(): JSX.Element {
|
||||
placeholder="Enter new password"
|
||||
disabled={loading}
|
||||
className="signup-antd-input"
|
||||
onBlur={handlePasswordBlur}
|
||||
/>
|
||||
</FormContainer.Item>
|
||||
</div>
|
||||
@@ -185,6 +153,12 @@ function SignUp(): JSX.Element {
|
||||
<FormContainer.Item
|
||||
name="confirmPassword"
|
||||
validateTrigger="onBlur"
|
||||
validateStatus={showPasswordMismatchError ? 'error' : undefined}
|
||||
help={
|
||||
showPasswordMismatchError
|
||||
? "Passwords don't match. Please try again."
|
||||
: undefined
|
||||
}
|
||||
rules={[{ required: true, message: 'Please enter confirm password!' }]}
|
||||
>
|
||||
<AntdInput.Password
|
||||
@@ -193,7 +167,7 @@ function SignUp(): JSX.Element {
|
||||
placeholder="Confirm your new password"
|
||||
disabled={loading}
|
||||
className="signup-antd-input"
|
||||
onBlur={handleConfirmPasswordBlur}
|
||||
onBlur={() => setConfirmPasswordTouched(true)}
|
||||
/>
|
||||
</FormContainer.Item>
|
||||
</div>
|
||||
@@ -205,19 +179,7 @@ function SignUp(): JSX.Element {
|
||||
your admin for an invite link
|
||||
</Callout>
|
||||
|
||||
{confirmPasswordError && (
|
||||
<Callout
|
||||
type="error"
|
||||
size="small"
|
||||
showIcon
|
||||
icon={<CircleAlert size={12} />}
|
||||
className="signup-error-callout"
|
||||
>
|
||||
Passwords don't match. Please try again.
|
||||
</Callout>
|
||||
)}
|
||||
|
||||
{formError && !confirmPasswordError && <AuthError error={formError} />}
|
||||
{formError && <AuthError error={formError} />}
|
||||
|
||||
<div className="signup-form-actions">
|
||||
<Button
|
||||
|
||||
@@ -200,7 +200,7 @@ func (t *telemetryMetaStore) getTracesKeys(ctx context.Context, fieldKeySelector
|
||||
`CASE
|
||||
// WHEN tagType = 'spanfield' THEN 1
|
||||
WHEN tagType = 'resource' THEN 2
|
||||
// WHEN tagType = 'scope' THEN 3
|
||||
WHEN tagType = 'scope' THEN 3
|
||||
WHEN tagType = 'tag' THEN 4
|
||||
ELSE 5
|
||||
END as priority`,
|
||||
|
||||
@@ -51,6 +51,7 @@ var (
|
||||
ValueType: schema.ColumnTypeString,
|
||||
}},
|
||||
"resource": {Name: "resource", Type: schema.JSONColumnType{}},
|
||||
"scope": {Name: "scope", Type: schema.JSONColumnType{}},
|
||||
|
||||
"events": {Name: "events", Type: schema.ArrayColumnType{
|
||||
ElementType: schema.ColumnTypeString,
|
||||
@@ -176,7 +177,7 @@ func (m *defaultFieldMapper) getColumn(
|
||||
case telemetrytypes.FieldContextResource:
|
||||
return []*schema.Column{indexV3Columns["resource"]}, nil
|
||||
case telemetrytypes.FieldContextScope:
|
||||
return []*schema.Column{}, qbtypes.ErrColumnNotFound
|
||||
return []*schema.Column{indexV3Columns["scope"]}, nil
|
||||
case telemetrytypes.FieldContextAttribute:
|
||||
switch key.FieldDataType {
|
||||
case telemetrytypes.FieldDataTypeString:
|
||||
@@ -261,21 +262,29 @@ func (m *defaultFieldMapper) FieldFor(
|
||||
|
||||
switch column.Type.GetType() {
|
||||
case schema.ColumnTypeEnumJSON:
|
||||
// json is only supported for resource context as of now
|
||||
if key.FieldContext != telemetrytypes.FieldContextResource {
|
||||
return "", errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "only resource context fields are supported for json columns, got %s", key.FieldContext.String)
|
||||
}
|
||||
oldColumn := indexV3Columns["resources_string"]
|
||||
oldKeyName := fmt.Sprintf("%s['%s']", oldColumn.Name, key.Name)
|
||||
// have to add ::string as clickHouse throws an error :- data types Variant/Dynamic are not allowed in GROUP BY
|
||||
// once clickHouse dependency is updated, we need to check if we can remove it.
|
||||
if key.Materialized {
|
||||
oldKeyName = telemetrytypes.FieldKeyToMaterializedColumnName(key)
|
||||
oldKeyNameExists := telemetrytypes.FieldKeyToMaterializedColumnNameForExists(key)
|
||||
return fmt.Sprintf("multiIf(%s.`%s` IS NOT NULL, %s.`%s`::String, %s==true, %s, NULL)", column.Name, key.Name, column.Name, key.Name, oldKeyNameExists, oldKeyName), nil
|
||||
} else {
|
||||
return fmt.Sprintf("multiIf(%s.`%s` IS NOT NULL, %s.`%s`::String, mapContains(%s, '%s'), %s, NULL)", column.Name, key.Name, column.Name, key.Name, oldColumn.Name, key.Name, oldKeyName), nil
|
||||
switch key.FieldContext {
|
||||
case telemetrytypes.FieldContextScope:
|
||||
scopeKey, _ := strings.CutPrefix(key.Name, "scope.")
|
||||
switch scopeKey {
|
||||
case "name", "version":
|
||||
return fmt.Sprintf("%s.%s::String", column.Name, scopeKey), nil
|
||||
default:
|
||||
return fmt.Sprintf("%s.attributes.`%s`::String", column.Name, scopeKey), nil
|
||||
}
|
||||
case telemetrytypes.FieldContextResource:
|
||||
oldColumn := indexV3Columns["resources_string"]
|
||||
oldKeyName := fmt.Sprintf("%s['%s']", oldColumn.Name, key.Name)
|
||||
// have to add ::string as clickHouse throws an error :- data types Variant/Dynamic are not allowed in GROUP BY
|
||||
// once clickHouse dependency is updated, we need to check if we can remove it.
|
||||
if key.Materialized {
|
||||
oldKeyName = telemetrytypes.FieldKeyToMaterializedColumnName(key)
|
||||
oldKeyNameExists := telemetrytypes.FieldKeyToMaterializedColumnNameForExists(key)
|
||||
return fmt.Sprintf("multiIf(%s.`%s` IS NOT NULL, %s.`%s`::String, %s==true, %s, NULL)", column.Name, key.Name, column.Name, key.Name, oldKeyNameExists, oldKeyName), nil
|
||||
} else {
|
||||
return fmt.Sprintf("multiIf(%s.`%s` IS NOT NULL, %s.`%s`::String, mapContains(%s, '%s'), %s, NULL)", column.Name, key.Name, column.Name, key.Name, oldColumn.Name, key.Name, oldKeyName), nil
|
||||
}
|
||||
}
|
||||
return "", errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "json column type only supported for resource and scope context, got %s", key.FieldContext.String)
|
||||
case schema.ColumnTypeEnumString,
|
||||
schema.ColumnTypeEnumUInt64,
|
||||
schema.ColumnTypeEnumUInt32,
|
||||
|
||||
@@ -78,6 +78,51 @@ func TestGetFieldKeyName(t *testing.T) {
|
||||
expectedResult: "multiIf(resource.`deployment.environment` IS NOT NULL, resource.`deployment.environment`::String, `resource_string_deployment$$environment_exists`==true, `resource_string_deployment$$environment`, NULL)",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Scope field - name",
|
||||
key: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "name",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
expectedResult: "scope.name::String",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Scope field - scope.name",
|
||||
key: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "scope.name",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
expectedResult: "scope.name::String",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Scope field - version",
|
||||
key: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "version",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
expectedResult: "scope.version::String",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Scope field - scope.version",
|
||||
key: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "scope.version",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
expectedResult: "scope.version::String",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Scope field - custom attribute",
|
||||
key: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "custom.attr",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
expectedResult: "scope.attributes.`custom.attr`::String",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Non-existent column",
|
||||
key: telemetrytypes.TelemetryFieldKey{
|
||||
|
||||
@@ -350,6 +350,66 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "scope.name filter and group by",
|
||||
requestType: qbtypes.RequestTypeTimeSeries,
|
||||
query: qbtypes.QueryBuilderQuery[qbtypes.TraceAggregation]{
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
StepInterval: qbtypes.Step{Duration: 30 * time.Second},
|
||||
Aggregations: []qbtypes.TraceAggregation{
|
||||
{
|
||||
Expression: "count()",
|
||||
},
|
||||
},
|
||||
Filter: &qbtypes.Filter{
|
||||
Expression: "scope.name = 'opentelemetry-io'",
|
||||
},
|
||||
Limit: 10,
|
||||
GroupBy: []qbtypes.GroupByKey{
|
||||
{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "scope.name",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE true AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ?), __limit_cte AS (SELECT toString(multiIf(scope.name::String IS NOT NULL, scope.name::String, NULL)) AS `scope.name`, count() AS __result_0 FROM signoz_traces.distributed_signoz_index_v3 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND (scope.name::String = ? AND scope.name::String IS NOT NULL) AND timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? GROUP BY `scope.name` ORDER BY __result_0 DESC LIMIT ?) SELECT toStartOfInterval(timestamp, INTERVAL 30 SECOND) AS ts, toString(multiIf(scope.name::String IS NOT NULL, scope.name::String, NULL)) AS `scope.name`, count() AS __result_0 FROM signoz_traces.distributed_signoz_index_v3 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND (scope.name::String = ? AND scope.name::String IS NOT NULL) AND timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? AND (`scope.name`) GLOBAL IN (SELECT `scope.name` FROM __limit_cte) GROUP BY ts, `scope.name`",
|
||||
Args: []any{uint64(1747945619), uint64(1747983448), "opentelemetry-io", "1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10, "opentelemetry-io", "1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448)},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "scope.version filter with scope.name group by",
|
||||
requestType: qbtypes.RequestTypeTimeSeries,
|
||||
query: qbtypes.QueryBuilderQuery[qbtypes.TraceAggregation]{
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
StepInterval: qbtypes.Step{Duration: 30 * time.Second},
|
||||
Aggregations: []qbtypes.TraceAggregation{
|
||||
{
|
||||
Expression: "count()",
|
||||
},
|
||||
},
|
||||
Filter: &qbtypes.Filter{
|
||||
Expression: "scope.version = '1.0.0'",
|
||||
},
|
||||
Limit: 10,
|
||||
GroupBy: []qbtypes.GroupByKey{
|
||||
{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: "scope.name",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE true AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ?), __limit_cte AS (SELECT toString(multiIf(scope.name::String IS NOT NULL, scope.name::String, NULL)) AS `scope.name`, count() AS __result_0 FROM signoz_traces.distributed_signoz_index_v3 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND (scope.version::String = ? AND scope.version::String IS NOT NULL) AND timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? GROUP BY `scope.name` ORDER BY __result_0 DESC LIMIT ?) SELECT toStartOfInterval(timestamp, INTERVAL 30 SECOND) AS ts, toString(multiIf(scope.name::String IS NOT NULL, scope.name::String, NULL)) AS `scope.name`, count() AS __result_0 FROM signoz_traces.distributed_signoz_index_v3 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND (scope.version::String = ? AND scope.version::String IS NOT NULL) AND timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? AND (`scope.name`) GLOBAL IN (SELECT `scope.name` FROM __limit_cte) GROUP BY ts, `scope.name`",
|
||||
Args: []any{uint64(1747945619), uint64(1747983448), "1.0.0", "1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10, "1.0.0", "1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448)},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
fm := NewFieldMapper()
|
||||
|
||||
@@ -111,6 +111,20 @@ func buildCompleteFieldKeyMap() map[string][]*telemetrytypes.TelemetryFieldKey {
|
||||
FieldDataType: telemetrytypes.FieldDataTypeBool,
|
||||
},
|
||||
},
|
||||
"scope.name": {
|
||||
{
|
||||
Name: "scope.name",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
},
|
||||
},
|
||||
"scope.version": {
|
||||
{
|
||||
Name: "scope.version",
|
||||
FieldContext: telemetrytypes.FieldContextScope,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, keys := range keysMap {
|
||||
for _, key := range keys {
|
||||
|
||||
Reference in New Issue
Block a user