From a0405912a84e8db4259550632235d2f978c86228 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 25 Jan 2023 11:00:32 -0800 Subject: [PATCH] Preferences: Add preferences kind and remove unused navbar settings (#59621) --- .../core/preferences/schema-reference.md | 33 +++++ kinds/preferences/preferences_kind.cue | 36 ++++++ packages/grafana-schema/src/index.gen.ts | 6 + .../preferences/x/preferences_types.gen.ts | 44 +++++++ pkg/api/dtos/prefs.go | 13 -- pkg/api/preferences.go | 39 +++--- pkg/kinds/preferences/preferences_kind_gen.go | 113 ++++++++++++++++++ .../preferences/preferences_types_gen.go | 37 ++++++ pkg/kindsys/report.json | 32 ++++- pkg/registry/corekind/base_gen.go | 14 +++ pkg/services/preference/model.go | 14 --- pkg/services/preference/prefimpl/pref.go | 26 ---- pkg/services/preference/prefimpl/pref_test.go | 43 +------ .../preference/prefimpl/store_test.go | 9 +- pkg/services/store/entity/models.go | 13 +- .../store/kind/preferences/summary.go | 54 +++++++++ pkg/services/store/kind/registry.go | 5 + pkg/services/store/kind/registry_test.go | 1 + .../SharedPreferences.test.tsx | 2 +- .../SharedPreferences/SharedPreferences.tsx | 10 +- .../history/RichHistoryRemoteStorage.test.ts | 4 +- .../app/core/services/PreferencesService.ts | 2 +- public/app/types/index.ts | 1 - public/app/types/preferences.ts | 13 -- 24 files changed, 420 insertions(+), 144 deletions(-) create mode 100644 docs/sources/developers/kinds/core/preferences/schema-reference.md create mode 100644 kinds/preferences/preferences_kind.cue create mode 100644 packages/grafana-schema/src/raw/preferences/x/preferences_types.gen.ts create mode 100644 pkg/kinds/preferences/preferences_kind_gen.go create mode 100644 pkg/kinds/preferences/preferences_types_gen.go create mode 100644 pkg/services/store/kind/preferences/summary.go delete mode 100644 public/app/types/preferences.ts diff --git a/docs/sources/developers/kinds/core/preferences/schema-reference.md b/docs/sources/developers/kinds/core/preferences/schema-reference.md new file mode 100644 index 00000000000..fc5bf9ec796 --- /dev/null +++ b/docs/sources/developers/kinds/core/preferences/schema-reference.md @@ -0,0 +1,33 @@ +--- +keywords: + - grafana + - schema +title: Preferences kind +--- +> Both documentation generation and kinds schemas are in active development and subject to change without prior notice. + +# Preferences kind + +## Maturity: merged +## Version: 0.0 + +## Properties + +| Property | Type | Required | Description | +|--------------------|---------------------------------------------------|----------|---------------------------------------------------------------------------------| +| `homeDashboardUID` | string | No | UID for the home dashboard | +| `language` | string | No | Selected language (beta) | +| `queryHistory` | [QueryHistoryPreference](#queryhistorypreference) | No | | +| `theme` | string | No | light, dark, empty is default | +| `timezone` | string | No | The timezone selection
TODO: this should use the timezone defined in common | +| `weekStart` | string | No | day of the week (sunday, monday, etc) | + +## QueryHistoryPreference + +### Properties + +| Property | Type | Required | Description | +|-----------|--------|----------|---------------------------------------------| +| `homeTab` | string | No | one of: '' | 'query' | 'starred'; | + + diff --git a/kinds/preferences/preferences_kind.cue b/kinds/preferences/preferences_kind.cue new file mode 100644 index 00000000000..1e4be8b9b82 --- /dev/null +++ b/kinds/preferences/preferences_kind.cue @@ -0,0 +1,36 @@ +package kind + +name: "Preferences" +maturity: "merged" + +lineage: seqs: [ + { + schemas: [ + { + // UID for the home dashboard + homeDashboardUID?: string + + // The timezone selection + // TODO: this should use the timezone defined in common + timezone?: string + + // day of the week (sunday, monday, etc) + weekStart?: string + + // light, dark, empty is default + theme?: string + + // Selected language (beta) + language?: string + + // Explore query history preferences + queryHistory?: #QueryHistoryPreference + + #QueryHistoryPreference: { + // one of: '' | 'query' | 'starred'; + homeTab?: string + } @cuetsy(kind="interface") //0.0 + }, + ] + }, +] diff --git a/packages/grafana-schema/src/index.gen.ts b/packages/grafana-schema/src/index.gen.ts index 6e9378c10c7..500568d6555 100644 --- a/packages/grafana-schema/src/index.gen.ts +++ b/packages/grafana-schema/src/index.gen.ts @@ -95,6 +95,12 @@ export type { // Raw generated enums and default consts from playlist kind. export { defaultPlaylist } from './raw/playlist/x/playlist_types.gen'; +// Raw generated types from Preferences kind. +export type { + Preferences, + QueryHistoryPreference +} from './raw/preferences/x/preferences_types.gen'; + // Raw generated types from Serviceaccount kind. export type { Serviceaccount, diff --git a/packages/grafana-schema/src/raw/preferences/x/preferences_types.gen.ts b/packages/grafana-schema/src/raw/preferences/x/preferences_types.gen.ts new file mode 100644 index 00000000000..e18a9375d62 --- /dev/null +++ b/packages/grafana-schema/src/raw/preferences/x/preferences_types.gen.ts @@ -0,0 +1,44 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. +// +// Generated by: +// kinds/gen.go +// Using jennies: +// TSTypesJenny +// LatestMajorsOrXJenny +// +// Run 'make gen-cue' from repository root to regenerate. + +export interface QueryHistoryPreference { + /** + * one of: '' | 'query' | 'starred'; + */ + homeTab?: string; +} + +export interface Preferences { + /** + * UID for the home dashboard + */ + homeDashboardUID?: string; + /** + * Selected language (beta) + */ + language?: string; + /** + * Explore query history preferences + */ + queryHistory?: QueryHistoryPreference; + /** + * light, dark, empty is default + */ + theme?: string; + /** + * The timezone selection + * TODO: this should use the timezone defined in common + */ + timezone?: string; + /** + * day of the week (sunday, monday, etc) + */ + weekStart?: string; +} diff --git a/pkg/api/dtos/prefs.go b/pkg/api/dtos/prefs.go index 4dc3d7cc97c..b92ae22f221 100644 --- a/pkg/api/dtos/prefs.go +++ b/pkg/api/dtos/prefs.go @@ -4,17 +4,6 @@ import ( pref "github.com/grafana/grafana/pkg/services/preference" ) -type Prefs struct { - Theme string `json:"theme"` - HomeDashboardID int64 `json:"homeDashboardId"` - HomeDashboardUID string `json:"homeDashboardUID,omitempty"` - Timezone string `json:"timezone"` - WeekStart string `json:"weekStart"` - Language string `json:"language"` - Navbar pref.NavbarPreference `json:"navbar,omitempty"` - QueryHistory pref.QueryHistoryPreference `json:"queryHistory,omitempty"` -} - // swagger:model type UpdatePrefsCmd struct { // Enum: light,dark @@ -26,7 +15,6 @@ type UpdatePrefsCmd struct { // Enum: utc,browser Timezone string `json:"timezone"` WeekStart string `json:"weekStart"` - Navbar *pref.NavbarPreference `json:"navbar,omitempty"` QueryHistory *pref.QueryHistoryPreference `json:"queryHistory,omitempty"` Language string `json:"language"` } @@ -42,7 +30,6 @@ type PatchPrefsCmd struct { Timezone *string `json:"timezone,omitempty"` WeekStart *string `json:"weekStart,omitempty"` Language *string `json:"language,omitempty"` - Navbar *pref.NavbarPreference `json:"navbar,omitempty"` QueryHistory *pref.QueryHistoryPreference `json:"queryHistory,omitempty"` HomeDashboardUID *string `json:"homeDashboardUID,omitempty"` } diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index 7f9761723d5..456b5a31dc6 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/kinds/preferences" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/dashboards" pref "github.com/grafana/grafana/pkg/services/preference" @@ -83,23 +84,31 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team } } - weekStart := "" - if preference.WeekStart != nil { - weekStart = *preference.WeekStart - } + dto := preferences.Preferences{} - dto := dtos.Prefs{ - Theme: preference.Theme, - HomeDashboardID: preference.HomeDashboardID, - HomeDashboardUID: dashboardUID, - Timezone: preference.Timezone, - WeekStart: weekStart, + if preference.WeekStart != nil && *preference.WeekStart != "" { + dto.WeekStart = preference.WeekStart + } + if preference.Theme != "" { + dto.Theme = &preference.Theme + } + if dashboardUID != "" { + dto.HomeDashboardUID = &dashboardUID + } + if preference.Timezone != "" { + dto.Timezone = &preference.Timezone } if preference.JSONData != nil { - dto.Language = preference.JSONData.Language - dto.Navbar = preference.JSONData.Navbar - dto.QueryHistory = preference.JSONData.QueryHistory + if preference.JSONData.Language != "" { + dto.Language = &preference.JSONData.Language + } + + if preference.JSONData.QueryHistory.HomeTab != "" { + dto.QueryHistory = &preferences.QueryHistoryPreference{ + HomeTab: &preference.JSONData.QueryHistory.HomeTab, + } + } } return response.JSON(http.StatusOK, &dto) @@ -155,7 +164,6 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t WeekStart: dtoCmd.WeekStart, HomeDashboardID: dtoCmd.HomeDashboardID, QueryHistory: dtoCmd.QueryHistory, - Navbar: dtoCmd.Navbar, } if err := hs.preferenceService.Save(ctx, &saveCmd); err != nil { @@ -214,7 +222,6 @@ func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, te WeekStart: dtoCmd.WeekStart, HomeDashboardID: dtoCmd.HomeDashboardID, Language: dtoCmd.Language, - Navbar: dtoCmd.Navbar, QueryHistory: dtoCmd.QueryHistory, } @@ -292,7 +299,7 @@ type UpdateOrgPreferencesParams struct { // swagger:response getPreferencesResponse type GetPreferencesResponse struct { // in:body - Body dtos.Prefs `json:"body"` + Body preferences.Preferences `json:"body"` } // swagger:parameters patchUserPreferences diff --git a/pkg/kinds/preferences/preferences_kind_gen.go b/pkg/kinds/preferences/preferences_kind_gen.go new file mode 100644 index 00000000000..4ffd0a15688 --- /dev/null +++ b/pkg/kinds/preferences/preferences_kind_gen.go @@ -0,0 +1,113 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. +// +// Generated by: +// kinds/gen.go +// Using jennies: +// CoreKindJenny +// +// Run 'make gen-cue' from repository root to regenerate. + +package preferences + +import ( + "github.com/grafana/grafana/pkg/kindsys" + "github.com/grafana/thema" + "github.com/grafana/thema/vmux" +) + +// rootrel is the relative path from the grafana repository root to the +// directory containing the .cue files in which this kind is declared. Necessary +// for runtime errors related to the declaration and/or lineage to provide +// a real path to the correct .cue file. +const rootrel string = "kinds/preferences" + +// TODO standard generated docs +type Kind struct { + lin thema.ConvergentLineage[*Preferences] + jcodec vmux.Codec + valmux vmux.ValueMux[*Preferences] + decl kindsys.Decl[kindsys.CoreProperties] +} + +// type guard +var _ kindsys.Core = &Kind{} + +// TODO standard generated docs +func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) { + decl, err := kindsys.LoadCoreKind(rootrel, rt.Context(), nil) + if err != nil { + return nil, err + } + k := &Kind{ + decl: decl, + } + + lin, err := decl.Some().BindKindLineage(rt, opts...) + if err != nil { + return nil, err + } + + // Get the thema.Schema that the meta says is in the current version (which + // codegen ensures is always the latest) + cursch := thema.SchemaP(lin, k.decl.Properties.CurrentVersion) + tsch, err := thema.BindType[*Preferences](cursch, &Preferences{}) + if err != nil { + // Should be unreachable, modulo bugs in the Thema->Go code generator + return nil, err + } + + k.jcodec = vmux.NewJSONCodec("preferences.json") + k.lin = tsch.ConvergentLineage() + k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec) + return k, nil +} + +// TODO standard generated docs +func (k *Kind) Name() string { + return "preferences" +} + +// TODO standard generated docs +func (k *Kind) MachineName() string { + return "preferences" +} + +// TODO standard generated docs +func (k *Kind) Lineage() thema.Lineage { + return k.lin +} + +// TODO standard generated docs +func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Preferences] { + return k.lin +} + +// JSONValueMux is a version multiplexer that maps a []byte containing JSON data +// at any schematized dashboard version to an instance of Preferences. +// +// Validation and translation errors emitted from this func will identify the +// input bytes as "dashboard.json". +// +// This is a thin wrapper around Thema's [vmux.ValueMux]. +func (k *Kind) JSONValueMux(b []byte) (*Preferences, thema.TranslationLacunas, error) { + return k.valmux(b) +} + +// TODO standard generated docs +func (k *Kind) Maturity() kindsys.Maturity { + return k.decl.Properties.Maturity +} + +// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the +// preferences declaration in .cue files. +func (k *Kind) Decl() kindsys.Decl[kindsys.CoreProperties] { + return k.decl +} + +// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreProperties], +// representing the static properties declared in the preferences kind. +// +// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface]. +func (k *Kind) Props() kindsys.SomeKindProperties { + return k.decl.Properties +} diff --git a/pkg/kinds/preferences/preferences_types_gen.go b/pkg/kinds/preferences/preferences_types_gen.go new file mode 100644 index 00000000000..9ab65c6c388 --- /dev/null +++ b/pkg/kinds/preferences/preferences_types_gen.go @@ -0,0 +1,37 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. +// +// Generated by: +// kinds/gen.go +// Using jennies: +// GoTypesJenny +// LatestJenny +// +// Run 'make gen-cue' from repository root to regenerate. + +package preferences + +// QueryHistoryPreference defines model for QueryHistoryPreference. +type QueryHistoryPreference struct { + // one of: '' | 'query' | 'starred'; + HomeTab *string `json:"homeTab,omitempty"` +} + +// Preferences defines model for preferences. +type Preferences struct { + // UID for the home dashboard + HomeDashboardUID *string `json:"homeDashboardUID,omitempty"` + + // Selected language (beta) + Language *string `json:"language,omitempty"` + QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"` + + // light, dark, empty is default + Theme *string `json:"theme,omitempty"` + + // The timezone selection + // TODO: this should use the timezone defined in common + Timezone *string `json:"timezone,omitempty"` + + // day of the week (sunday, monday, etc) + WeekStart *string `json:"weekStart,omitempty"` +} diff --git a/pkg/kindsys/report.json b/pkg/kindsys/report.json index 35d314c27c9..2f97bb2c5dd 100644 --- a/pkg/kindsys/report.json +++ b/pkg/kindsys/report.json @@ -1211,6 +1211,32 @@ "pluralName": "PostgreSQLDataSourceCfgs", "schemaInterface": "DataSourceCfg" }, + "preferences": { + "category": "core", + "codeowners": [ + "grafana/grafana-as-code", + "grafana/grafana-bi-squad", + "grafana/plugins-platform-frontend", + "grafana/user-essentials" + ], + "currentVersion": [ + 0, + 0 + ], + "grafanaMaturityCount": 0, + "lineageIsGroup": false, + "links": { + "docs": "https://grafana.com/docs/grafana/next/developers/kinds/core/preferences/schema-reference", + "go": "https://github.com/grafana/grafana/tree/main/pkg/kinds/preferences", + "schema": "https://github.com/grafana/grafana/tree/main/kinds/preferences/preferences_kind.cue", + "ts": "https://github.com/grafana/grafana/tree/main/packages/grafana-schema/src/raw/preferences/x/preferences_types.gen.ts" + }, + "machineName": "preferences", + "maturity": "merged", + "name": "Preferences", + "pluralMachineName": "preferencess", + "pluralName": "Preferencess" + }, "prometheusdataquery": { "category": "composable", "codeowners": [], @@ -1739,6 +1765,7 @@ "datasource", "folder", "playlist", + "preferences", "query", "queryhistory", "serviceaccount", @@ -1746,7 +1773,7 @@ "thumb", "user" ], - "count": 11 + "count": 12 } }, "maturity": { @@ -1777,10 +1804,11 @@ "items": [ "alertgroupspanelcfg", "playlist", + "preferences", "serviceaccount", "team" ], - "count": 4 + "count": 5 }, "planned": { "name": "planned", diff --git a/pkg/registry/corekind/base_gen.go b/pkg/registry/corekind/base_gen.go index f3e52a08564..3770ae0250e 100644 --- a/pkg/registry/corekind/base_gen.go +++ b/pkg/registry/corekind/base_gen.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/kinds/dashboard" "github.com/grafana/grafana/pkg/kinds/playlist" + "github.com/grafana/grafana/pkg/kinds/preferences" "github.com/grafana/grafana/pkg/kinds/serviceaccount" "github.com/grafana/grafana/pkg/kinds/team" "github.com/grafana/grafana/pkg/kindsys" @@ -34,6 +35,7 @@ type Base struct { all []kindsys.Core dashboard *dashboard.Kind playlist *playlist.Kind + preferences *preferences.Kind serviceaccount *serviceaccount.Kind team *team.Kind } @@ -42,6 +44,7 @@ type Base struct { var ( _ kindsys.Core = &dashboard.Kind{} _ kindsys.Core = &playlist.Kind{} + _ kindsys.Core = &preferences.Kind{} _ kindsys.Core = &serviceaccount.Kind{} _ kindsys.Core = &team.Kind{} ) @@ -56,6 +59,11 @@ func (b *Base) Playlist() *playlist.Kind { return b.playlist } +// Preferences returns the [kindsys.Interface] implementation for the preferences kind. +func (b *Base) Preferences() *preferences.Kind { + return b.preferences +} + // Serviceaccount returns the [kindsys.Interface] implementation for the serviceaccount kind. func (b *Base) Serviceaccount() *serviceaccount.Kind { return b.serviceaccount @@ -82,6 +90,12 @@ func doNewBase(rt *thema.Runtime) *Base { } reg.all = append(reg.all, reg.playlist) + reg.preferences, err = preferences.NewKind(rt) + if err != nil { + panic(fmt.Sprintf("error while initializing the preferences Kind: %s", err)) + } + reg.all = append(reg.all, reg.preferences) + reg.serviceaccount, err = serviceaccount.NewKind(rt) if err != nil { panic(fmt.Sprintf("error while initializing the serviceaccount Kind: %s", err)) diff --git a/pkg/services/preference/model.go b/pkg/services/preference/model.go index 9bb6a2ef22f..7505255a3bd 100644 --- a/pkg/services/preference/model.go +++ b/pkg/services/preference/model.go @@ -50,7 +50,6 @@ type SavePreferenceCommand struct { WeekStart string `json:"weekStart,omitempty"` Theme string `json:"theme,omitempty"` Language string `json:"language,omitempty"` - Navbar *NavbarPreference `json:"navbar,omitempty"` QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"` } @@ -65,24 +64,11 @@ type PatchPreferenceCommand struct { WeekStart *string `json:"weekStart,omitempty"` Theme *string `json:"theme,omitempty"` Language *string `json:"language,omitempty"` - Navbar *NavbarPreference `json:"navbar,omitempty"` QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"` } -type NavLink struct { - ID string `json:"id,omitempty"` - Text string `json:"text,omitempty"` - Url string `json:"url,omitempty"` - Target string `json:"target,omitempty"` -} - -type NavbarPreference struct { - SavedItems []NavLink `json:"savedItems"` -} - type PreferenceJSONData struct { Language string `json:"language"` - Navbar NavbarPreference `json:"navbar"` QueryHistory QueryHistoryPreference `json:"queryHistory"` } diff --git a/pkg/services/preference/prefimpl/pref.go b/pkg/services/preference/prefimpl/pref.go index feadcbfa06e..1ddc5b94cf0 100644 --- a/pkg/services/preference/prefimpl/pref.go +++ b/pkg/services/preference/prefimpl/pref.go @@ -65,10 +65,6 @@ func (s *Service) GetWithDefaults(ctx context.Context, query *pref.GetPreference res.JSONData.Language = p.JSONData.Language } - if len(p.JSONData.Navbar.SavedItems) > 0 { - res.JSONData.Navbar = p.JSONData.Navbar - } - if p.JSONData.QueryHistory.HomeTab != "" { res.JSONData.QueryHistory.HomeTab = p.JSONData.QueryHistory.HomeTab } @@ -134,9 +130,6 @@ func (s *Service) Save(ctx context.Context, cmd *pref.SavePreferenceCommand) err Language: cmd.Language, } - if cmd.Navbar != nil { - preference.JSONData.Navbar = *cmd.Navbar - } if cmd.QueryHistory != nil { preference.JSONData.QueryHistory = *cmd.QueryHistory } @@ -173,15 +166,6 @@ func (s *Service) Patch(ctx context.Context, cmd *pref.PatchPreferenceCommand) e preference.JSONData.Language = *cmd.Language } - if cmd.Navbar != nil { - if preference.JSONData == nil { - preference.JSONData = &pref.PreferenceJSONData{} - } - if cmd.Navbar.SavedItems != nil { - preference.JSONData.Navbar.SavedItems = cmd.Navbar.SavedItems - } - } - if cmd.QueryHistory != nil { if preference.JSONData == nil { preference.JSONData = &pref.PreferenceJSONData{} @@ -210,16 +194,6 @@ func (s *Service) Patch(ctx context.Context, cmd *pref.PatchPreferenceCommand) e preference.Updated = time.Now() preference.Version += 1 - // Wrap this in an if statement to maintain backwards compatibility - if cmd.Navbar != nil { - if preference.JSONData == nil { - preference.JSONData = &pref.PreferenceJSONData{} - } - if cmd.Navbar.SavedItems != nil { - preference.JSONData.Navbar.SavedItems = cmd.Navbar.SavedItems - } - } - if exists { err = s.store.Update(ctx, preference) } else { diff --git a/pkg/services/preference/prefimpl/pref_test.go b/pkg/services/preference/prefimpl/pref_test.go index 0f5868b0117..9463901ce7f 100644 --- a/pkg/services/preference/prefimpl/pref_test.go +++ b/pkg/services/preference/prefimpl/pref_test.go @@ -174,51 +174,15 @@ func TestGetDefaults_JSONData(t *testing.T) { queryPreference := pref.QueryHistoryPreference{ HomeTab: "hometab", } - userNavbarPreferences := pref.NavbarPreference{ - SavedItems: []pref.NavLink{{ - ID: "explore", - Text: "Explore", - Url: "/explore", - }}, - } - orgNavbarPreferences := pref.NavbarPreference{ - SavedItems: []pref.NavLink{{ - ID: "alerting", - Text: "Alerting", - Url: "/alerting", - }}, - } - team1NavbarPreferences := pref.NavbarPreference{ - SavedItems: []pref.NavLink{{ - ID: "dashboards", - Text: "Dashboards", - Url: "/dashboards", - }}, - } - team2NavbarPreferences := pref.NavbarPreference{ - SavedItems: []pref.NavLink{{ - ID: "home", - Text: "Home", - Url: "/home", - }}, - } userPreferencesJsonData := pref.PreferenceJSONData{ - Navbar: userNavbarPreferences, QueryHistory: queryPreference, } - orgPreferencesJsonData := pref.PreferenceJSONData{ - Navbar: orgNavbarPreferences, - } + orgPreferencesJsonData := pref.PreferenceJSONData{} orgPreferencesWithLanguageJsonData := pref.PreferenceJSONData{ - Navbar: orgNavbarPreferences, Language: "en-GB", } - team2PreferencesJsonData := pref.PreferenceJSONData{ - Navbar: team2NavbarPreferences, - } - team1PreferencesJsonData := pref.PreferenceJSONData{ - Navbar: team1NavbarPreferences, - } + team2PreferencesJsonData := pref.PreferenceJSONData{} + team1PreferencesJsonData := pref.PreferenceJSONData{} t.Run("users have precedence over org", func(t *testing.T) { prefService := &Service{ @@ -274,7 +238,6 @@ func TestGetDefaults_JSONData(t *testing.T) { WeekStart: &weekStart, JSONData: &pref.PreferenceJSONData{ Language: "en-GB", - Navbar: userNavbarPreferences, QueryHistory: queryPreference, }, }, preference) diff --git a/pkg/services/preference/prefimpl/store_test.go b/pkg/services/preference/prefimpl/store_test.go index 0773c1c7134..43d56d4c97f 100644 --- a/pkg/services/preference/prefimpl/store_test.go +++ b/pkg/services/preference/prefimpl/store_test.go @@ -20,13 +20,6 @@ func testIntegrationPreferencesDataAccess(t *testing.T, fn getStore) { weekStartOne := "1" ss := db.InitTestDB(t) prefStore := fn(ss) - orgNavbarPreferences := pref.NavbarPreference{ - SavedItems: []pref.NavLink{{ - ID: "alerting", - Text: "Alerting", - Url: "/alerting", - }}, - } t.Run("Get with saved org and user home dashboard returns not found", func(t *testing.T) { query := &pref.Preference{OrgID: 1, UserID: 1, TeamID: 2} @@ -124,7 +117,7 @@ func testIntegrationPreferencesDataAccess(t *testing.T, fn getStore) { Timezone: "browser", HomeDashboardID: 5, WeekStart: &weekStartOne, - JSONData: &pref.PreferenceJSONData{Navbar: orgNavbarPreferences}, + JSONData: &pref.PreferenceJSONData{}, Created: time.Now(), Updated: time.Now(), }) diff --git a/pkg/services/store/entity/models.go b/pkg/services/store/entity/models.go index a4c7388388f..9f5ea100e19 100644 --- a/pkg/services/store/entity/models.go +++ b/pkg/services/store/entity/models.go @@ -4,13 +4,16 @@ package entity // NOTE: the object store is in heavy development, and the locations will likely continue to move //----------------------------------------------------------------------------------------------------- -import "context" +import ( + "context" +) const ( - StandardKindDashboard = "dashboard" - StandardKindPlaylist = "playlist" - StandardKindSnapshot = "snapshot" - StandardKindFolder = "folder" + StandardKindDashboard = "dashboard" + StandardKindPlaylist = "playlist" + StandardKindSnapshot = "snapshot" + StandardKindFolder = "folder" + StandardKindPreferences = "preferences" // StandardKindDataSource: not a real kind yet, but used to define references from dashboards // Types: influx, prometheus, testdata, ... diff --git a/pkg/services/store/kind/preferences/summary.go b/pkg/services/store/kind/preferences/summary.go new file mode 100644 index 00000000000..1efdae01633 --- /dev/null +++ b/pkg/services/store/kind/preferences/summary.go @@ -0,0 +1,54 @@ +package preferences + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/grafana/grafana/pkg/kinds/preferences" + "github.com/grafana/grafana/pkg/services/store/entity" +) + +func GetEntityKindInfo() entity.EntityKindInfo { + return entity.EntityKindInfo{ + ID: entity.StandardKindPreferences, + Name: "Preferences", + } +} + +func GetEntitySummaryBuilder() entity.EntitySummaryBuilder { + return func(ctx context.Context, uid string, body []byte) (*entity.EntitySummary, []byte, error) { + if uid != "default" { + parts := strings.Split(uid, "-") + if len(parts) != 2 { + return nil, nil, fmt.Errorf("expecting UID: default, user-{#}, or team-{#}") + } + if !(parts[0] == "team" || parts[0] == "user") { + return nil, nil, fmt.Errorf("expecting UID: default, user-{#}, or team-{#}") + } + } + + obj := &preferences.Preferences{} + err := json.Unmarshal(body, obj) + if err != nil { + return nil, nil, err // unable to read object + } + + summary := &entity.EntitySummary{ + Kind: entity.StandardKindPreferences, + Name: uid, // team-${id} | user-${id} + UID: uid, + } + + if obj.HomeDashboardUID != nil && *obj.HomeDashboardUID != "" { + summary.References = append(summary.References, &entity.EntityExternalReference{ + Kind: entity.StandardKindDashboard, + UID: *obj.HomeDashboardUID, + }) + } + + out, err := json.MarshalIndent(obj, "", " ") + return summary, out, err + } +} diff --git a/pkg/services/store/kind/registry.go b/pkg/services/store/kind/registry.go index d977511ea4c..f720c68d452 100644 --- a/pkg/services/store/kind/registry.go +++ b/pkg/services/store/kind/registry.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/store/kind/jsonobj" "github.com/grafana/grafana/pkg/services/store/kind/playlist" "github.com/grafana/grafana/pkg/services/store/kind/png" + "github.com/grafana/grafana/pkg/services/store/kind/preferences" "github.com/grafana/grafana/pkg/services/store/kind/snapshot" "github.com/grafana/grafana/pkg/services/store/kind/svg" "github.com/grafana/grafana/pkg/setting" @@ -61,6 +62,10 @@ func NewKindRegistry() KindRegistry { info: jsonobj.GetEntityKindInfo(), builder: jsonobj.GetEntitySummaryBuilder(), } + kinds[entity.StandardKindPreferences] = &kindValues{ + info: preferences.GetEntityKindInfo(), + builder: preferences.GetEntitySummaryBuilder(), + } // create a registry reg := ®istry{ diff --git a/pkg/services/store/kind/registry_test.go b/pkg/services/store/kind/registry_test.go index 419b029e64e..9443edc1263 100644 --- a/pkg/services/store/kind/registry_test.go +++ b/pkg/services/store/kind/registry_test.go @@ -26,6 +26,7 @@ func TestKindRegistry(t *testing.T) { "jsonobj", "playlist", "png", + "preferences", "snapshot", "test", }, ids) diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx index e6b4fc69fcc..a1ea4c4ff0d 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx @@ -5,7 +5,7 @@ import TestProvider from 'test/helpers/TestProvider'; import { assertInstanceOf } from 'test/helpers/asserts'; import { getSelectParent, selectOptionInTest } from 'test/helpers/selectOptionInTest'; -import { UserPreferencesDTO } from 'app/types'; +import { Preferences as UserPreferencesDTO } from '@grafana/schema/src/raw/preferences/x/preferences_types.gen'; import SharedPreferences from './SharedPreferences'; diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index 5a6486e250d..73b7ee09290 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -4,6 +4,7 @@ import React, { PureComponent } from 'react'; import { FeatureState, SelectableValue } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { config, reportInteraction } from '@grafana/runtime'; +import { Preferences as UserPreferencesDTO } from '@grafana/schema/src/raw/preferences/x/preferences_types.gen'; import { Button, Field, @@ -21,7 +22,6 @@ import { DashboardPicker } from 'app/core/components/Select/DashboardPicker'; import { t, Trans } from 'app/core/internationalization'; import { LANGUAGES } from 'app/core/internationalization/constants'; import { PreferencesService } from 'app/core/services/PreferencesService'; -import { UserPreferencesDTO } from 'app/types'; export interface Props { resourceUri: string; @@ -130,6 +130,10 @@ export class SharedPreferences extends PureComponent { const { disabled } = this.props; const styles = getStyles(); const languages = getLanguageOptions(); + let currentThemeOption = this.themeOptions[0].value; + if (theme?.length) { + currentThemeOption = this.themeOptions.find((item) => item.value === theme)?.value; + } return (
@@ -139,7 +143,7 @@ export class SharedPreferences extends PureComponent { item.value === theme)?.value} + value={currentThemeOption} onChange={this.onThemeChanged} /> @@ -181,7 +185,7 @@ export class SharedPreferences extends PureComponent { data-testid={selectors.components.WeekStartPicker.containerV2} > diff --git a/public/app/core/history/RichHistoryRemoteStorage.test.ts b/public/app/core/history/RichHistoryRemoteStorage.test.ts index e01781b9c3a..2e70202c5f6 100644 --- a/public/app/core/history/RichHistoryRemoteStorage.test.ts +++ b/public/app/core/history/RichHistoryRemoteStorage.test.ts @@ -1,7 +1,9 @@ import { of } from 'rxjs'; +import { Preferences as UserPreferencesDTO } from '@grafana/schema/src/raw/preferences/x/preferences_types.gen'; + import { DatasourceSrv } from '../../features/plugins/datasource_srv'; -import { RichHistoryQuery, UserPreferencesDTO } from '../../types'; +import { RichHistoryQuery } from '../../types'; import { SortOrder } from '../utils/richHistoryTypes'; import RichHistoryRemoteStorage, { RichHistoryRemoteStorageDTO } from './RichHistoryRemoteStorage'; diff --git a/public/app/core/services/PreferencesService.ts b/public/app/core/services/PreferencesService.ts index fe431964725..ea636f7daea 100644 --- a/public/app/core/services/PreferencesService.ts +++ b/public/app/core/services/PreferencesService.ts @@ -1,4 +1,4 @@ -import { UserPreferencesDTO } from 'app/types'; +import { Preferences as UserPreferencesDTO } from '@grafana/schema/src/raw/preferences/x/preferences_types.gen'; import { backendSrv } from './backend_srv'; diff --git a/public/app/types/index.ts b/public/app/types/index.ts index ec74cb8539e..830fb6cbea1 100644 --- a/public/app/types/index.ts +++ b/public/app/types/index.ts @@ -16,7 +16,6 @@ export * from './store'; export * from './ldap'; export * from './appEvent'; export * from './query'; -export * from './preferences'; export * from './accessControl'; export * from './supportBundles'; diff --git a/public/app/types/preferences.ts b/public/app/types/preferences.ts deleted file mode 100644 index c6b37f94fad..00000000000 --- a/public/app/types/preferences.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { TimeZone } from '@grafana/data'; - -export interface UserPreferencesDTO { - timezone: TimeZone; - weekStart: string; - language: string; - // It is undefined when there is not dashboard assigned (default) - homeDashboardUID?: string; - theme: string; - queryHistory: { - homeTab: '' | 'query' | 'starred'; - }; -}