diff --git a/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go b/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go new file mode 100644 index 0000000000000..ff22a06073308 --- /dev/null +++ b/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go @@ -0,0 +1,240 @@ +// Copyright 2023 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: teleport/userpreferences/v1/cluster_preferences.proto + +package userpreferencesv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// PinnedResourcesUserPreferences is a collection of resource IDs that will be +// displayed in the user's pinned resources tab in the Web UI. +type PinnedResourcesUserPreferences struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // resource_ids is a list of unified resource name sort keys. + ResourceIds []string `protobuf:"bytes,1,rep,name=resource_ids,json=resourceIds,proto3" json:"resource_ids,omitempty"` +} + +func (x *PinnedResourcesUserPreferences) Reset() { + *x = PinnedResourcesUserPreferences{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PinnedResourcesUserPreferences) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PinnedResourcesUserPreferences) ProtoMessage() {} + +func (x *PinnedResourcesUserPreferences) ProtoReflect() protoreflect.Message { + mi := &file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PinnedResourcesUserPreferences.ProtoReflect.Descriptor instead. +func (*PinnedResourcesUserPreferences) Descriptor() ([]byte, []int) { + return file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescGZIP(), []int{0} +} + +func (x *PinnedResourcesUserPreferences) GetResourceIds() []string { + if x != nil { + return x.ResourceIds + } + return nil +} + +// ClusterUserPreferences are user preferences saved per cluster. +type ClusterUserPreferences struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // pinned_resources is a list of pinned resources. + PinnedResources *PinnedResourcesUserPreferences `protobuf:"bytes,1,opt,name=pinned_resources,json=pinnedResources,proto3" json:"pinned_resources,omitempty"` +} + +func (x *ClusterUserPreferences) Reset() { + *x = ClusterUserPreferences{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClusterUserPreferences) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClusterUserPreferences) ProtoMessage() {} + +func (x *ClusterUserPreferences) ProtoReflect() protoreflect.Message { + mi := &file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClusterUserPreferences.ProtoReflect.Descriptor instead. +func (*ClusterUserPreferences) Descriptor() ([]byte, []int) { + return file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescGZIP(), []int{1} +} + +func (x *ClusterUserPreferences) GetPinnedResources() *PinnedResourcesUserPreferences { + if x != nil { + return x.PinnedResources + } + return nil +} + +var File_teleport_userpreferences_v1_cluster_preferences_proto protoreflect.FileDescriptor + +var file_teleport_userpreferences_v1_cluster_preferences_proto_rawDesc = []byte{ + 0x0a, 0x35, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x22, 0x43, 0x0a, 0x1e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x73, 0x22, 0x80, 0x01, 0x0a, 0x16, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x12, 0x66, 0x0a, 0x10, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x6e, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x55, 0x73, 0x65, 0x72, + 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x0f, 0x70, 0x69, 0x6e, + 0x6e, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x42, 0x59, 0x5a, 0x57, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x67, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescOnce sync.Once + file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescData = file_teleport_userpreferences_v1_cluster_preferences_proto_rawDesc +) + +func file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescGZIP() []byte { + file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescOnce.Do(func() { + file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescData = protoimpl.X.CompressGZIP(file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescData) + }) + return file_teleport_userpreferences_v1_cluster_preferences_proto_rawDescData +} + +var file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_teleport_userpreferences_v1_cluster_preferences_proto_goTypes = []interface{}{ + (*PinnedResourcesUserPreferences)(nil), // 0: teleport.userpreferences.v1.PinnedResourcesUserPreferences + (*ClusterUserPreferences)(nil), // 1: teleport.userpreferences.v1.ClusterUserPreferences +} +var file_teleport_userpreferences_v1_cluster_preferences_proto_depIdxs = []int32{ + 0, // 0: teleport.userpreferences.v1.ClusterUserPreferences.pinned_resources:type_name -> teleport.userpreferences.v1.PinnedResourcesUserPreferences + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_teleport_userpreferences_v1_cluster_preferences_proto_init() } +func file_teleport_userpreferences_v1_cluster_preferences_proto_init() { + if File_teleport_userpreferences_v1_cluster_preferences_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinnedResourcesUserPreferences); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClusterUserPreferences); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_teleport_userpreferences_v1_cluster_preferences_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_teleport_userpreferences_v1_cluster_preferences_proto_goTypes, + DependencyIndexes: file_teleport_userpreferences_v1_cluster_preferences_proto_depIdxs, + MessageInfos: file_teleport_userpreferences_v1_cluster_preferences_proto_msgTypes, + }.Build() + File_teleport_userpreferences_v1_cluster_preferences_proto = out.File + file_teleport_userpreferences_v1_cluster_preferences_proto_rawDesc = nil + file_teleport_userpreferences_v1_cluster_preferences_proto_goTypes = nil + file_teleport_userpreferences_v1_cluster_preferences_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go b/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go index 85f08816262a8..49635d3d8e266 100644 --- a/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go +++ b/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go @@ -47,6 +47,8 @@ type UserPreferences struct { Theme Theme `protobuf:"varint,2,opt,name=theme,proto3,enum=teleport.userpreferences.v1.Theme" json:"theme,omitempty"` // onboard is the preferences from the onboarding questionnaire. Onboard *OnboardUserPreferences `protobuf:"bytes,3,opt,name=onboard,proto3" json:"onboard,omitempty"` + // cluster_preferences are user preferences saved per cluster. + ClusterPreferences *ClusterUserPreferences `protobuf:"bytes,4,opt,name=cluster_preferences,json=clusterPreferences,proto3" json:"cluster_preferences,omitempty"` } func (x *UserPreferences) Reset() { @@ -102,6 +104,13 @@ func (x *UserPreferences) GetOnboard() *OnboardUserPreferences { return nil } +func (x *UserPreferences) GetClusterPreferences() *ClusterUserPreferences { + if x != nil { + return x.ClusterPreferences + } + return nil +} + // GetUserPreferencesRequest is a request to get the user preferences. type GetUserPreferencesRequest struct { state protoimpl.MessageState @@ -251,68 +260,77 @@ var file_teleport_userpreferences_v1_userpreferences_proto_rawDesc = []byte{ 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x73, 0x73, 0x69, 0x73, - 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x29, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x35, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x27, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, - 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, - 0x74, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe6, 0x01, 0x0a, 0x0f, - 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, - 0x4a, 0x0a, 0x06, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, - 0x73, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x73, 0x52, 0x06, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x05, 0x74, - 0x68, 0x65, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x05, - 0x74, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x07, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x29, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xcc, 0x02, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x06, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x55, 0x73, 0x65, 0x72, - 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x07, 0x6f, 0x6e, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x22, 0x2b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x22, 0x6c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4e, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, - 0x7e, 0x0a, 0x1c, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x4e, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x4a, - 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, - 0x8c, 0x02, 0x0a, 0x16, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x12, 0x47, - 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x73, 0x12, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x06, 0x61, 0x73, 0x73, 0x69, + 0x73, 0x74, 0x12, 0x38, 0x0a, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x07, + 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x52, 0x07, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x64, 0x0a, 0x13, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x12, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x22, 0x2b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4a, 0x04, + 0x08, 0x01, 0x10, 0x02, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x6c, + 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0b, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, + 0x0b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x7e, 0x0a, 0x1c, + 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0b, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x15, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x39, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x59, - 0x5a, 0x57, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x0b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x02, + 0x10, 0x03, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0x8c, 0x02, 0x0a, + 0x16, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x36, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x6a, 0x0a, 0x15, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x59, 0x5a, 0x57, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, + 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -336,23 +354,25 @@ var file_teleport_userpreferences_v1_userpreferences_proto_goTypes = []interface (*AssistUserPreferences)(nil), // 4: teleport.userpreferences.v1.AssistUserPreferences (Theme)(0), // 5: teleport.userpreferences.v1.Theme (*OnboardUserPreferences)(nil), // 6: teleport.userpreferences.v1.OnboardUserPreferences - (*emptypb.Empty)(nil), // 7: google.protobuf.Empty + (*ClusterUserPreferences)(nil), // 7: teleport.userpreferences.v1.ClusterUserPreferences + (*emptypb.Empty)(nil), // 8: google.protobuf.Empty } var file_teleport_userpreferences_v1_userpreferences_proto_depIdxs = []int32{ 4, // 0: teleport.userpreferences.v1.UserPreferences.assist:type_name -> teleport.userpreferences.v1.AssistUserPreferences 5, // 1: teleport.userpreferences.v1.UserPreferences.theme:type_name -> teleport.userpreferences.v1.Theme 6, // 2: teleport.userpreferences.v1.UserPreferences.onboard:type_name -> teleport.userpreferences.v1.OnboardUserPreferences - 0, // 3: teleport.userpreferences.v1.GetUserPreferencesResponse.preferences:type_name -> teleport.userpreferences.v1.UserPreferences - 0, // 4: teleport.userpreferences.v1.UpsertUserPreferencesRequest.preferences:type_name -> teleport.userpreferences.v1.UserPreferences - 1, // 5: teleport.userpreferences.v1.UserPreferencesService.GetUserPreferences:input_type -> teleport.userpreferences.v1.GetUserPreferencesRequest - 3, // 6: teleport.userpreferences.v1.UserPreferencesService.UpsertUserPreferences:input_type -> teleport.userpreferences.v1.UpsertUserPreferencesRequest - 2, // 7: teleport.userpreferences.v1.UserPreferencesService.GetUserPreferences:output_type -> teleport.userpreferences.v1.GetUserPreferencesResponse - 7, // 8: teleport.userpreferences.v1.UserPreferencesService.UpsertUserPreferences:output_type -> google.protobuf.Empty - 7, // [7:9] is the sub-list for method output_type - 5, // [5:7] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 7, // 3: teleport.userpreferences.v1.UserPreferences.cluster_preferences:type_name -> teleport.userpreferences.v1.ClusterUserPreferences + 0, // 4: teleport.userpreferences.v1.GetUserPreferencesResponse.preferences:type_name -> teleport.userpreferences.v1.UserPreferences + 0, // 5: teleport.userpreferences.v1.UpsertUserPreferencesRequest.preferences:type_name -> teleport.userpreferences.v1.UserPreferences + 1, // 6: teleport.userpreferences.v1.UserPreferencesService.GetUserPreferences:input_type -> teleport.userpreferences.v1.GetUserPreferencesRequest + 3, // 7: teleport.userpreferences.v1.UserPreferencesService.UpsertUserPreferences:input_type -> teleport.userpreferences.v1.UpsertUserPreferencesRequest + 2, // 8: teleport.userpreferences.v1.UserPreferencesService.GetUserPreferences:output_type -> teleport.userpreferences.v1.GetUserPreferencesResponse + 8, // 9: teleport.userpreferences.v1.UserPreferencesService.UpsertUserPreferences:output_type -> google.protobuf.Empty + 8, // [8:10] is the sub-list for method output_type + 6, // [6:8] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_teleport_userpreferences_v1_userpreferences_proto_init() } @@ -361,6 +381,7 @@ func file_teleport_userpreferences_v1_userpreferences_proto_init() { return } file_teleport_userpreferences_v1_assist_proto_init() + file_teleport_userpreferences_v1_cluster_preferences_proto_init() file_teleport_userpreferences_v1_onboard_proto_init() file_teleport_userpreferences_v1_theme_proto_init() if !protoimpl.UnsafeEnabled { diff --git a/api/proto/teleport/userpreferences/v1/cluster_preferences.proto b/api/proto/teleport/userpreferences/v1/cluster_preferences.proto new file mode 100644 index 0000000000000..cd9d6cc1b7d64 --- /dev/null +++ b/api/proto/teleport/userpreferences/v1/cluster_preferences.proto @@ -0,0 +1,32 @@ +// Copyright 2023 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package teleport.userpreferences.v1; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1;userpreferencesv1"; + +// PinnedResourcesUserPreferences is a collection of resource IDs that will be +// displayed in the user's pinned resources tab in the Web UI. +message PinnedResourcesUserPreferences { + // resource_ids is a list of unified resource name sort keys. + repeated string resource_ids = 1; +} + +// ClusterUserPreferences are user preferences saved per cluster. +message ClusterUserPreferences { + // pinned_resources is a list of pinned resources. + PinnedResourcesUserPreferences pinned_resources = 1; +} diff --git a/api/proto/teleport/userpreferences/v1/userpreferences.proto b/api/proto/teleport/userpreferences/v1/userpreferences.proto index 229a768f444c7..452121b654273 100644 --- a/api/proto/teleport/userpreferences/v1/userpreferences.proto +++ b/api/proto/teleport/userpreferences/v1/userpreferences.proto @@ -18,6 +18,7 @@ package teleport.userpreferences.v1; import "google/protobuf/empty.proto"; import "teleport/userpreferences/v1/assist.proto"; +import "teleport/userpreferences/v1/cluster_preferences.proto"; import "teleport/userpreferences/v1/onboard.proto"; import "teleport/userpreferences/v1/theme.proto"; @@ -31,6 +32,8 @@ message UserPreferences { Theme theme = 2; // onboard is the preferences from the onboarding questionnaire. v1.OnboardUserPreferences onboard = 3; + // cluster_preferences are user preferences saved per cluster. + v1.ClusterUserPreferences cluster_preferences = 4; } // GetUserPreferencesRequest is a request to get the user preferences. diff --git a/lib/auth/userpreferences/userpreferencesv1/service.go b/lib/auth/userpreferences/userpreferencesv1/service.go index 37393f0c770ad..e09ca4d885714 100644 --- a/lib/auth/userpreferences/userpreferencesv1/service.go +++ b/lib/auth/userpreferences/userpreferencesv1/service.go @@ -70,10 +70,6 @@ func (a *Service) GetUserPreferences(ctx context.Context, _ *userpreferences.Get return nil, trace.Wrap(err) } - if !authz.IsLocalUser(*authCtx) { - return nil, trace.AccessDenied("Non-local user cannot get user preferences") - } - username := authCtx.User.GetName() prefs, err := a.backend.GetUserPreferences(ctx, username) @@ -92,9 +88,6 @@ func (a *Service) UpsertUserPreferences(ctx context.Context, req *userpreference if err != nil { return nil, trace.Wrap(err) } - if !authz.IsLocalUser(*authCtx) { - return nil, trace.AccessDenied("Non-local user cannot upsert user preferences") - } username := authCtx.User.GetName() diff --git a/lib/auth/userpreferences/userpreferencesv1/service_test.go b/lib/auth/userpreferences/userpreferencesv1/service_test.go index 2fb1b2e627c51..1b943a978f76c 100644 --- a/lib/auth/userpreferences/userpreferencesv1/service_test.go +++ b/lib/auth/userpreferences/userpreferencesv1/service_test.go @@ -62,6 +62,9 @@ func TestService_GetUserPreferences(t *testing.T) { PreferredResources: []userpreferencesv1.Resource{}, MarketingParams: &userpreferencesv1.MarketingParams{}, }, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{}, + }, }, }, wantErr: assert.NoError, @@ -101,6 +104,11 @@ func TestService_UpsertUserPreferences(t *testing.T) { Onboard: &userpreferencesv1.OnboardUserPreferences{ PreferredResources: []userpreferencesv1.Resource{}, }, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: []string{"node1", "node2"}, + }, + }, } tests := []struct { diff --git a/lib/services/local/userpreferences.go b/lib/services/local/userpreferences.go index 45053e9d61a90..75a1777ca9d21 100644 --- a/lib/services/local/userpreferences.go +++ b/lib/services/local/userpreferences.go @@ -45,6 +45,9 @@ func DefaultUserPreferences() *userpreferencesv1.UserPreferences { PreferredResources: []userpreferencesv1.Resource{}, MarketingParams: &userpreferencesv1.MarketingParams{}, }, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{}, + }, } } @@ -78,19 +81,7 @@ func (u *UserPreferencesService) UpsertUserPreferences(ctx context.Context, user return trace.Wrap(err) } - preferences, err := u.getUserPreferences(ctx, username) - if err != nil { - if !trace.IsNotFound(err) { - return trace.Wrap(err) - } - preferences = DefaultUserPreferences() - } - - if err := overwriteValues(preferences, prefs); err != nil { - return trace.Wrap(err) - } - - item, err := createBackendItem(username, preferences) + item, err := createBackendItem(username, prefs) if err != nil { return trace.Wrap(err) } diff --git a/lib/services/local/userpreferences_test.go b/lib/services/local/userpreferences_test.go index 2794eabeee0c5..965035ceae650 100644 --- a/lib/services/local/userpreferences_test.go +++ b/lib/services/local/userpreferences_test.go @@ -43,6 +43,37 @@ func newUserPreferencesService(t *testing.T) *local.UserPreferencesService { return local.NewUserPreferencesService(backend) } +func TestUserPreferences_ClusterPreferences(t *testing.T) { + t.Parallel() + + ctx := context.Background() + defaultPref := local.DefaultUserPreferences() + defaultPref.ClusterPreferences = &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: []string{"123", "234"}, + }, + } + + username := "something" + identity := newUserPreferencesService(t) + + err := identity.UpsertUserPreferences(ctx, username, defaultPref) + require.NoError(t, err) + + res, err := identity.GetUserPreferences(ctx, username) + require.NoError(t, err) + + require.Empty(t, cmp.Diff(defaultPref, res, protocmp.Transform())) + + // send empty preferences, cluster prefs should be overwritten + reqPrefs := local.DefaultUserPreferences() + err = identity.UpsertUserPreferences(ctx, username, reqPrefs) + require.NoError(t, err) + res, err = identity.GetUserPreferences(ctx, username) + require.NoError(t, err) + require.Empty(t, cmp.Diff(reqPrefs, res, protocmp.Transform())) +} + func TestUserPreferencesCRUD(t *testing.T) { t.Parallel() @@ -68,9 +99,10 @@ func TestUserPreferencesCRUD(t *testing.T) { }, }, expected: &userpreferencesv1.UserPreferences{ - Assist: defaultPref.Assist, - Onboard: defaultPref.Onboard, - Theme: userpreferencesv1.Theme_THEME_DARK, + Assist: defaultPref.Assist, + Onboard: defaultPref.Onboard, + Theme: userpreferencesv1.Theme_THEME_DARK, + ClusterPreferences: defaultPref.ClusterPreferences, }, }, { @@ -93,6 +125,7 @@ func TestUserPreferencesCRUD(t *testing.T) { PreferredLogins: []string{"foo", "bar"}, ViewMode: defaultPref.Assist.ViewMode, }, + ClusterPreferences: defaultPref.ClusterPreferences, }, }, { @@ -111,6 +144,7 @@ func TestUserPreferencesCRUD(t *testing.T) { PreferredLogins: defaultPref.Assist.PreferredLogins, ViewMode: userpreferencesv1.AssistViewMode_ASSIST_VIEW_MODE_POPUP_EXPANDED_SIDEBAR_VISIBLE, }, + ClusterPreferences: defaultPref.ClusterPreferences, }, }, { @@ -140,6 +174,29 @@ func TestUserPreferencesCRUD(t *testing.T) { Intent: "i_1", }, }, + ClusterPreferences: defaultPref.ClusterPreferences, + }, + }, + { + name: "update cluster preference only", + req: &userpreferencesv1.UpsertUserPreferencesRequest{ + Preferences: &userpreferencesv1.UserPreferences{ + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: []string{"node1", "node2"}, + }, + }, + }, + }, + expected: &userpreferencesv1.UserPreferences{ + Assist: defaultPref.Assist, + Theme: defaultPref.Theme, + Onboard: defaultPref.Onboard, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: []string{"node1", "node2"}, + }, + }, }, }, { @@ -160,6 +217,11 @@ func TestUserPreferencesCRUD(t *testing.T) { Intent: "i_2", }, }, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: []string{"node1", "node2"}, + }, + }, }, }, expected: &userpreferencesv1.UserPreferences{ @@ -177,6 +239,11 @@ func TestUserPreferencesCRUD(t *testing.T) { Intent: "i_2", }, }, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: []string{"node1", "node2"}, + }, + }, }, }, } diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index ecccb1af0a23d..830bda5893efe 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -861,6 +861,12 @@ func (h *Handler) bindDefaultEndpoints() { // Updates the user's preferences h.PUT("/webapi/user/preferences", h.WithAuth(h.updateUserPreferences)) + + // Fetches the user's cluster preferences. + h.GET("/webapi/user/preferences/:site", h.WithClusterAuth(h.getUserClusterPreferences)) + + // Updates the user's cluster preferences. + h.PUT("/webapi/user/preferences/:site", h.WithClusterAuth(h.updateUserClusterPreferences)) } // GetProxyClient returns authenticated auth server client diff --git a/lib/web/userpreferences.go b/lib/web/userpreferences.go index ececb5af1e9ed..01611ac938b27 100644 --- a/lib/web/userpreferences.go +++ b/lib/web/userpreferences.go @@ -24,6 +24,7 @@ import ( userpreferencesv1 "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1" "github.com/gravitational/teleport/lib/httplib" + "github.com/gravitational/teleport/lib/reversetunnelclient" ) // AssistUserPreferencesResponse is the JSON response for the assist user preferences. @@ -44,16 +45,21 @@ type OnboardUserPreferencesResponse struct { MarketingParams preferencesMarketingParams `json:"marketingParams"` } +// ClusterUserPreferencesResponse is the JSON response for the user's cluster preferences. +type ClusterUserPreferencesResponse struct { + PinnedResources []string `json:"pinnedResources"` +} + // UserPreferencesResponse is the JSON response for the user preferences. type UserPreferencesResponse struct { - Assist AssistUserPreferencesResponse `json:"assist"` - Theme userpreferencesv1.Theme `json:"theme"` - Onboard OnboardUserPreferencesResponse `json:"onboard"` + Assist AssistUserPreferencesResponse `json:"assist"` + Theme userpreferencesv1.Theme `json:"theme"` + Onboard OnboardUserPreferencesResponse `json:"onboard"` + ClusterPreferences ClusterUserPreferencesResponse `json:"clusterPreferences,omitempty"` } -// getUserPreferences is a handler for GET /webapi/user/preferences -func (h *Handler) getUserPreferences(_ http.ResponseWriter, r *http.Request, _ httprouter.Params, sctx *SessionContext) (any, error) { - authClient, err := sctx.GetClient() +func (h *Handler) getUserClusterPreferences(_ http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { + authClient, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) } @@ -63,23 +69,48 @@ func (h *Handler) getUserPreferences(_ http.ResponseWriter, r *http.Request, _ h return nil, trace.Wrap(err) } - return userPreferencesResponse(resp.Preferences), nil + return resp.Preferences.ClusterPreferences, nil } -// updateUserPreferences is a handler for PUT /webapi/user/preferences. -func (h *Handler) updateUserPreferences(_ http.ResponseWriter, r *http.Request, _ httprouter.Params, sctx *SessionContext) (any, error) { +// updateUserClusterPreferences is a handler for PUT /webapi/user/preferences. +func (h *Handler) updateUserClusterPreferences(_ http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { req := UserPreferencesResponse{} if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) } + authClient, err := sctx.GetUserClient(r.Context(), site) + if err != nil { + return nil, trace.Wrap(err) + } + + preferences := makePreferenceRequest(req) + + if err := authClient.UpsertUserPreferences(r.Context(), preferences); err != nil { + return nil, trace.Wrap(err) + } + + return OK(), nil +} + +// getUserPreferences is a handler for GET /webapi/user/preferences. +func (h *Handler) getUserPreferences(_ http.ResponseWriter, r *http.Request, _ httprouter.Params, sctx *SessionContext) (any, error) { authClient, err := sctx.GetClient() if err != nil { return nil, trace.Wrap(err) } - preferences := &userpreferencesv1.UpsertUserPreferencesRequest{ + resp, err := authClient.GetUserPreferences(r.Context(), &userpreferencesv1.GetUserPreferencesRequest{}) + if err != nil { + return nil, trace.Wrap(err) + } + + return userPreferencesResponse(resp.Preferences), nil +} + +func makePreferenceRequest(req UserPreferencesResponse) *userpreferencesv1.UpsertUserPreferencesRequest { + return &userpreferencesv1.UpsertUserPreferencesRequest{ Preferences: &userpreferencesv1.UserPreferences{ Theme: req.Theme, Assist: &userpreferencesv1.AssistUserPreferences{ @@ -95,9 +126,29 @@ func (h *Handler) updateUserPreferences(_ http.ResponseWriter, r *http.Request, Intent: req.Onboard.MarketingParams.Intent, }, }, + ClusterPreferences: &userpreferencesv1.ClusterUserPreferences{ + PinnedResources: &userpreferencesv1.PinnedResourcesUserPreferences{ + ResourceIds: req.ClusterPreferences.PinnedResources, + }, + }, }, } +} + +// updateUserPreferences is a handler for PUT /webapi/user/preferences. +func (h *Handler) updateUserPreferences(_ http.ResponseWriter, r *http.Request, _ httprouter.Params, sctx *SessionContext) (any, error) { + var req UserPreferencesResponse + + if err := httplib.ReadJSON(r, &req); err != nil { + return nil, trace.Wrap(err) + } + + authClient, err := sctx.GetClient() + if err != nil { + return nil, trace.Wrap(err) + } + preferences := makePreferenceRequest(req) if err := authClient.UpsertUserPreferences(r.Context(), preferences); err != nil { return nil, trace.Wrap(err) } diff --git a/web/packages/teleport/src/config.ts b/web/packages/teleport/src/config.ts index b4623812a8ffa..8ca868eb7dc26 100644 --- a/web/packages/teleport/src/config.ts +++ b/web/packages/teleport/src/config.ts @@ -268,11 +268,18 @@ const cfg = { assistExecuteCommandWebSocketPath: 'wss://:hostname/v1/webapi/command/:clusterId/execute', userPreferencesPath: '/v1/webapi/user/preferences', + userClusterPreferencesPath: '/v1/webapi/user/preferences/:clusterId', // Assist needs some access request info to exist in OSS accessRequestPath: '/v1/enterprise/accessrequest/:requestId?', }, + getUserClusterPreferencesUrl(clusterId: string) { + return generatePath(cfg.api.userClusterPreferencesPath, { + clusterId, + }); + }, + getAppFqdnUrl(params: UrlAppParams) { return generatePath(cfg.api.appFqdnPath, { ...params }); }, diff --git a/web/packages/teleport/src/services/userPreferences/types.ts b/web/packages/teleport/src/services/userPreferences/types.ts index 9777e12fbcaa6..73b7ef59e4741 100644 --- a/web/packages/teleport/src/services/userPreferences/types.ts +++ b/web/packages/teleport/src/services/userPreferences/types.ts @@ -48,8 +48,17 @@ export interface UserPreferences { theme: ThemePreference; assist: AssistUserPreferences; onboard: OnboardUserPreferences; + clusterPreferences: UserClusterPreferences; } +// UserClusterPreferences are user preferences that are +// different per cluster. +export interface UserClusterPreferences { + // pinnedResources is an array of resource IDs. + pinnedResources: string[]; +} + +export type GetUserClusterPreferencesResponse = UserClusterPreferences; export type GetUserPreferencesResponse = UserPreferences; export function deprecatedThemeToThemePreference( diff --git a/web/packages/teleport/src/services/userPreferences/userPreferences.ts b/web/packages/teleport/src/services/userPreferences/userPreferences.ts index bbc6adab50703..eb7bd04c5103a 100644 --- a/web/packages/teleport/src/services/userPreferences/userPreferences.ts +++ b/web/packages/teleport/src/services/userPreferences/userPreferences.ts @@ -21,7 +21,9 @@ import { ViewMode } from 'teleport/Assist/types'; import { ThemePreference } from 'teleport/services/userPreferences/types'; import type { + GetUserClusterPreferencesResponse, GetUserPreferencesResponse, + UserClusterPreferences, UserPreferences, } from 'teleport/services/userPreferences/types'; @@ -33,6 +35,21 @@ export async function getUserPreferences() { return res; } +export async function getUserClusterPreferences(clusterId: string) { + const res: GetUserClusterPreferencesResponse = await api.get( + cfg.getUserClusterPreferencesUrl(clusterId) + ); + + return res; +} + +export function updateUserClusterPreferences( + clusterId: string, + preferences: Partial +) { + return api.put(cfg.getUserClusterPreferencesUrl(clusterId), preferences); +} + export function updateUserPreferences(preferences: Partial) { return api.put(cfg.api.userPreferencesPath, preferences); } @@ -53,5 +70,12 @@ export function makeDefaultUserPreferences(): UserPreferences { intent: '', }, }, + clusterPreferences: makeDefaultUserClusterPreferences(), + }; +} + +export function makeDefaultUserClusterPreferences(): UserClusterPreferences { + return { + pinnedResources: [], }; }