Compare commits

..

1 Commits

Author SHA1 Message Date
primus-bot[bot]
74c875ec79 chore(release): bump to v0.125.0 (#11369)
Some checks are pending
build-staging / js-build (push) Blocked by required conditions
Release Drafter / update_release_draft (push) Waiting to run
build-staging / prepare (push) Waiting to run
build-staging / go-build (push) Blocked by required conditions
build-staging / staging (push) Blocked by required conditions
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2026-05-20 07:18:40 +00:00
14 changed files with 10 additions and 330 deletions

View File

@@ -190,7 +190,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.124.0
image: signoz/signoz:v0.125.0
ports:
- "8080:8080" # signoz port
# - "6060:6060" # pprof port

View File

@@ -117,7 +117,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.124.0
image: signoz/signoz:v0.125.0
ports:
- "8080:8080" # signoz port
volumes:

View File

@@ -181,7 +181,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.124.0}
image: signoz/signoz:${VERSION:-v0.125.0}
container_name: signoz
ports:
- "8080:8080" # signoz port

View File

@@ -109,7 +109,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.124.0}
image: signoz/signoz:${VERSION:-v0.125.0}
container_name: signoz
ports:
- "8080:8080" # signoz port

View File

@@ -2342,8 +2342,6 @@ components:
type: boolean
org_id:
type: string
source:
$ref: '#/components/schemas/DashboardtypesSource'
updatedAt:
format: date-time
type: string
@@ -2373,12 +2371,6 @@ components:
timeRangeEnabled:
type: boolean
type: object
DashboardtypesSource:
enum:
- user
- system
- integration
type: string
DashboardtypesStorableDashboardData:
additionalProperties: {}
type: object

View File

@@ -49,14 +49,6 @@ func (module *module) CreatePublic(ctx context.Context, orgID valuer.UUID, publi
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
dashboard, err := module.Get(ctx, orgID, publicDashboard.DashboardID)
if err != nil {
return err
}
if err := dashboard.ErrIfNotPublishable(); err != nil {
return err
}
storablePublicDashboard, err := module.store.GetPublic(ctx, publicDashboard.DashboardID.StringValue())
if err != nil && !errors.Ast(err, errors.TypeNotFound) {
return err
@@ -137,14 +129,6 @@ func (module *module) UpdatePublic(ctx context.Context, orgID valuer.UUID, publi
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
dashboard, err := module.Get(ctx, orgID, publicDashboard.DashboardID)
if err != nil {
return err
}
if err := dashboard.ErrIfNotPublishable(); err != nil {
return err
}
return module.store.UpdatePublic(ctx, dashboardtypes.NewStorablePublicDashboardFromPublicDashboard(publicDashboard))
}
@@ -154,10 +138,6 @@ func (module *module) Delete(ctx context.Context, orgID valuer.UUID, id valuer.U
return err
}
if err := dashboard.ErrIfNotDeletable(); err != nil {
return err
}
if dashboard.Locked {
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "dashboard is locked, please unlock the dashboard to be delete it")
}
@@ -188,14 +168,6 @@ func (module *module) DeletePublic(ctx context.Context, orgID valuer.UUID, dashb
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
dashboard, err := module.Get(ctx, orgID, dashboardID)
if err != nil {
return err
}
if err := dashboard.ErrIfNotPublishable(); err != nil {
return err
}
err = module.store.DeletePublic(ctx, dashboardID.StringValue())
if err != nil {
return err

View File

@@ -2999,11 +2999,6 @@ export interface CoretypesPatchableObjectsDTO {
deletions: CoretypesObjectGroupDTO[] | null;
}
export enum DashboardtypesSourceDTO {
user = 'user',
system = 'system',
integration = 'integration',
}
export interface DashboardtypesDashboardDTO {
/**
* @type string
@@ -3027,7 +3022,6 @@ export interface DashboardtypesDashboardDTO {
* @type string
*/
org_id?: string;
source?: DashboardtypesSourceDTO;
/**
* @type string
* @format date-time

View File

@@ -38,7 +38,7 @@ func NewModule(store dashboardtypes.Store, settings factory.ProviderSettings, an
}
func (module *module) Create(ctx context.Context, orgID valuer.UUID, createdBy string, creator valuer.UUID, postableDashboard dashboardtypes.PostableDashboard) (*dashboardtypes.Dashboard, error) {
dashboard, err := dashboardtypes.NewDashboard(orgID, createdBy, dashboardtypes.SourceUser, postableDashboard)
dashboard, err := dashboardtypes.NewDashboard(orgID, createdBy, postableDashboard)
if err != nil {
return nil, err
}
@@ -72,16 +72,7 @@ func (module *module) List(ctx context.Context, orgID valuer.UUID) ([]*dashboard
return nil, err
}
// system dashboards are hidden from the listing endpoint but still gettable by id.
filtered := make([]*dashboardtypes.StorableDashboard, 0, len(storableDashboards))
for _, storable := range storableDashboards {
if storable.Source == dashboardtypes.SourceSystem {
continue
}
filtered = append(filtered, storable)
}
return dashboardtypes.NewDashboardsFromStorableDashboards(filtered), nil
return dashboardtypes.NewDashboardsFromStorableDashboards(storableDashboards), nil
}
func (module *module) Update(ctx context.Context, orgID valuer.UUID, id valuer.UUID, updatedBy string, updatableDashboard dashboardtypes.UpdatableDashboard, diff int) (*dashboardtypes.Dashboard, error) {
@@ -90,10 +81,6 @@ func (module *module) Update(ctx context.Context, orgID valuer.UUID, id valuer.U
return nil, err
}
if err := dashboard.ErrIfNotMutable(); err != nil {
return nil, err
}
err = dashboard.Update(ctx, updatableDashboard, updatedBy, diff)
if err != nil {
return nil, err
@@ -118,10 +105,6 @@ func (module *module) LockUnlock(ctx context.Context, orgID valuer.UUID, id valu
return err
}
if err := dashboard.ErrIfNotLockable(); err != nil {
return err
}
err = dashboard.LockUnlock(lock, isAdmin, updatedBy)
if err != nil {
return err
@@ -145,10 +128,6 @@ func (module *module) Delete(ctx context.Context, orgID valuer.UUID, id valuer.U
return err
}
if err := dashboard.ErrIfNotDeletable(); err != nil {
return err
}
if dashboard.Locked {
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "dashboard is locked, please unlock the dashboard to be delete it")
}

View File

@@ -348,8 +348,7 @@ func (m *Manager) GetInstalledIntegrationDashboardById(
CreatedBy: author,
UpdatedBy: author,
},
OrgID: orgId,
Source: dashboardtypes.SourceIntegration,
OrgID: orgId,
}, nil
}
}
@@ -388,8 +387,7 @@ func (m *Manager) GetDashboardsForInstalledIntegrations(
CreatedBy: author,
UpdatedBy: author,
},
OrgID: orgId,
Source: dashboardtypes.SourceIntegration,
OrgID: orgId,
})
}
}

View File

@@ -204,7 +204,6 @@ func NewSQLMigrationProviderFactories(
sqlmigration.NewAddTagsFactory(sqlstore, sqlschema),
sqlmigration.NewAddRoleCRUDTuplesFactory(sqlstore),
sqlmigration.NewAddIntegrationDashboardFactory(sqlstore, sqlschema),
sqlmigration.NewAddSourceToDashboardFactory(sqlstore, sqlschema),
)
}

View File

@@ -1,79 +0,0 @@
package sqlmigration
import (
"context"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlschema"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
)
type addSourceToDashboard struct {
sqlstore sqlstore.SQLStore
sqlschema sqlschema.SQLSchema
}
func NewAddSourceToDashboardFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(
factory.MustNewName("add_source_to_dashboard"),
func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return &addSourceToDashboard{sqlstore: sqlstore, sqlschema: sqlschema}, nil
},
)
}
func (migration *addSourceToDashboard) Register(migrations *migrate.Migrations) error {
return migrations.Register(migration.Up, migration.Down)
}
func (migration *addSourceToDashboard) Up(ctx context.Context, db *bun.DB) error {
// dashboard is referenced by public_dashboard and integration_dashboard;
// FK enforcement must be off for the SQLite recreate-table fallback.
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, false); err != nil {
return err
}
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer func() {
_ = tx.Rollback()
}()
table, uniqueConstraints, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("dashboard"))
if err != nil {
return err
}
sourceColumn := &sqlschema.Column{
Name: sqlschema.ColumnName("source"),
DataType: sqlschema.DataTypeText,
Nullable: false,
}
// backfill existing rows with 'user' before the NOT NULL flip.
sqls := migration.sqlschema.Operator().AddColumn(table, uniqueConstraints, sourceColumn, "user")
for _, sql := range sqls {
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
return err
}
}
if err := tx.Commit(); err != nil {
return err
}
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, true); err != nil {
return err
}
return nil
}
func (migration *addSourceToDashboard) Down(context.Context, *bun.DB) error {
return nil
}

View File

@@ -366,7 +366,6 @@ func GetDashboardsFromAssets(
CreatedBy: author,
UpdatedBy: author,
},
Source: dashboardtypes.SourceIntegration,
})
}

View File

@@ -2,10 +2,8 @@ package dashboardtypes
import (
"context"
"database/sql/driver"
"encoding/json"
"log/slog"
"slices"
"time"
"github.com/SigNoz/signoz/pkg/errors"
@@ -21,66 +19,8 @@ var (
ErrCodeDashboardNotFound = errors.MustNewCode("dashboard_not_found")
ErrCodeDashboardInvalidData = errors.MustNewCode("dashboard_invalid_data")
ErrCodeDashboardInvalidWidgetQuery = errors.MustNewCode("dashboard_invalid_widget_query")
ErrCodeDashboardInvalidSource = errors.MustNewCode("dashboard_invalid_source")
ErrCodeDashboardImmutable = errors.MustNewCode("dashboard_immutable")
)
type Source struct {
valuer.String
}
var (
SourceUser = Source{valuer.NewString("user")}
SourceSystem = Source{valuer.NewString("system")}
SourceIntegration = Source{valuer.NewString("integration")}
)
func (Source) Enum() []any {
return []any{SourceUser, SourceSystem, SourceIntegration}
}
func (s Source) IsValid() bool {
return slices.ContainsFunc(s.Enum(), func(v any) bool { return v == s })
}
// Value rejects anything outside the enum so unknown values can't be written.
func (s Source) Value() (driver.Value, error) {
if !s.IsValid() {
return nil, errors.Newf(errors.TypeInvalidInput, ErrCodeDashboardInvalidSource, "invalid dashboard source %q, must be one of user, system, integration", s.StringValue())
}
return s.StringValue(), nil
}
// Scan is lenient on read; deliberate choice to not break
// reads. Strictness lives in Value.
func (s *Source) Scan(src any) error {
if src == nil {
return errors.Newf(errors.TypeInternal, errors.CodeInternal, "dashboard source: cannot scan nil")
}
var val string
switch v := src.(type) {
case string:
val = v
case []byte:
val = string(v)
default:
return errors.Newf(errors.TypeInternal, errors.CodeInternal, "dashboard source: cannot scan %T", src)
}
*s = Source{valuer.NewString(val)}
return nil
}
// NewSource validates a caller-supplied source string.
func NewSource(source string) (Source, error) {
candidate := Source{valuer.NewString(source)}
if !candidate.IsValid() {
return Source{}, errors.Newf(errors.TypeInvalidInput, ErrCodeDashboardInvalidSource, "invalid dashboard source %q, must be one of user, system, integration", source)
}
return candidate, nil
}
type StorableDashboard struct {
bun.BaseModel `bun:"table:dashboard,alias:dashboard"`
@@ -90,7 +30,6 @@ type StorableDashboard struct {
Data StorableDashboardData `bun:"data,type:text,notnull"`
Locked bool `bun:"locked,notnull,default:false"`
OrgID valuer.UUID `bun:"org_id,notnull"`
Source Source `bun:"source,type:text,notnull"`
}
type Dashboard struct {
@@ -101,7 +40,6 @@ type Dashboard struct {
Data StorableDashboardData `json:"data"`
Locked bool `json:"locked"`
OrgID valuer.UUID `json:"org_id"`
Source Source `json:"source"`
}
type LockUnlockDashboard struct {
@@ -126,10 +64,6 @@ func NewStorableDashboardFromDashboard(dashboard *Dashboard) (*StorableDashboard
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid uuid")
}
if !dashboard.Source.IsValid() {
return nil, errors.Newf(errors.TypeInvalidInput, ErrCodeDashboardInvalidSource, "invalid dashboard source %q", dashboard.Source.StringValue())
}
return &StorableDashboard{
Identifiable: types.Identifiable{
ID: dashboardID,
@@ -145,15 +79,10 @@ func NewStorableDashboardFromDashboard(dashboard *Dashboard) (*StorableDashboard
OrgID: dashboard.OrgID,
Data: dashboard.Data,
Locked: dashboard.Locked,
Source: dashboard.Source,
}, nil
}
func NewDashboard(orgID valuer.UUID, createdBy string, source Source, storableDashboardData StorableDashboardData) (*Dashboard, error) {
if !source.IsValid() {
return nil, errors.Newf(errors.TypeInvalidInput, ErrCodeDashboardInvalidSource, "invalid dashboard source %q", source.StringValue())
}
func NewDashboard(orgID valuer.UUID, createdBy string, storableDashboardData StorableDashboardData) (*Dashboard, error) {
currentTime := time.Now()
return &Dashboard{
@@ -169,7 +98,6 @@ func NewDashboard(orgID valuer.UUID, createdBy string, source Source, storableDa
OrgID: orgID,
Data: storableDashboardData,
Locked: false,
Source: source,
}, nil
}
@@ -187,7 +115,6 @@ func NewDashboardFromStorableDashboard(storableDashboard *StorableDashboard) *Da
OrgID: storableDashboard.OrgID,
Data: storableDashboard.Data,
Locked: storableDashboard.Locked,
Source: storableDashboard.Source,
}
}
@@ -220,7 +147,6 @@ func NewGettableDashboardFromDashboard(dashboard *Dashboard) (*GettableDashboard
OrgID: dashboard.OrgID,
Data: dashboard.Data,
Locked: dashboard.Locked,
Source: dashboard.Source,
}, nil
}
@@ -312,43 +238,6 @@ func (storableDashboardData *StorableDashboardData) GetWidgetIds() []string {
return widgetIds
}
func (dashboard *Dashboard) ErrIfNotMutable() error {
if dashboard.Source == SourceIntegration {
return errors.Newf(errors.TypeForbidden, ErrCodeDashboardImmutable, "integration dashboards cannot be modified")
}
return nil
}
func (dashboard *Dashboard) ErrIfNotDeletable() error {
if err := dashboard.ErrIfNotMutable(); err != nil {
return err
}
if dashboard.Source == SourceSystem {
return errors.Newf(errors.TypeForbidden, ErrCodeDashboardImmutable, "system dashboards cannot be deleted")
}
return nil
}
func (dashboard *Dashboard) ErrIfNotLockable() error {
if err := dashboard.ErrIfNotMutable(); err != nil {
return err
}
if dashboard.Source == SourceSystem {
return errors.Newf(errors.TypeForbidden, ErrCodeDashboardImmutable, "system dashboards cannot be locked or unlocked")
}
return nil
}
func (dashboard *Dashboard) ErrIfNotPublishable() error {
if err := dashboard.ErrIfNotMutable(); err != nil {
return err
}
if dashboard.Source == SourceSystem {
return errors.Newf(errors.TypeForbidden, ErrCodeDashboardImmutable, "system dashboards cannot be made public")
}
return nil
}
func (dashboard *Dashboard) CanUpdate(ctx context.Context, data StorableDashboardData, diff int) error {
if dashboard.Locked {
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot update a locked dashboard, please unlock the dashboard to update")

View File

@@ -6,7 +6,6 @@ import (
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func makeTestWidgets(ids ...string) []interface{} {
@@ -20,68 +19,6 @@ func makeTestWidgets(ids ...string) []interface{} {
return widgets
}
func TestSourceEnum(t *testing.T) {
t.Run("valid sources round-trip through Value/Scan", func(t *testing.T) {
for _, src := range []Source{SourceUser, SourceSystem, SourceIntegration} {
val, err := src.Value()
require.NoError(t, err)
var got Source
require.NoError(t, got.Scan(val))
assert.Equal(t, src, got)
}
})
t.Run("invalid source is rejected by Value", func(t *testing.T) {
bogus := Source{valuer.NewString("hacker")}
_, err := bogus.Value()
assert.Error(t, err)
})
t.Run("Scan tolerates unknown strings, Value still rejects them", func(t *testing.T) {
var got Source
require.NoError(t, got.Scan("future_source"))
assert.Equal(t, "future_source", got.StringValue())
assert.False(t, got.IsValid())
_, err := got.Value()
assert.Error(t, err)
})
t.Run("NewSource validates input", func(t *testing.T) {
s, err := NewSource("USER")
require.NoError(t, err)
assert.Equal(t, SourceUser, s)
_, err = NewSource("nope")
assert.Error(t, err)
})
}
func TestErrIfNotMutable_BySource(t *testing.T) {
cases := []struct {
source Source
mutable bool
deletable bool
lockable bool
publishable bool
}{
{SourceUser, true, true, true, true},
{SourceSystem, true, false, false, false},
{SourceIntegration, false, false, false, false},
}
for _, tc := range cases {
t.Run(tc.source.StringValue(), func(t *testing.T) {
d := &Dashboard{Source: tc.source}
assert.Equal(t, tc.mutable, d.ErrIfNotMutable() == nil)
assert.Equal(t, tc.deletable, d.ErrIfNotDeletable() == nil)
assert.Equal(t, tc.lockable, d.ErrIfNotLockable() == nil)
assert.Equal(t, tc.publishable, d.ErrIfNotPublishable() == nil)
})
}
}
func TestCanUpdate_MultipleDeletions_ByDiff(t *testing.T) {
testCases := []struct {
name string
@@ -129,7 +66,7 @@ func TestCanUpdate_MultipleDeletions_ByDiff(t *testing.T) {
initial := StorableDashboardData{
"widgets": makeTestWidgets("a", "b", "c"),
}
d, err := NewDashboard(orgID, "tester", SourceUser, initial)
d, err := NewDashboard(orgID, "tester", initial)
assert.NoError(t, err)
updated := StorableDashboardData{