From 7a59c0693d9c826d3356d09f46fc66905bf04d3d Mon Sep 17 00:00:00 2001 From: AobaIwaki Date: Mon, 15 Dec 2025 02:10:04 +0900 Subject: [PATCH 1/3] chore(proto): add auto refresh settings --- proto/api/v1/instance_service.proto | 4 +++ proto/api/v1/user_service.proto | 2 ++ proto/gen/api/v1/activity_service.pb.go | 2 +- proto/gen/api/v1/attachment_service.pb.go | 2 +- proto/gen/api/v1/auth_service.pb.go | 2 +- proto/gen/api/v1/common.pb.go | 2 +- proto/gen/api/v1/idp_service.pb.go | 2 +- proto/gen/api/v1/instance_service.pb.go | 29 ++++++++++++++++--- proto/gen/api/v1/memo_service.pb.go | 2 +- proto/gen/api/v1/shortcut_service.pb.go | 2 +- proto/gen/api/v1/user_service.pb.go | 24 ++++++++++----- proto/gen/google/api/annotations.pb.go | 2 +- proto/gen/google/api/client.pb.go | 2 +- proto/gen/google/api/field_behavior.pb.go | 2 +- proto/gen/google/api/http.pb.go | 2 +- proto/gen/google/api/resource.pb.go | 2 +- proto/gen/store/activity.pb.go | 2 +- proto/gen/store/attachment.pb.go | 2 +- proto/gen/store/idp.pb.go | 2 +- proto/gen/store/inbox.pb.go | 2 +- proto/gen/store/instance_setting.pb.go | 27 +++++++++++++++-- proto/gen/store/memo.pb.go | 2 +- proto/gen/store/user_setting.pb.go | 22 ++++++++++---- proto/store/instance_setting.proto | 4 +++ proto/store/user_setting.proto | 2 ++ .../types/proto/api/v1/instance_service_pb.ts | 16 +++++++++- web/src/types/proto/api/v1/user_service_pb.ts | 9 +++++- 27 files changed, 134 insertions(+), 39 deletions(-) diff --git a/proto/api/v1/instance_service.proto b/proto/api/v1/instance_service.proto index 418f4e1ce..2d16835a5 100644 --- a/proto/api/v1/instance_service.proto +++ b/proto/api/v1/instance_service.proto @@ -102,6 +102,10 @@ message InstanceSetting { bool disallow_change_username = 8; // disallow_change_nickname disallows changing nickname. bool disallow_change_nickname = 9; + // enable_explore_auto_refresh enables auto-refresh on Explore page. Default: true. + bool enable_explore_auto_refresh = 10; + // min_auto_refresh_interval is the minimum auto-refresh interval in seconds. Default: 1. + int32 min_auto_refresh_interval = 11; // Custom profile configuration for instance branding. message CustomProfile { diff --git a/proto/api/v1/user_service.proto b/proto/api/v1/user_service.proto index 8eff1bebd..cdf01294c 100644 --- a/proto/api/v1/user_service.proto +++ b/proto/api/v1/user_service.proto @@ -416,6 +416,8 @@ message UserSetting { // This references a CSS file in the web/public/themes/ directory. // If not set, the default theme will be used. string theme = 4 [(google.api.field_behavior) = OPTIONAL]; + // Auto-refresh interval in seconds. 0 = disabled, default = 30. + int32 auto_refresh_interval = 5 [(google.api.field_behavior) = OPTIONAL]; } // User authentication sessions configuration. diff --git a/proto/gen/api/v1/activity_service.pb.go b/proto/gen/api/v1/activity_service.pb.go index 67824c087..a938f47a9 100644 --- a/proto/gen/api/v1/activity_service.pb.go +++ b/proto/gen/api/v1/activity_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/activity_service.proto diff --git a/proto/gen/api/v1/attachment_service.pb.go b/proto/gen/api/v1/attachment_service.pb.go index 65bdf6eb5..535bbb3bd 100644 --- a/proto/gen/api/v1/attachment_service.pb.go +++ b/proto/gen/api/v1/attachment_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/attachment_service.proto diff --git a/proto/gen/api/v1/auth_service.pb.go b/proto/gen/api/v1/auth_service.pb.go index 4753d5b98..7a2f58228 100644 --- a/proto/gen/api/v1/auth_service.pb.go +++ b/proto/gen/api/v1/auth_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/auth_service.proto diff --git a/proto/gen/api/v1/common.pb.go b/proto/gen/api/v1/common.pb.go index 20bfbedd5..0082d736a 100644 --- a/proto/gen/api/v1/common.pb.go +++ b/proto/gen/api/v1/common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/common.proto diff --git a/proto/gen/api/v1/idp_service.pb.go b/proto/gen/api/v1/idp_service.pb.go index 600219a00..1ed9c1128 100644 --- a/proto/gen/api/v1/idp_service.pb.go +++ b/proto/gen/api/v1/idp_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/idp_service.proto diff --git a/proto/gen/api/v1/instance_service.pb.go b/proto/gen/api/v1/instance_service.pb.go index 71b72df83..7fa289b9d 100644 --- a/proto/gen/api/v1/instance_service.pb.go +++ b/proto/gen/api/v1/instance_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/instance_service.proto @@ -478,6 +478,10 @@ type InstanceSetting_GeneralSetting struct { DisallowChangeUsername bool `protobuf:"varint,8,opt,name=disallow_change_username,json=disallowChangeUsername,proto3" json:"disallow_change_username,omitempty"` // disallow_change_nickname disallows changing nickname. DisallowChangeNickname bool `protobuf:"varint,9,opt,name=disallow_change_nickname,json=disallowChangeNickname,proto3" json:"disallow_change_nickname,omitempty"` + // enable_explore_auto_refresh enables auto-refresh on Explore page. Default: true. + EnableExploreAutoRefresh bool `protobuf:"varint,10,opt,name=enable_explore_auto_refresh,json=enableExploreAutoRefresh,proto3" json:"enable_explore_auto_refresh,omitempty"` + // min_auto_refresh_interval is the minimum auto-refresh interval in seconds. Default: 1. + MinAutoRefreshInterval int32 `protobuf:"varint,11,opt,name=min_auto_refresh_interval,json=minAutoRefreshInterval,proto3" json:"min_auto_refresh_interval,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -568,6 +572,20 @@ func (x *InstanceSetting_GeneralSetting) GetDisallowChangeNickname() bool { return false } +func (x *InstanceSetting_GeneralSetting) GetEnableExploreAutoRefresh() bool { + if x != nil { + return x.EnableExploreAutoRefresh + } + return false +} + +func (x *InstanceSetting_GeneralSetting) GetMinAutoRefreshInterval() int32 { + if x != nil { + return x.MinAutoRefreshInterval + } + return 0 +} + // Storage configuration settings for instance attachments. type InstanceSetting_StorageSetting struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -899,12 +917,12 @@ const file_api_v1_instance_service_proto_rawDesc = "" + "\aversion\x18\x02 \x01(\tR\aversion\x12\x12\n" + "\x04mode\x18\x03 \x01(\tR\x04mode\x12!\n" + "\finstance_url\x18\x06 \x01(\tR\vinstanceUrl\"\x1b\n" + - "\x19GetInstanceProfileRequest\"\xef\x0f\n" + + "\x19GetInstanceProfileRequest\"\xe9\x10\n" + "\x0fInstanceSetting\x12\x17\n" + "\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12W\n" + "\x0fgeneral_setting\x18\x02 \x01(\v2,.memos.api.v1.InstanceSetting.GeneralSettingH\x00R\x0egeneralSetting\x12W\n" + "\x0fstorage_setting\x18\x03 \x01(\v2,.memos.api.v1.InstanceSetting.StorageSettingH\x00R\x0estorageSetting\x12d\n" + - "\x14memo_related_setting\x18\x04 \x01(\v20.memos.api.v1.InstanceSetting.MemoRelatedSettingH\x00R\x12memoRelatedSetting\x1a\xca\x04\n" + + "\x14memo_related_setting\x18\x04 \x01(\v20.memos.api.v1.InstanceSetting.MemoRelatedSettingH\x00R\x12memoRelatedSetting\x1a\xc4\x05\n" + "\x0eGeneralSetting\x12<\n" + "\x1adisallow_user_registration\x18\x02 \x01(\bR\x18disallowUserRegistration\x124\n" + "\x16disallow_password_auth\x18\x03 \x01(\bR\x14disallowPasswordAuth\x12+\n" + @@ -913,7 +931,10 @@ const file_api_v1_instance_service_proto_rawDesc = "" + "\x0ecustom_profile\x18\x06 \x01(\v2:.memos.api.v1.InstanceSetting.GeneralSetting.CustomProfileR\rcustomProfile\x121\n" + "\x15week_start_day_offset\x18\a \x01(\x05R\x12weekStartDayOffset\x128\n" + "\x18disallow_change_username\x18\b \x01(\bR\x16disallowChangeUsername\x128\n" + - "\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\x1ab\n" + + "\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\x12=\n" + + "\x1benable_explore_auto_refresh\x18\n" + + " \x01(\bR\x18enableExploreAutoRefresh\x129\n" + + "\x19min_auto_refresh_interval\x18\v \x01(\x05R\x16minAutoRefreshInterval\x1ab\n" + "\rCustomProfile\x12\x14\n" + "\x05title\x18\x01 \x01(\tR\x05title\x12 \n" + "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" + diff --git a/proto/gen/api/v1/memo_service.pb.go b/proto/gen/api/v1/memo_service.pb.go index 1774d9253..2c8b65711 100644 --- a/proto/gen/api/v1/memo_service.pb.go +++ b/proto/gen/api/v1/memo_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/memo_service.proto diff --git a/proto/gen/api/v1/shortcut_service.pb.go b/proto/gen/api/v1/shortcut_service.pb.go index 1054cd2f2..708078b93 100644 --- a/proto/gen/api/v1/shortcut_service.pb.go +++ b/proto/gen/api/v1/shortcut_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/shortcut_service.proto diff --git a/proto/gen/api/v1/user_service.pb.go b/proto/gen/api/v1/user_service.pb.go index 0f08bb699..590e285a9 100644 --- a/proto/gen/api/v1/user_service.pb.go +++ b/proto/gen/api/v1/user_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: api/v1/user_service.proto @@ -2607,9 +2607,11 @@ type UserSetting_GeneralSetting struct { // The preferred theme of the user. // This references a CSS file in the web/public/themes/ directory. // If not set, the default theme will be used. - Theme string `protobuf:"bytes,4,opt,name=theme,proto3" json:"theme,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Theme string `protobuf:"bytes,4,opt,name=theme,proto3" json:"theme,omitempty"` + // Auto-refresh interval in seconds. 0 = disabled, default = 30. + AutoRefreshInterval int32 `protobuf:"varint,5,opt,name=auto_refresh_interval,json=autoRefreshInterval,proto3" json:"auto_refresh_interval,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *UserSetting_GeneralSetting) Reset() { @@ -2663,6 +2665,13 @@ func (x *UserSetting_GeneralSetting) GetTheme() string { return "" } +func (x *UserSetting_GeneralSetting) GetAutoRefreshInterval() int32 { + if x != nil { + return x.AutoRefreshInterval + } + return 0 +} + // User authentication sessions configuration. type UserSetting_SessionsSetting struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -2964,17 +2973,18 @@ const file_api_v1_user_service_proto_rawDesc = "" + "\x11memos.api.v1/UserR\x04name\"\x19\n" + "\x17ListAllUserStatsRequest\"I\n" + "\x18ListAllUserStatsResponse\x12-\n" + - "\x05stats\x18\x01 \x03(\v2\x17.memos.api.v1.UserStatsR\x05stats\"\xb3\a\n" + + "\x05stats\x18\x01 \x03(\v2\x17.memos.api.v1.UserStatsR\x05stats\"\xed\a\n" + "\vUserSetting\x12\x17\n" + "\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12S\n" + "\x0fgeneral_setting\x18\x02 \x01(\v2(.memos.api.v1.UserSetting.GeneralSettingH\x00R\x0egeneralSetting\x12V\n" + "\x10sessions_setting\x18\x03 \x01(\v2).memos.api.v1.UserSetting.SessionsSettingH\x00R\x0fsessionsSetting\x12c\n" + "\x15access_tokens_setting\x18\x04 \x01(\v2-.memos.api.v1.UserSetting.AccessTokensSettingH\x00R\x13accessTokensSetting\x12V\n" + - "\x10webhooks_setting\x18\x05 \x01(\v2).memos.api.v1.UserSetting.WebhooksSettingH\x00R\x0fwebhooksSetting\x1av\n" + + "\x10webhooks_setting\x18\x05 \x01(\v2).memos.api.v1.UserSetting.WebhooksSettingH\x00R\x0fwebhooksSetting\x1a\xaf\x01\n" + "\x0eGeneralSetting\x12\x1b\n" + "\x06locale\x18\x01 \x01(\tB\x03\xe0A\x01R\x06locale\x12,\n" + "\x0fmemo_visibility\x18\x03 \x01(\tB\x03\xe0A\x01R\x0ememoVisibility\x12\x19\n" + - "\x05theme\x18\x04 \x01(\tB\x03\xe0A\x01R\x05theme\x1aH\n" + + "\x05theme\x18\x04 \x01(\tB\x03\xe0A\x01R\x05theme\x127\n" + + "\x15auto_refresh_interval\x18\x05 \x01(\x05B\x03\xe0A\x01R\x13autoRefreshInterval\x1aH\n" + "\x0fSessionsSetting\x125\n" + "\bsessions\x18\x01 \x03(\v2\x19.memos.api.v1.UserSessionR\bsessions\x1aY\n" + "\x13AccessTokensSetting\x12B\n" + diff --git a/proto/gen/google/api/annotations.pb.go b/proto/gen/google/api/annotations.pb.go index e65a57cc7..bd05ec10e 100644 --- a/proto/gen/google/api/annotations.pb.go +++ b/proto/gen/google/api/annotations.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: google/api/annotations.proto diff --git a/proto/gen/google/api/client.pb.go b/proto/gen/google/api/client.pb.go index f73df28da..2e4c5455a 100644 --- a/proto/gen/google/api/client.pb.go +++ b/proto/gen/google/api/client.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: google/api/client.proto diff --git a/proto/gen/google/api/field_behavior.pb.go b/proto/gen/google/api/field_behavior.pb.go index f7d80d0e0..9f465d7c2 100644 --- a/proto/gen/google/api/field_behavior.pb.go +++ b/proto/gen/google/api/field_behavior.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: google/api/field_behavior.proto diff --git a/proto/gen/google/api/http.pb.go b/proto/gen/google/api/http.pb.go index 5d1bb59bd..7e5a548ef 100644 --- a/proto/gen/google/api/http.pb.go +++ b/proto/gen/google/api/http.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: google/api/http.proto diff --git a/proto/gen/google/api/resource.pb.go b/proto/gen/google/api/resource.pb.go index 2c9637ae7..ea6406c8e 100644 --- a/proto/gen/google/api/resource.pb.go +++ b/proto/gen/google/api/resource.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: google/api/resource.proto diff --git a/proto/gen/store/activity.pb.go b/proto/gen/store/activity.pb.go index ecce5aa4d..f0e03cbf2 100644 --- a/proto/gen/store/activity.pb.go +++ b/proto/gen/store/activity.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/activity.proto diff --git a/proto/gen/store/attachment.pb.go b/proto/gen/store/attachment.pb.go index 45c4b2918..1c734ec5a 100644 --- a/proto/gen/store/attachment.pb.go +++ b/proto/gen/store/attachment.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/attachment.proto diff --git a/proto/gen/store/idp.pb.go b/proto/gen/store/idp.pb.go index 1e4f43ad1..074fc9c04 100644 --- a/proto/gen/store/idp.pb.go +++ b/proto/gen/store/idp.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/idp.proto diff --git a/proto/gen/store/inbox.pb.go b/proto/gen/store/inbox.pb.go index f9b5c65ff..7bcc06d60 100644 --- a/proto/gen/store/inbox.pb.go +++ b/proto/gen/store/inbox.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/inbox.proto diff --git a/proto/gen/store/instance_setting.pb.go b/proto/gen/store/instance_setting.pb.go index f4e11402a..84746414b 100644 --- a/proto/gen/store/instance_setting.pb.go +++ b/proto/gen/store/instance_setting.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/instance_setting.proto @@ -331,6 +331,10 @@ type InstanceGeneralSetting struct { DisallowChangeUsername bool `protobuf:"varint,8,opt,name=disallow_change_username,json=disallowChangeUsername,proto3" json:"disallow_change_username,omitempty"` // disallow_change_nickname disallows changing nickname. DisallowChangeNickname bool `protobuf:"varint,9,opt,name=disallow_change_nickname,json=disallowChangeNickname,proto3" json:"disallow_change_nickname,omitempty"` + // enable_explore_auto_refresh enables auto-refresh on Explore page. Default: true. + EnableExploreAutoRefresh bool `protobuf:"varint,10,opt,name=enable_explore_auto_refresh,json=enableExploreAutoRefresh,proto3" json:"enable_explore_auto_refresh,omitempty"` + // min_auto_refresh_interval is the minimum auto-refresh interval in seconds. Default: 1. + MinAutoRefreshInterval int32 `protobuf:"varint,11,opt,name=min_auto_refresh_interval,json=minAutoRefreshInterval,proto3" json:"min_auto_refresh_interval,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -421,6 +425,20 @@ func (x *InstanceGeneralSetting) GetDisallowChangeNickname() bool { return false } +func (x *InstanceGeneralSetting) GetEnableExploreAutoRefresh() bool { + if x != nil { + return x.EnableExploreAutoRefresh + } + return false +} + +func (x *InstanceGeneralSetting) GetMinAutoRefreshInterval() int32 { + if x != nil { + return x.MinAutoRefreshInterval + } + return 0 +} + type InstanceCustomProfile struct { state protoimpl.MessageState `protogen:"open.v1"` Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` @@ -753,7 +771,7 @@ const file_store_instance_setting_proto_rawDesc = "" + "\x14InstanceBasicSetting\x12\x1d\n" + "\n" + "secret_key\x18\x01 \x01(\tR\tsecretKey\x12%\n" + - "\x0eschema_version\x18\x02 \x01(\tR\rschemaVersion\"\xd6\x03\n" + + "\x0eschema_version\x18\x02 \x01(\tR\rschemaVersion\"\xd0\x04\n" + "\x16InstanceGeneralSetting\x12<\n" + "\x1adisallow_user_registration\x18\x02 \x01(\bR\x18disallowUserRegistration\x124\n" + "\x16disallow_password_auth\x18\x03 \x01(\bR\x14disallowPasswordAuth\x12+\n" + @@ -762,7 +780,10 @@ const file_store_instance_setting_proto_rawDesc = "" + "\x0ecustom_profile\x18\x06 \x01(\v2\".memos.store.InstanceCustomProfileR\rcustomProfile\x121\n" + "\x15week_start_day_offset\x18\a \x01(\x05R\x12weekStartDayOffset\x128\n" + "\x18disallow_change_username\x18\b \x01(\bR\x16disallowChangeUsername\x128\n" + - "\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\"j\n" + + "\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\x12=\n" + + "\x1benable_explore_auto_refresh\x18\n" + + " \x01(\bR\x18enableExploreAutoRefresh\x129\n" + + "\x19min_auto_refresh_interval\x18\v \x01(\x05R\x16minAutoRefreshInterval\"j\n" + "\x15InstanceCustomProfile\x12\x14\n" + "\x05title\x18\x01 \x01(\tR\x05title\x12 \n" + "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" + diff --git a/proto/gen/store/memo.pb.go b/proto/gen/store/memo.pb.go index 816d0caab..270821e2d 100644 --- a/proto/gen/store/memo.pb.go +++ b/proto/gen/store/memo.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/memo.proto diff --git a/proto/gen/store/user_setting.pb.go b/proto/gen/store/user_setting.pb.go index 11b29ecd5..5b862f741 100644 --- a/proto/gen/store/user_setting.pb.go +++ b/proto/gen/store/user_setting.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: store/user_setting.proto @@ -239,9 +239,11 @@ type GeneralUserSetting struct { MemoVisibility string `protobuf:"bytes,2,opt,name=memo_visibility,json=memoVisibility,proto3" json:"memo_visibility,omitempty"` // The user's theme preference. // This references a CSS file in the web/public/themes/ directory. - Theme string `protobuf:"bytes,3,opt,name=theme,proto3" json:"theme,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Theme string `protobuf:"bytes,3,opt,name=theme,proto3" json:"theme,omitempty"` + // Auto-refresh interval in seconds. 0 = disabled, default = 30. + AutoRefreshInterval int32 `protobuf:"varint,4,opt,name=auto_refresh_interval,json=autoRefreshInterval,proto3" json:"auto_refresh_interval,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GeneralUserSetting) Reset() { @@ -295,6 +297,13 @@ func (x *GeneralUserSetting) GetTheme() string { return "" } +func (x *GeneralUserSetting) GetAutoRefreshInterval() int32 { + if x != nil { + return x.AutoRefreshInterval + } + return 0 +} + type SessionsUserSetting struct { state protoimpl.MessageState `protogen:"open.v1"` Sessions []*SessionsUserSetting_Session `protobuf:"bytes,1,rep,name=sessions,proto3" json:"sessions,omitempty"` @@ -823,11 +832,12 @@ const file_store_user_setting_proto_rawDesc = "" + "\rACCESS_TOKENS\x10\x03\x12\r\n" + "\tSHORTCUTS\x10\x04\x12\f\n" + "\bWEBHOOKS\x10\x05B\a\n" + - "\x05value\"k\n" + + "\x05value\"\x9f\x01\n" + "\x12GeneralUserSetting\x12\x16\n" + "\x06locale\x18\x01 \x01(\tR\x06locale\x12'\n" + "\x0fmemo_visibility\x18\x02 \x01(\tR\x0ememoVisibility\x12\x14\n" + - "\x05theme\x18\x03 \x01(\tR\x05theme\"\xf3\x03\n" + + "\x05theme\x18\x03 \x01(\tR\x05theme\x122\n" + + "\x15auto_refresh_interval\x18\x04 \x01(\x05R\x13autoRefreshInterval\"\xf3\x03\n" + "\x13SessionsUserSetting\x12D\n" + "\bsessions\x18\x01 \x03(\v2(.memos.store.SessionsUserSetting.SessionR\bsessions\x1a\xfd\x01\n" + "\aSession\x12\x1d\n" + diff --git a/proto/store/instance_setting.proto b/proto/store/instance_setting.proto index 6314731c7..c3b24b5a3 100644 --- a/proto/store/instance_setting.proto +++ b/proto/store/instance_setting.proto @@ -52,6 +52,10 @@ message InstanceGeneralSetting { bool disallow_change_username = 8; // disallow_change_nickname disallows changing nickname. bool disallow_change_nickname = 9; + // enable_explore_auto_refresh enables auto-refresh on Explore page. Default: true. + bool enable_explore_auto_refresh = 10; + // min_auto_refresh_interval is the minimum auto-refresh interval in seconds. Default: 1. + int32 min_auto_refresh_interval = 11; } message InstanceCustomProfile { diff --git a/proto/store/user_setting.proto b/proto/store/user_setting.proto index 87c8657f4..45f76bebc 100644 --- a/proto/store/user_setting.proto +++ b/proto/store/user_setting.proto @@ -41,6 +41,8 @@ message GeneralUserSetting { // The user's theme preference. // This references a CSS file in the web/public/themes/ directory. string theme = 3; + // Auto-refresh interval in seconds. 0 = disabled, default = 30. + int32 auto_refresh_interval = 4; } message SessionsUserSetting { diff --git a/web/src/types/proto/api/v1/instance_service_pb.ts b/web/src/types/proto/api/v1/instance_service_pb.ts index d7bd89399..36f3bd409 100644 --- a/web/src/types/proto/api/v1/instance_service_pb.ts +++ b/web/src/types/proto/api/v1/instance_service_pb.ts @@ -16,7 +16,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file api/v1/instance_service.proto. */ export const file_api_v1_instance_service: GenFile = /*@__PURE__*/ - fileDesc("Ch1hcGkvdjEvaW5zdGFuY2Vfc2VydmljZS5wcm90bxIMbWVtb3MuYXBpLnYxIlUKD0luc3RhbmNlUHJvZmlsZRINCgVvd25lchgBIAEoCRIPCgd2ZXJzaW9uGAIgASgJEgwKBG1vZGUYAyABKAkSFAoMaW5zdGFuY2VfdXJsGAYgASgJIhsKGUdldEluc3RhbmNlUHJvZmlsZVJlcXVlc3Qi6AsKD0luc3RhbmNlU2V0dGluZxIRCgRuYW1lGAEgASgJQgPgQQgSRwoPZ2VuZXJhbF9zZXR0aW5nGAIgASgLMiwubWVtb3MuYXBpLnYxLkluc3RhbmNlU2V0dGluZy5HZW5lcmFsU2V0dGluZ0gAEkcKD3N0b3JhZ2Vfc2V0dGluZxgDIAEoCzIsLm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuU3RvcmFnZVNldHRpbmdIABJQChRtZW1vX3JlbGF0ZWRfc2V0dGluZxgEIAEoCzIwLm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuTWVtb1JlbGF0ZWRTZXR0aW5nSAAahwMKDkdlbmVyYWxTZXR0aW5nEiIKGmRpc2FsbG93X3VzZXJfcmVnaXN0cmF0aW9uGAIgASgIEh4KFmRpc2FsbG93X3Bhc3N3b3JkX2F1dGgYAyABKAgSGQoRYWRkaXRpb25hbF9zY3JpcHQYBCABKAkSGAoQYWRkaXRpb25hbF9zdHlsZRgFIAEoCRJSCg5jdXN0b21fcHJvZmlsZRgGIAEoCzI6Lm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuR2VuZXJhbFNldHRpbmcuQ3VzdG9tUHJvZmlsZRIdChV3ZWVrX3N0YXJ0X2RheV9vZmZzZXQYByABKAUSIAoYZGlzYWxsb3dfY2hhbmdlX3VzZXJuYW1lGAggASgIEiAKGGRpc2FsbG93X2NoYW5nZV9uaWNrbmFtZRgJIAEoCBpFCg1DdXN0b21Qcm9maWxlEg0KBXRpdGxlGAEgASgJEhMKC2Rlc2NyaXB0aW9uGAIgASgJEhAKCGxvZ29fdXJsGAMgASgJGroDCg5TdG9yYWdlU2V0dGluZxJOCgxzdG9yYWdlX3R5cGUYASABKA4yOC5tZW1vcy5hcGkudjEuSW5zdGFuY2VTZXR0aW5nLlN0b3JhZ2VTZXR0aW5nLlN0b3JhZ2VUeXBlEhkKEWZpbGVwYXRoX3RlbXBsYXRlGAIgASgJEhwKFHVwbG9hZF9zaXplX2xpbWl0X21iGAMgASgDEkgKCXMzX2NvbmZpZxgEIAEoCzI1Lm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuU3RvcmFnZVNldHRpbmcuUzNDb25maWcahgEKCFMzQ29uZmlnEhUKDWFjY2Vzc19rZXlfaWQYASABKAkSGQoRYWNjZXNzX2tleV9zZWNyZXQYAiABKAkSEAoIZW5kcG9pbnQYAyABKAkSDgoGcmVnaW9uGAQgASgJEg4KBmJ1Y2tldBgFIAEoCRIWCg51c2VfcGF0aF9zdHlsZRgGIAEoCCJMCgtTdG9yYWdlVHlwZRIcChhTVE9SQUdFX1RZUEVfVU5TUEVDSUZJRUQQABIMCghEQVRBQkFTRRABEgkKBUxPQ0FMEAISBgoCUzMQAxriAQoSTWVtb1JlbGF0ZWRTZXR0aW5nEiIKGmRpc2FsbG93X3B1YmxpY192aXNpYmlsaXR5GAEgASgIEiAKGGRpc3BsYXlfd2l0aF91cGRhdGVfdGltZRgCIAEoCBIcChRjb250ZW50X2xlbmd0aF9saW1pdBgDIAEoBRIgChhlbmFibGVfZG91YmxlX2NsaWNrX2VkaXQYBCABKAgSEQoJcmVhY3Rpb25zGAcgAygJEiAKGGVuYWJsZV9ibHVyX25zZndfY29udGVudBgJIAEoCBIRCgluc2Z3X3RhZ3MYCiADKAkiRgoDS2V5EhMKD0tFWV9VTlNQRUNJRklFRBAAEgsKB0dFTkVSQUwQARILCgdTVE9SQUdFEAISEAoMTUVNT19SRUxBVEVEEAM6YepBXgocbWVtb3MuYXBpLnYxL0luc3RhbmNlU2V0dGluZxIbaW5zdGFuY2Uvc2V0dGluZ3Mve3NldHRpbmd9KhBpbnN0YW5jZVNldHRpbmdzMg9pbnN0YW5jZVNldHRpbmdCBwoFdmFsdWUiTwoZR2V0SW5zdGFuY2VTZXR0aW5nUmVxdWVzdBIyCgRuYW1lGAEgASgJQiTgQQL6QR4KHG1lbW9zLmFwaS52MS9JbnN0YW5jZVNldHRpbmciiQEKHFVwZGF0ZUluc3RhbmNlU2V0dGluZ1JlcXVlc3QSMwoHc2V0dGluZxgBIAEoCzIdLm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmdCA+BBAhI0Cgt1cGRhdGVfbWFzaxgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2tCA+BBATLbAwoPSW5zdGFuY2VTZXJ2aWNlEn4KEkdldEluc3RhbmNlUHJvZmlsZRInLm1lbW9zLmFwaS52MS5HZXRJbnN0YW5jZVByb2ZpbGVSZXF1ZXN0Gh0ubWVtb3MuYXBpLnYxLkluc3RhbmNlUHJvZmlsZSIggtPkkwIaEhgvYXBpL3YxL2luc3RhbmNlL3Byb2ZpbGUSjwEKEkdldEluc3RhbmNlU2V0dGluZxInLm1lbW9zLmFwaS52MS5HZXRJbnN0YW5jZVNldHRpbmdSZXF1ZXN0Gh0ubWVtb3MuYXBpLnYxLkluc3RhbmNlU2V0dGluZyIx2kEEbmFtZYLT5JMCJBIiL2FwaS92MS97bmFtZT1pbnN0YW5jZS9zZXR0aW5ncy8qfRK1AQoVVXBkYXRlSW5zdGFuY2VTZXR0aW5nEioubWVtb3MuYXBpLnYxLlVwZGF0ZUluc3RhbmNlU2V0dGluZ1JlcXVlc3QaHS5tZW1vcy5hcGkudjEuSW5zdGFuY2VTZXR0aW5nIlHaQRNzZXR0aW5nLHVwZGF0ZV9tYXNrgtPkkwI1OgdzZXR0aW5nMiovYXBpL3YxL3tzZXR0aW5nLm5hbWU9aW5zdGFuY2Uvc2V0dGluZ3MvKn1CrAEKEGNvbS5tZW1vcy5hcGkudjFCFEluc3RhbmNlU2VydmljZVByb3RvUAFaMGdpdGh1Yi5jb20vdXNlbWVtb3MvbWVtb3MvcHJvdG8vZ2VuL2FwaS92MTthcGl2MaICA01BWKoCDE1lbW9zLkFwaS5WMcoCDE1lbW9zXEFwaVxWMeICGE1lbW9zXEFwaVxWMVxHUEJNZXRhZGF0YeoCDk1lbW9zOjpBcGk6OlYxYgZwcm90bzM", [file_google_api_annotations, file_google_api_client, file_google_api_field_behavior, file_google_api_resource, file_google_protobuf_field_mask]); + fileDesc("Ch1hcGkvdjEvaW5zdGFuY2Vfc2VydmljZS5wcm90bxIMbWVtb3MuYXBpLnYxIlUKD0luc3RhbmNlUHJvZmlsZRINCgVvd25lchgBIAEoCRIPCgd2ZXJzaW9uGAIgASgJEgwKBG1vZGUYAyABKAkSFAoMaW5zdGFuY2VfdXJsGAYgASgJIhsKGUdldEluc3RhbmNlUHJvZmlsZVJlcXVlc3QisAwKD0luc3RhbmNlU2V0dGluZxIRCgRuYW1lGAEgASgJQgPgQQgSRwoPZ2VuZXJhbF9zZXR0aW5nGAIgASgLMiwubWVtb3MuYXBpLnYxLkluc3RhbmNlU2V0dGluZy5HZW5lcmFsU2V0dGluZ0gAEkcKD3N0b3JhZ2Vfc2V0dGluZxgDIAEoCzIsLm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuU3RvcmFnZVNldHRpbmdIABJQChRtZW1vX3JlbGF0ZWRfc2V0dGluZxgEIAEoCzIwLm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuTWVtb1JlbGF0ZWRTZXR0aW5nSAAazwMKDkdlbmVyYWxTZXR0aW5nEiIKGmRpc2FsbG93X3VzZXJfcmVnaXN0cmF0aW9uGAIgASgIEh4KFmRpc2FsbG93X3Bhc3N3b3JkX2F1dGgYAyABKAgSGQoRYWRkaXRpb25hbF9zY3JpcHQYBCABKAkSGAoQYWRkaXRpb25hbF9zdHlsZRgFIAEoCRJSCg5jdXN0b21fcHJvZmlsZRgGIAEoCzI6Lm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuR2VuZXJhbFNldHRpbmcuQ3VzdG9tUHJvZmlsZRIdChV3ZWVrX3N0YXJ0X2RheV9vZmZzZXQYByABKAUSIAoYZGlzYWxsb3dfY2hhbmdlX3VzZXJuYW1lGAggASgIEiAKGGRpc2FsbG93X2NoYW5nZV9uaWNrbmFtZRgJIAEoCBIjChtlbmFibGVfZXhwbG9yZV9hdXRvX3JlZnJlc2gYCiABKAgSIQoZbWluX2F1dG9fcmVmcmVzaF9pbnRlcnZhbBgLIAEoBRpFCg1DdXN0b21Qcm9maWxlEg0KBXRpdGxlGAEgASgJEhMKC2Rlc2NyaXB0aW9uGAIgASgJEhAKCGxvZ29fdXJsGAMgASgJGroDCg5TdG9yYWdlU2V0dGluZxJOCgxzdG9yYWdlX3R5cGUYASABKA4yOC5tZW1vcy5hcGkudjEuSW5zdGFuY2VTZXR0aW5nLlN0b3JhZ2VTZXR0aW5nLlN0b3JhZ2VUeXBlEhkKEWZpbGVwYXRoX3RlbXBsYXRlGAIgASgJEhwKFHVwbG9hZF9zaXplX2xpbWl0X21iGAMgASgDEkgKCXMzX2NvbmZpZxgEIAEoCzI1Lm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmcuU3RvcmFnZVNldHRpbmcuUzNDb25maWcahgEKCFMzQ29uZmlnEhUKDWFjY2Vzc19rZXlfaWQYASABKAkSGQoRYWNjZXNzX2tleV9zZWNyZXQYAiABKAkSEAoIZW5kcG9pbnQYAyABKAkSDgoGcmVnaW9uGAQgASgJEg4KBmJ1Y2tldBgFIAEoCRIWCg51c2VfcGF0aF9zdHlsZRgGIAEoCCJMCgtTdG9yYWdlVHlwZRIcChhTVE9SQUdFX1RZUEVfVU5TUEVDSUZJRUQQABIMCghEQVRBQkFTRRABEgkKBUxPQ0FMEAISBgoCUzMQAxriAQoSTWVtb1JlbGF0ZWRTZXR0aW5nEiIKGmRpc2FsbG93X3B1YmxpY192aXNpYmlsaXR5GAEgASgIEiAKGGRpc3BsYXlfd2l0aF91cGRhdGVfdGltZRgCIAEoCBIcChRjb250ZW50X2xlbmd0aF9saW1pdBgDIAEoBRIgChhlbmFibGVfZG91YmxlX2NsaWNrX2VkaXQYBCABKAgSEQoJcmVhY3Rpb25zGAcgAygJEiAKGGVuYWJsZV9ibHVyX25zZndfY29udGVudBgJIAEoCBIRCgluc2Z3X3RhZ3MYCiADKAkiRgoDS2V5EhMKD0tFWV9VTlNQRUNJRklFRBAAEgsKB0dFTkVSQUwQARILCgdTVE9SQUdFEAISEAoMTUVNT19SRUxBVEVEEAM6YepBXgocbWVtb3MuYXBpLnYxL0luc3RhbmNlU2V0dGluZxIbaW5zdGFuY2Uvc2V0dGluZ3Mve3NldHRpbmd9KhBpbnN0YW5jZVNldHRpbmdzMg9pbnN0YW5jZVNldHRpbmdCBwoFdmFsdWUiTwoZR2V0SW5zdGFuY2VTZXR0aW5nUmVxdWVzdBIyCgRuYW1lGAEgASgJQiTgQQL6QR4KHG1lbW9zLmFwaS52MS9JbnN0YW5jZVNldHRpbmciiQEKHFVwZGF0ZUluc3RhbmNlU2V0dGluZ1JlcXVlc3QSMwoHc2V0dGluZxgBIAEoCzIdLm1lbW9zLmFwaS52MS5JbnN0YW5jZVNldHRpbmdCA+BBAhI0Cgt1cGRhdGVfbWFzaxgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2tCA+BBATLbAwoPSW5zdGFuY2VTZXJ2aWNlEn4KEkdldEluc3RhbmNlUHJvZmlsZRInLm1lbW9zLmFwaS52MS5HZXRJbnN0YW5jZVByb2ZpbGVSZXF1ZXN0Gh0ubWVtb3MuYXBpLnYxLkluc3RhbmNlUHJvZmlsZSIggtPkkwIaEhgvYXBpL3YxL2luc3RhbmNlL3Byb2ZpbGUSjwEKEkdldEluc3RhbmNlU2V0dGluZxInLm1lbW9zLmFwaS52MS5HZXRJbnN0YW5jZVNldHRpbmdSZXF1ZXN0Gh0ubWVtb3MuYXBpLnYxLkluc3RhbmNlU2V0dGluZyIx2kEEbmFtZYLT5JMCJBIiL2FwaS92MS97bmFtZT1pbnN0YW5jZS9zZXR0aW5ncy8qfRK1AQoVVXBkYXRlSW5zdGFuY2VTZXR0aW5nEioubWVtb3MuYXBpLnYxLlVwZGF0ZUluc3RhbmNlU2V0dGluZ1JlcXVlc3QaHS5tZW1vcy5hcGkudjEuSW5zdGFuY2VTZXR0aW5nIlHaQRNzZXR0aW5nLHVwZGF0ZV9tYXNrgtPkkwI1OgdzZXR0aW5nMiovYXBpL3YxL3tzZXR0aW5nLm5hbWU9aW5zdGFuY2Uvc2V0dGluZ3MvKn1CrAEKEGNvbS5tZW1vcy5hcGkudjFCFEluc3RhbmNlU2VydmljZVByb3RvUAFaMGdpdGh1Yi5jb20vdXNlbWVtb3MvbWVtb3MvcHJvdG8vZ2VuL2FwaS92MTthcGl2MaICA01BWKoCDE1lbW9zLkFwaS5WMcoCDE1lbW9zXEFwaVxWMeICGE1lbW9zXEFwaVxWMVxHUEJNZXRhZGF0YeoCDk1lbW9zOjpBcGk6OlYxYgZwcm90bzM", [file_google_api_annotations, file_google_api_client, file_google_api_field_behavior, file_google_api_resource, file_google_protobuf_field_mask]); /** * Instance profile message containing basic instance information. @@ -184,6 +184,20 @@ export type InstanceSetting_GeneralSetting = Message<"memos.api.v1.InstanceSetti * @generated from field: bool disallow_change_nickname = 9; */ disallowChangeNickname: boolean; + + /** + * enable_explore_auto_refresh enables auto-refresh on Explore page. Default: true. + * + * @generated from field: bool enable_explore_auto_refresh = 10; + */ + enableExploreAutoRefresh: boolean; + + /** + * min_auto_refresh_interval is the minimum auto-refresh interval in seconds. Default: 1. + * + * @generated from field: int32 min_auto_refresh_interval = 11; + */ + minAutoRefreshInterval: number; }; /** diff --git a/web/src/types/proto/api/v1/user_service_pb.ts b/web/src/types/proto/api/v1/user_service_pb.ts index e940526b8..d20c9445f 100644 --- a/web/src/types/proto/api/v1/user_service_pb.ts +++ b/web/src/types/proto/api/v1/user_service_pb.ts @@ -18,7 +18,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file api/v1/user_service.proto. */ export const file_api_v1_user_service: GenFile = /*@__PURE__*/ - fileDesc("ChlhcGkvdjEvdXNlcl9zZXJ2aWNlLnByb3RvEgxtZW1vcy5hcGkudjEi4AMKBFVzZXISEQoEbmFtZRgBIAEoCUID4EEIEioKBHJvbGUYAiABKA4yFy5tZW1vcy5hcGkudjEuVXNlci5Sb2xlQgPgQQISFQoIdXNlcm5hbWUYAyABKAlCA+BBAhISCgVlbWFpbBgEIAEoCUID4EEBEhkKDGRpc3BsYXlfbmFtZRgFIAEoCUID4EEBEhcKCmF2YXRhcl91cmwYBiABKAlCA+BBARIYCgtkZXNjcmlwdGlvbhgHIAEoCUID4EEBEhUKCHBhc3N3b3JkGAggASgJQgPgQQQSJwoFc3RhdGUYCSABKA4yEy5tZW1vcy5hcGkudjEuU3RhdGVCA+BBAhI0CgtjcmVhdGVfdGltZRgKIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxI0Cgt1cGRhdGVfdGltZRgLIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAyI7CgRSb2xlEhQKEFJPTEVfVU5TUEVDSUZJRUQQABIICgRIT1NUEAESCQoFQURNSU4QAhIICgRVU0VSEAM6N+pBNAoRbWVtb3MuYXBpLnYxL1VzZXISDHVzZXJzL3t1c2VyfRoEbmFtZSoFdXNlcnMyBHVzZXIicwoQTGlzdFVzZXJzUmVxdWVzdBIWCglwYWdlX3NpemUYASABKAVCA+BBARIXCgpwYWdlX3Rva2VuGAIgASgJQgPgQQESEwoGZmlsdGVyGAMgASgJQgPgQQESGQoMc2hvd19kZWxldGVkGAQgASgIQgPgQQEiYwoRTGlzdFVzZXJzUmVzcG9uc2USIQoFdXNlcnMYASADKAsyEi5tZW1vcy5hcGkudjEuVXNlchIXCg9uZXh0X3BhZ2VfdG9rZW4YAiABKAkSEgoKdG90YWxfc2l6ZRgDIAEoBSJtCg5HZXRVc2VyUmVxdWVzdBInCgRuYW1lGAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEjIKCXJlYWRfbWFzaxgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2tCA+BBASKIAQoRQ3JlYXRlVXNlclJlcXVlc3QSKAoEdXNlchgBIAEoCzISLm1lbW9zLmFwaS52MS5Vc2VyQgbgQQLgQQQSFAoHdXNlcl9pZBgCIAEoCUID4EEBEhoKDXZhbGlkYXRlX29ubHkYAyABKAhCA+BBARIXCgpyZXF1ZXN0X2lkGAQgASgJQgPgQQEijAEKEVVwZGF0ZVVzZXJSZXF1ZXN0EiUKBHVzZXIYASABKAsyEi5tZW1vcy5hcGkudjEuVXNlckID4EECEjQKC3VwZGF0ZV9tYXNrGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkZpZWxkTWFza0ID4EECEhoKDWFsbG93X21pc3NpbmcYAyABKAhCA+BBASJQChFEZWxldGVVc2VyUmVxdWVzdBInCgRuYW1lGAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEhIKBWZvcmNlGAIgASgIQgPgQQEi2AMKCVVzZXJTdGF0cxIRCgRuYW1lGAEgASgJQgPgQQgSOwoXbWVtb19kaXNwbGF5X3RpbWVzdGFtcHMYAiADKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEj4KD21lbW9fdHlwZV9zdGF0cxgDIAEoCzIlLm1lbW9zLmFwaS52MS5Vc2VyU3RhdHMuTWVtb1R5cGVTdGF0cxI4Cgl0YWdfY291bnQYBCADKAsyJS5tZW1vcy5hcGkudjEuVXNlclN0YXRzLlRhZ0NvdW50RW50cnkSFAoMcGlubmVkX21lbW9zGAUgAygJEhgKEHRvdGFsX21lbW9fY291bnQYBiABKAUaLwoNVGFnQ291bnRFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAU6AjgBGl8KDU1lbW9UeXBlU3RhdHMSEgoKbGlua19jb3VudBgBIAEoBRISCgpjb2RlX2NvdW50GAIgASgFEhIKCnRvZG9fY291bnQYAyABKAUSEgoKdW5kb19jb3VudBgEIAEoBTo/6kE8ChZtZW1vcy5hcGkudjEvVXNlclN0YXRzEgx1c2Vycy97dXNlcn0qCXVzZXJTdGF0czIJdXNlclN0YXRzIj4KE0dldFVzZXJTdGF0c1JlcXVlc3QSJwoEbmFtZRgBIAEoCUIZ4EEC+kETChFtZW1vcy5hcGkudjEvVXNlciIZChdMaXN0QWxsVXNlclN0YXRzUmVxdWVzdCJCChhMaXN0QWxsVXNlclN0YXRzUmVzcG9uc2USJgoFc3RhdHMYASADKAsyFy5tZW1vcy5hcGkudjEuVXNlclN0YXRzIqUGCgtVc2VyU2V0dGluZxIRCgRuYW1lGAEgASgJQgPgQQgSQwoPZ2VuZXJhbF9zZXR0aW5nGAIgASgLMigubWVtb3MuYXBpLnYxLlVzZXJTZXR0aW5nLkdlbmVyYWxTZXR0aW5nSAASRQoQc2Vzc2lvbnNfc2V0dGluZxgDIAEoCzIpLm1lbW9zLmFwaS52MS5Vc2VyU2V0dGluZy5TZXNzaW9uc1NldHRpbmdIABJOChVhY2Nlc3NfdG9rZW5zX3NldHRpbmcYBCABKAsyLS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmcuQWNjZXNzVG9rZW5zU2V0dGluZ0gAEkUKEHdlYmhvb2tzX3NldHRpbmcYBSABKAsyKS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmcuV2ViaG9va3NTZXR0aW5nSAAaVwoOR2VuZXJhbFNldHRpbmcSEwoGbG9jYWxlGAEgASgJQgPgQQESHAoPbWVtb192aXNpYmlsaXR5GAMgASgJQgPgQQESEgoFdGhlbWUYBCABKAlCA+BBARo+Cg9TZXNzaW9uc1NldHRpbmcSKwoIc2Vzc2lvbnMYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlclNlc3Npb24aSwoTQWNjZXNzVG9rZW5zU2V0dGluZxI0Cg1hY2Nlc3NfdG9rZW5zGAEgAygLMh0ubWVtb3MuYXBpLnYxLlVzZXJBY2Nlc3NUb2tlbho+Cg9XZWJob29rc1NldHRpbmcSKwoId2ViaG9va3MYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlcldlYmhvb2siVgoDS2V5EhMKD0tFWV9VTlNQRUNJRklFRBAAEgsKB0dFTkVSQUwQARIMCghTRVNTSU9OUxACEhEKDUFDQ0VTU19UT0tFTlMQAxIMCghXRUJIT09LUxAEOlnqQVYKGG1lbW9zLmFwaS52MS9Vc2VyU2V0dGluZxIfdXNlcnMve3VzZXJ9L3NldHRpbmdzL3tzZXR0aW5nfSoMdXNlclNldHRpbmdzMgt1c2VyU2V0dGluZ0IHCgV2YWx1ZSJHChVHZXRVc2VyU2V0dGluZ1JlcXVlc3QSLgoEbmFtZRgBIAEoCUIg4EEC+kEaChhtZW1vcy5hcGkudjEvVXNlclNldHRpbmcigQEKGFVwZGF0ZVVzZXJTZXR0aW5nUmVxdWVzdBIvCgdzZXR0aW5nGAEgASgLMhkubWVtb3MuYXBpLnYxLlVzZXJTZXR0aW5nQgPgQQISNAoLdXBkYXRlX21hc2sYAiABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrQgPgQQIidQoXTGlzdFVzZXJTZXR0aW5nc1JlcXVlc3QSKQoGcGFyZW50GAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEhYKCXBhZ2Vfc2l6ZRgCIAEoBUID4EEBEhcKCnBhZ2VfdG9rZW4YAyABKAlCA+BBASJ0ChhMaXN0VXNlclNldHRpbmdzUmVzcG9uc2USKwoIc2V0dGluZ3MYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmcSFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhIKCnRvdGFsX3NpemUYAyABKAUisgIKD1VzZXJBY2Nlc3NUb2tlbhIRCgRuYW1lGAEgASgJQgPgQQgSGQoMYWNjZXNzX3Rva2VuGAIgASgJQgPgQQMSGAoLZGVzY3JpcHRpb24YAyABKAlCA+BBARIyCglpc3N1ZWRfYXQYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSMwoKZXhwaXJlc19hdBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBATpu6kFrChxtZW1vcy5hcGkudjEvVXNlckFjY2Vzc1Rva2VuEih1c2Vycy97dXNlcn0vYWNjZXNzVG9rZW5zL3thY2Nlc3NfdG9rZW59KhB1c2VyQWNjZXNzVG9rZW5zMg91c2VyQWNjZXNzVG9rZW4ieQobTGlzdFVzZXJBY2Nlc3NUb2tlbnNSZXF1ZXN0EikKBnBhcmVudBgBIAEoCUIZ4EEC+kETChFtZW1vcy5hcGkudjEvVXNlchIWCglwYWdlX3NpemUYAiABKAVCA+BBARIXCgpwYWdlX3Rva2VuGAMgASgJQgPgQQEigQEKHExpc3RVc2VyQWNjZXNzVG9rZW5zUmVzcG9uc2USNAoNYWNjZXNzX3Rva2VucxgBIAMoCzIdLm1lbW9zLmFwaS52MS5Vc2VyQWNjZXNzVG9rZW4SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhIKCnRvdGFsX3NpemUYAyABKAUioQEKHENyZWF0ZVVzZXJBY2Nlc3NUb2tlblJlcXVlc3QSKQoGcGFyZW50GAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEjgKDGFjY2Vzc190b2tlbhgCIAEoCzIdLm1lbW9zLmFwaS52MS5Vc2VyQWNjZXNzVG9rZW5CA+BBAhIcCg9hY2Nlc3NfdG9rZW5faWQYAyABKAlCA+BBASJSChxEZWxldGVVc2VyQWNjZXNzVG9rZW5SZXF1ZXN0EjIKBG5hbWUYASABKAlCJOBBAvpBHgocbWVtb3MuYXBpLnYxL1VzZXJBY2Nlc3NUb2tlbiKpAwoLVXNlclNlc3Npb24SEQoEbmFtZRgBIAEoCUID4EEIEhcKCnNlc3Npb25faWQYAiABKAlCA+BBAxI0CgtjcmVhdGVfdGltZRgDIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxI7ChJsYXN0X2FjY2Vzc2VkX3RpbWUYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSPgoLY2xpZW50X2luZm8YBSABKAsyJC5tZW1vcy5hcGkudjEuVXNlclNlc3Npb24uQ2xpZW50SW5mb0ID4EEDGnUKCkNsaWVudEluZm8SEgoKdXNlcl9hZ2VudBgBIAEoCRISCgppcF9hZGRyZXNzGAIgASgJEhgKC2RldmljZV90eXBlGAMgASgJQgPgQQESDwoCb3MYBCABKAlCA+BBARIUCgdicm93c2VyGAUgASgJQgPgQQE6ROpBQQoYbWVtb3MuYXBpLnYxL1VzZXJTZXNzaW9uEh91c2Vycy97dXNlcn0vc2Vzc2lvbnMve3Nlc3Npb259GgRuYW1lIkQKF0xpc3RVc2VyU2Vzc2lvbnNSZXF1ZXN0EikKBnBhcmVudBgBIAEoCUIZ4EEC+kETChFtZW1vcy5hcGkudjEvVXNlciJHChhMaXN0VXNlclNlc3Npb25zUmVzcG9uc2USKwoIc2Vzc2lvbnMYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlclNlc3Npb24iLQoYUmV2b2tlVXNlclNlc3Npb25SZXF1ZXN0EhEKBG5hbWUYASABKAlCA+BBAiKqAQoLVXNlcldlYmhvb2sSDAoEbmFtZRgBIAEoCRILCgN1cmwYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEjQKC2NyZWF0ZV90aW1lGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDEjQKC3VwZGF0ZV90aW1lGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDIi4KF0xpc3RVc2VyV2ViaG9va3NSZXF1ZXN0EhMKBnBhcmVudBgBIAEoCUID4EECIkcKGExpc3RVc2VyV2ViaG9va3NSZXNwb25zZRIrCgh3ZWJob29rcxgBIAMoCzIZLm1lbW9zLmFwaS52MS5Vc2VyV2ViaG9vayJgChhDcmVhdGVVc2VyV2ViaG9va1JlcXVlc3QSEwoGcGFyZW50GAEgASgJQgPgQQISLwoHd2ViaG9vaxgCIAEoCzIZLm1lbW9zLmFwaS52MS5Vc2VyV2ViaG9va0ID4EECInwKGFVwZGF0ZVVzZXJXZWJob29rUmVxdWVzdBIvCgd3ZWJob29rGAEgASgLMhkubWVtb3MuYXBpLnYxLlVzZXJXZWJob29rQgPgQQISLwoLdXBkYXRlX21hc2sYAiABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrIi0KGERlbGV0ZVVzZXJXZWJob29rUmVxdWVzdBIRCgRuYW1lGAEgASgJQgPgQQIiigQKEFVzZXJOb3RpZmljYXRpb24SFAoEbmFtZRgBIAEoCUIG4EED4EEIEikKBnNlbmRlchgCIAEoCUIZ4EED+kETChFtZW1vcy5hcGkudjEvVXNlchI6CgZzdGF0dXMYAyABKA4yJS5tZW1vcy5hcGkudjEuVXNlck5vdGlmaWNhdGlvbi5TdGF0dXNCA+BBARI0CgtjcmVhdGVfdGltZRgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxI2CgR0eXBlGAUgASgOMiMubWVtb3MuYXBpLnYxLlVzZXJOb3RpZmljYXRpb24uVHlwZUID4EEDEh0KC2FjdGl2aXR5X2lkGAYgASgFQgPgQQFIAIgBASI6CgZTdGF0dXMSFgoSU1RBVFVTX1VOU1BFQ0lGSUVEEAASCgoGVU5SRUFEEAESDAoIQVJDSElWRUQQAiIuCgRUeXBlEhQKEFRZUEVfVU5TUEVDSUZJRUQQABIQCgxNRU1PX0NPTU1FTlQQATpw6kFtCh1tZW1vcy5hcGkudjEvVXNlck5vdGlmaWNhdGlvbhIpdXNlcnMve3VzZXJ9L25vdGlmaWNhdGlvbnMve25vdGlmaWNhdGlvbn0aBG5hbWUqDW5vdGlmaWNhdGlvbnMyDG5vdGlmaWNhdGlvbkIOCgxfYWN0aXZpdHlfaWQijwEKHExpc3RVc2VyTm90aWZpY2F0aW9uc1JlcXVlc3QSKQoGcGFyZW50GAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEhYKCXBhZ2Vfc2l6ZRgCIAEoBUID4EEBEhcKCnBhZ2VfdG9rZW4YAyABKAlCA+BBARITCgZmaWx0ZXIYBCABKAlCA+BBASJvCh1MaXN0VXNlck5vdGlmaWNhdGlvbnNSZXNwb25zZRI1Cg1ub3RpZmljYXRpb25zGAEgAygLMh4ubWVtb3MuYXBpLnYxLlVzZXJOb3RpZmljYXRpb24SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJIpABCh1VcGRhdGVVc2VyTm90aWZpY2F0aW9uUmVxdWVzdBI5Cgxub3RpZmljYXRpb24YASABKAsyHi5tZW1vcy5hcGkudjEuVXNlck5vdGlmaWNhdGlvbkID4EECEjQKC3VwZGF0ZV9tYXNrGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkZpZWxkTWFza0ID4EECIlQKHURlbGV0ZVVzZXJOb3RpZmljYXRpb25SZXF1ZXN0EjMKBG5hbWUYASABKAlCJeBBAvpBHwodbWVtb3MuYXBpLnYxL1VzZXJOb3RpZmljYXRpb24y/hgKC1VzZXJTZXJ2aWNlEmMKCUxpc3RVc2VycxIeLm1lbW9zLmFwaS52MS5MaXN0VXNlcnNSZXF1ZXN0Gh8ubWVtb3MuYXBpLnYxLkxpc3RVc2Vyc1Jlc3BvbnNlIhWC0+STAg8SDS9hcGkvdjEvdXNlcnMSYgoHR2V0VXNlchIcLm1lbW9zLmFwaS52MS5HZXRVc2VyUmVxdWVzdBoSLm1lbW9zLmFwaS52MS5Vc2VyIiXaQQRuYW1lgtPkkwIYEhYvYXBpL3YxL3tuYW1lPXVzZXJzLyp9EmUKCkNyZWF0ZVVzZXISHy5tZW1vcy5hcGkudjEuQ3JlYXRlVXNlclJlcXVlc3QaEi5tZW1vcy5hcGkudjEuVXNlciIi2kEEdXNlcoLT5JMCFToEdXNlciINL2FwaS92MS91c2VycxJ/CgpVcGRhdGVVc2VyEh8ubWVtb3MuYXBpLnYxLlVwZGF0ZVVzZXJSZXF1ZXN0GhIubWVtb3MuYXBpLnYxLlVzZXIiPNpBEHVzZXIsdXBkYXRlX21hc2uC0+STAiM6BHVzZXIyGy9hcGkvdjEve3VzZXIubmFtZT11c2Vycy8qfRJsCgpEZWxldGVVc2VyEh8ubWVtb3MuYXBpLnYxLkRlbGV0ZVVzZXJSZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IiXaQQRuYW1lgtPkkwIYKhYvYXBpL3YxL3tuYW1lPXVzZXJzLyp9En4KEExpc3RBbGxVc2VyU3RhdHMSJS5tZW1vcy5hcGkudjEuTGlzdEFsbFVzZXJTdGF0c1JlcXVlc3QaJi5tZW1vcy5hcGkudjEuTGlzdEFsbFVzZXJTdGF0c1Jlc3BvbnNlIhuC0+STAhUSEy9hcGkvdjEvdXNlcnM6c3RhdHMSegoMR2V0VXNlclN0YXRzEiEubWVtb3MuYXBpLnYxLkdldFVzZXJTdGF0c1JlcXVlc3QaFy5tZW1vcy5hcGkudjEuVXNlclN0YXRzIi7aQQRuYW1lgtPkkwIhEh8vYXBpL3YxL3tuYW1lPXVzZXJzLyp9OmdldFN0YXRzEoIBCg5HZXRVc2VyU2V0dGluZxIjLm1lbW9zLmFwaS52MS5HZXRVc2VyU2V0dGluZ1JlcXVlc3QaGS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmciMNpBBG5hbWWC0+STAiMSIS9hcGkvdjEve25hbWU9dXNlcnMvKi9zZXR0aW5ncy8qfRKoAQoRVXBkYXRlVXNlclNldHRpbmcSJi5tZW1vcy5hcGkudjEuVXBkYXRlVXNlclNldHRpbmdSZXF1ZXN0GhkubWVtb3MuYXBpLnYxLlVzZXJTZXR0aW5nIlDaQRNzZXR0aW5nLHVwZGF0ZV9tYXNrgtPkkwI0OgdzZXR0aW5nMikvYXBpL3YxL3tzZXR0aW5nLm5hbWU9dXNlcnMvKi9zZXR0aW5ncy8qfRKVAQoQTGlzdFVzZXJTZXR0aW5ncxIlLm1lbW9zLmFwaS52MS5MaXN0VXNlclNldHRpbmdzUmVxdWVzdBomLm1lbW9zLmFwaS52MS5MaXN0VXNlclNldHRpbmdzUmVzcG9uc2UiMtpBBnBhcmVudILT5JMCIxIhL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L3NldHRpbmdzEqUBChRMaXN0VXNlckFjY2Vzc1Rva2VucxIpLm1lbW9zLmFwaS52MS5MaXN0VXNlckFjY2Vzc1Rva2Vuc1JlcXVlc3QaKi5tZW1vcy5hcGkudjEuTGlzdFVzZXJBY2Nlc3NUb2tlbnNSZXNwb25zZSI22kEGcGFyZW50gtPkkwInEiUvYXBpL3YxL3twYXJlbnQ9dXNlcnMvKn0vYWNjZXNzVG9rZW5zErUBChVDcmVhdGVVc2VyQWNjZXNzVG9rZW4SKi5tZW1vcy5hcGkudjEuQ3JlYXRlVXNlckFjY2Vzc1Rva2VuUmVxdWVzdBodLm1lbW9zLmFwaS52MS5Vc2VyQWNjZXNzVG9rZW4iUdpBE3BhcmVudCxhY2Nlc3NfdG9rZW6C0+STAjU6DGFjY2Vzc190b2tlbiIlL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L2FjY2Vzc1Rva2VucxKRAQoVRGVsZXRlVXNlckFjY2Vzc1Rva2VuEioubWVtb3MuYXBpLnYxLkRlbGV0ZVVzZXJBY2Nlc3NUb2tlblJlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiNNpBBG5hbWWC0+STAicqJS9hcGkvdjEve25hbWU9dXNlcnMvKi9hY2Nlc3NUb2tlbnMvKn0SlQEKEExpc3RVc2VyU2Vzc2lvbnMSJS5tZW1vcy5hcGkudjEuTGlzdFVzZXJTZXNzaW9uc1JlcXVlc3QaJi5tZW1vcy5hcGkudjEuTGlzdFVzZXJTZXNzaW9uc1Jlc3BvbnNlIjLaQQZwYXJlbnSC0+STAiMSIS9hcGkvdjEve3BhcmVudD11c2Vycy8qfS9zZXNzaW9ucxKFAQoRUmV2b2tlVXNlclNlc3Npb24SJi5tZW1vcy5hcGkudjEuUmV2b2tlVXNlclNlc3Npb25SZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IjDaQQRuYW1lgtPkkwIjKiEvYXBpL3YxL3tuYW1lPXVzZXJzLyovc2Vzc2lvbnMvKn0SlQEKEExpc3RVc2VyV2ViaG9va3MSJS5tZW1vcy5hcGkudjEuTGlzdFVzZXJXZWJob29rc1JlcXVlc3QaJi5tZW1vcy5hcGkudjEuTGlzdFVzZXJXZWJob29rc1Jlc3BvbnNlIjLaQQZwYXJlbnSC0+STAiMSIS9hcGkvdjEve3BhcmVudD11c2Vycy8qfS93ZWJob29rcxKbAQoRQ3JlYXRlVXNlcldlYmhvb2sSJi5tZW1vcy5hcGkudjEuQ3JlYXRlVXNlcldlYmhvb2tSZXF1ZXN0GhkubWVtb3MuYXBpLnYxLlVzZXJXZWJob29rIkPaQQ5wYXJlbnQsd2ViaG9va4LT5JMCLDoHd2ViaG9vayIhL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L3dlYmhvb2tzEqgBChFVcGRhdGVVc2VyV2ViaG9vaxImLm1lbW9zLmFwaS52MS5VcGRhdGVVc2VyV2ViaG9va1JlcXVlc3QaGS5tZW1vcy5hcGkudjEuVXNlcldlYmhvb2siUNpBE3dlYmhvb2ssdXBkYXRlX21hc2uC0+STAjQ6B3dlYmhvb2syKS9hcGkvdjEve3dlYmhvb2submFtZT11c2Vycy8qL3dlYmhvb2tzLyp9EoUBChFEZWxldGVVc2VyV2ViaG9vaxImLm1lbW9zLmFwaS52MS5EZWxldGVVc2VyV2ViaG9va1JlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiMNpBBG5hbWWC0+STAiMqIS9hcGkvdjEve25hbWU9dXNlcnMvKi93ZWJob29rcy8qfRKpAQoVTGlzdFVzZXJOb3RpZmljYXRpb25zEioubWVtb3MuYXBpLnYxLkxpc3RVc2VyTm90aWZpY2F0aW9uc1JlcXVlc3QaKy5tZW1vcy5hcGkudjEuTGlzdFVzZXJOb3RpZmljYXRpb25zUmVzcG9uc2UiN9pBBnBhcmVudILT5JMCKBImL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L25vdGlmaWNhdGlvbnMSywEKFlVwZGF0ZVVzZXJOb3RpZmljYXRpb24SKy5tZW1vcy5hcGkudjEuVXBkYXRlVXNlck5vdGlmaWNhdGlvblJlcXVlc3QaHi5tZW1vcy5hcGkudjEuVXNlck5vdGlmaWNhdGlvbiJk2kEYbm90aWZpY2F0aW9uLHVwZGF0ZV9tYXNrgtPkkwJDOgxub3RpZmljYXRpb24yMy9hcGkvdjEve25vdGlmaWNhdGlvbi5uYW1lPXVzZXJzLyovbm90aWZpY2F0aW9ucy8qfRKUAQoWRGVsZXRlVXNlck5vdGlmaWNhdGlvbhIrLm1lbW9zLmFwaS52MS5EZWxldGVVc2VyTm90aWZpY2F0aW9uUmVxdWVzdBoWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eSI12kEEbmFtZYLT5JMCKComL2FwaS92MS97bmFtZT11c2Vycy8qL25vdGlmaWNhdGlvbnMvKn1CqAEKEGNvbS5tZW1vcy5hcGkudjFCEFVzZXJTZXJ2aWNlUHJvdG9QAVowZ2l0aHViLmNvbS91c2VtZW1vcy9tZW1vcy9wcm90by9nZW4vYXBpL3YxO2FwaXYxogIDTUFYqgIMTWVtb3MuQXBpLlYxygIMTWVtb3NcQXBpXFYx4gIYTWVtb3NcQXBpXFYxXEdQQk1ldGFkYXRh6gIOTWVtb3M6OkFwaTo6VjFiBnByb3RvMw", [file_api_v1_common, file_google_api_annotations, file_google_api_client, file_google_api_field_behavior, file_google_api_resource, file_google_protobuf_empty, file_google_protobuf_field_mask, file_google_protobuf_timestamp]); + fileDesc("ChlhcGkvdjEvdXNlcl9zZXJ2aWNlLnByb3RvEgxtZW1vcy5hcGkudjEi4AMKBFVzZXISEQoEbmFtZRgBIAEoCUID4EEIEioKBHJvbGUYAiABKA4yFy5tZW1vcy5hcGkudjEuVXNlci5Sb2xlQgPgQQISFQoIdXNlcm5hbWUYAyABKAlCA+BBAhISCgVlbWFpbBgEIAEoCUID4EEBEhkKDGRpc3BsYXlfbmFtZRgFIAEoCUID4EEBEhcKCmF2YXRhcl91cmwYBiABKAlCA+BBARIYCgtkZXNjcmlwdGlvbhgHIAEoCUID4EEBEhUKCHBhc3N3b3JkGAggASgJQgPgQQQSJwoFc3RhdGUYCSABKA4yEy5tZW1vcy5hcGkudjEuU3RhdGVCA+BBAhI0CgtjcmVhdGVfdGltZRgKIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxI0Cgt1cGRhdGVfdGltZRgLIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAyI7CgRSb2xlEhQKEFJPTEVfVU5TUEVDSUZJRUQQABIICgRIT1NUEAESCQoFQURNSU4QAhIICgRVU0VSEAM6N+pBNAoRbWVtb3MuYXBpLnYxL1VzZXISDHVzZXJzL3t1c2VyfRoEbmFtZSoFdXNlcnMyBHVzZXIicwoQTGlzdFVzZXJzUmVxdWVzdBIWCglwYWdlX3NpemUYASABKAVCA+BBARIXCgpwYWdlX3Rva2VuGAIgASgJQgPgQQESEwoGZmlsdGVyGAMgASgJQgPgQQESGQoMc2hvd19kZWxldGVkGAQgASgIQgPgQQEiYwoRTGlzdFVzZXJzUmVzcG9uc2USIQoFdXNlcnMYASADKAsyEi5tZW1vcy5hcGkudjEuVXNlchIXCg9uZXh0X3BhZ2VfdG9rZW4YAiABKAkSEgoKdG90YWxfc2l6ZRgDIAEoBSJtCg5HZXRVc2VyUmVxdWVzdBInCgRuYW1lGAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEjIKCXJlYWRfbWFzaxgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2tCA+BBASKIAQoRQ3JlYXRlVXNlclJlcXVlc3QSKAoEdXNlchgBIAEoCzISLm1lbW9zLmFwaS52MS5Vc2VyQgbgQQLgQQQSFAoHdXNlcl9pZBgCIAEoCUID4EEBEhoKDXZhbGlkYXRlX29ubHkYAyABKAhCA+BBARIXCgpyZXF1ZXN0X2lkGAQgASgJQgPgQQEijAEKEVVwZGF0ZVVzZXJSZXF1ZXN0EiUKBHVzZXIYASABKAsyEi5tZW1vcy5hcGkudjEuVXNlckID4EECEjQKC3VwZGF0ZV9tYXNrGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkZpZWxkTWFza0ID4EECEhoKDWFsbG93X21pc3NpbmcYAyABKAhCA+BBASJQChFEZWxldGVVc2VyUmVxdWVzdBInCgRuYW1lGAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEhIKBWZvcmNlGAIgASgIQgPgQQEi2AMKCVVzZXJTdGF0cxIRCgRuYW1lGAEgASgJQgPgQQgSOwoXbWVtb19kaXNwbGF5X3RpbWVzdGFtcHMYAiADKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEj4KD21lbW9fdHlwZV9zdGF0cxgDIAEoCzIlLm1lbW9zLmFwaS52MS5Vc2VyU3RhdHMuTWVtb1R5cGVTdGF0cxI4Cgl0YWdfY291bnQYBCADKAsyJS5tZW1vcy5hcGkudjEuVXNlclN0YXRzLlRhZ0NvdW50RW50cnkSFAoMcGlubmVkX21lbW9zGAUgAygJEhgKEHRvdGFsX21lbW9fY291bnQYBiABKAUaLwoNVGFnQ291bnRFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAU6AjgBGl8KDU1lbW9UeXBlU3RhdHMSEgoKbGlua19jb3VudBgBIAEoBRISCgpjb2RlX2NvdW50GAIgASgFEhIKCnRvZG9fY291bnQYAyABKAUSEgoKdW5kb19jb3VudBgEIAEoBTo/6kE8ChZtZW1vcy5hcGkudjEvVXNlclN0YXRzEgx1c2Vycy97dXNlcn0qCXVzZXJTdGF0czIJdXNlclN0YXRzIj4KE0dldFVzZXJTdGF0c1JlcXVlc3QSJwoEbmFtZRgBIAEoCUIZ4EEC+kETChFtZW1vcy5hcGkudjEvVXNlciIZChdMaXN0QWxsVXNlclN0YXRzUmVxdWVzdCJCChhMaXN0QWxsVXNlclN0YXRzUmVzcG9uc2USJgoFc3RhdHMYASADKAsyFy5tZW1vcy5hcGkudjEuVXNlclN0YXRzIskGCgtVc2VyU2V0dGluZxIRCgRuYW1lGAEgASgJQgPgQQgSQwoPZ2VuZXJhbF9zZXR0aW5nGAIgASgLMigubWVtb3MuYXBpLnYxLlVzZXJTZXR0aW5nLkdlbmVyYWxTZXR0aW5nSAASRQoQc2Vzc2lvbnNfc2V0dGluZxgDIAEoCzIpLm1lbW9zLmFwaS52MS5Vc2VyU2V0dGluZy5TZXNzaW9uc1NldHRpbmdIABJOChVhY2Nlc3NfdG9rZW5zX3NldHRpbmcYBCABKAsyLS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmcuQWNjZXNzVG9rZW5zU2V0dGluZ0gAEkUKEHdlYmhvb2tzX3NldHRpbmcYBSABKAsyKS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmcuV2ViaG9va3NTZXR0aW5nSAAaewoOR2VuZXJhbFNldHRpbmcSEwoGbG9jYWxlGAEgASgJQgPgQQESHAoPbWVtb192aXNpYmlsaXR5GAMgASgJQgPgQQESEgoFdGhlbWUYBCABKAlCA+BBARIiChVhdXRvX3JlZnJlc2hfaW50ZXJ2YWwYBSABKAVCA+BBARo+Cg9TZXNzaW9uc1NldHRpbmcSKwoIc2Vzc2lvbnMYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlclNlc3Npb24aSwoTQWNjZXNzVG9rZW5zU2V0dGluZxI0Cg1hY2Nlc3NfdG9rZW5zGAEgAygLMh0ubWVtb3MuYXBpLnYxLlVzZXJBY2Nlc3NUb2tlbho+Cg9XZWJob29rc1NldHRpbmcSKwoId2ViaG9va3MYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlcldlYmhvb2siVgoDS2V5EhMKD0tFWV9VTlNQRUNJRklFRBAAEgsKB0dFTkVSQUwQARIMCghTRVNTSU9OUxACEhEKDUFDQ0VTU19UT0tFTlMQAxIMCghXRUJIT09LUxAEOlnqQVYKGG1lbW9zLmFwaS52MS9Vc2VyU2V0dGluZxIfdXNlcnMve3VzZXJ9L3NldHRpbmdzL3tzZXR0aW5nfSoMdXNlclNldHRpbmdzMgt1c2VyU2V0dGluZ0IHCgV2YWx1ZSJHChVHZXRVc2VyU2V0dGluZ1JlcXVlc3QSLgoEbmFtZRgBIAEoCUIg4EEC+kEaChhtZW1vcy5hcGkudjEvVXNlclNldHRpbmcigQEKGFVwZGF0ZVVzZXJTZXR0aW5nUmVxdWVzdBIvCgdzZXR0aW5nGAEgASgLMhkubWVtb3MuYXBpLnYxLlVzZXJTZXR0aW5nQgPgQQISNAoLdXBkYXRlX21hc2sYAiABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrQgPgQQIidQoXTGlzdFVzZXJTZXR0aW5nc1JlcXVlc3QSKQoGcGFyZW50GAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEhYKCXBhZ2Vfc2l6ZRgCIAEoBUID4EEBEhcKCnBhZ2VfdG9rZW4YAyABKAlCA+BBASJ0ChhMaXN0VXNlclNldHRpbmdzUmVzcG9uc2USKwoIc2V0dGluZ3MYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmcSFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhIKCnRvdGFsX3NpemUYAyABKAUisgIKD1VzZXJBY2Nlc3NUb2tlbhIRCgRuYW1lGAEgASgJQgPgQQgSGQoMYWNjZXNzX3Rva2VuGAIgASgJQgPgQQMSGAoLZGVzY3JpcHRpb24YAyABKAlCA+BBARIyCglpc3N1ZWRfYXQYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSMwoKZXhwaXJlc19hdBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBATpu6kFrChxtZW1vcy5hcGkudjEvVXNlckFjY2Vzc1Rva2VuEih1c2Vycy97dXNlcn0vYWNjZXNzVG9rZW5zL3thY2Nlc3NfdG9rZW59KhB1c2VyQWNjZXNzVG9rZW5zMg91c2VyQWNjZXNzVG9rZW4ieQobTGlzdFVzZXJBY2Nlc3NUb2tlbnNSZXF1ZXN0EikKBnBhcmVudBgBIAEoCUIZ4EEC+kETChFtZW1vcy5hcGkudjEvVXNlchIWCglwYWdlX3NpemUYAiABKAVCA+BBARIXCgpwYWdlX3Rva2VuGAMgASgJQgPgQQEigQEKHExpc3RVc2VyQWNjZXNzVG9rZW5zUmVzcG9uc2USNAoNYWNjZXNzX3Rva2VucxgBIAMoCzIdLm1lbW9zLmFwaS52MS5Vc2VyQWNjZXNzVG9rZW4SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhIKCnRvdGFsX3NpemUYAyABKAUioQEKHENyZWF0ZVVzZXJBY2Nlc3NUb2tlblJlcXVlc3QSKQoGcGFyZW50GAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEjgKDGFjY2Vzc190b2tlbhgCIAEoCzIdLm1lbW9zLmFwaS52MS5Vc2VyQWNjZXNzVG9rZW5CA+BBAhIcCg9hY2Nlc3NfdG9rZW5faWQYAyABKAlCA+BBASJSChxEZWxldGVVc2VyQWNjZXNzVG9rZW5SZXF1ZXN0EjIKBG5hbWUYASABKAlCJOBBAvpBHgocbWVtb3MuYXBpLnYxL1VzZXJBY2Nlc3NUb2tlbiKpAwoLVXNlclNlc3Npb24SEQoEbmFtZRgBIAEoCUID4EEIEhcKCnNlc3Npb25faWQYAiABKAlCA+BBAxI0CgtjcmVhdGVfdGltZRgDIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxI7ChJsYXN0X2FjY2Vzc2VkX3RpbWUYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSPgoLY2xpZW50X2luZm8YBSABKAsyJC5tZW1vcy5hcGkudjEuVXNlclNlc3Npb24uQ2xpZW50SW5mb0ID4EEDGnUKCkNsaWVudEluZm8SEgoKdXNlcl9hZ2VudBgBIAEoCRISCgppcF9hZGRyZXNzGAIgASgJEhgKC2RldmljZV90eXBlGAMgASgJQgPgQQESDwoCb3MYBCABKAlCA+BBARIUCgdicm93c2VyGAUgASgJQgPgQQE6ROpBQQoYbWVtb3MuYXBpLnYxL1VzZXJTZXNzaW9uEh91c2Vycy97dXNlcn0vc2Vzc2lvbnMve3Nlc3Npb259GgRuYW1lIkQKF0xpc3RVc2VyU2Vzc2lvbnNSZXF1ZXN0EikKBnBhcmVudBgBIAEoCUIZ4EEC+kETChFtZW1vcy5hcGkudjEvVXNlciJHChhMaXN0VXNlclNlc3Npb25zUmVzcG9uc2USKwoIc2Vzc2lvbnMYASADKAsyGS5tZW1vcy5hcGkudjEuVXNlclNlc3Npb24iLQoYUmV2b2tlVXNlclNlc3Npb25SZXF1ZXN0EhEKBG5hbWUYASABKAlCA+BBAiKqAQoLVXNlcldlYmhvb2sSDAoEbmFtZRgBIAEoCRILCgN1cmwYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEjQKC2NyZWF0ZV90aW1lGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDEjQKC3VwZGF0ZV90aW1lGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDIi4KF0xpc3RVc2VyV2ViaG9va3NSZXF1ZXN0EhMKBnBhcmVudBgBIAEoCUID4EECIkcKGExpc3RVc2VyV2ViaG9va3NSZXNwb25zZRIrCgh3ZWJob29rcxgBIAMoCzIZLm1lbW9zLmFwaS52MS5Vc2VyV2ViaG9vayJgChhDcmVhdGVVc2VyV2ViaG9va1JlcXVlc3QSEwoGcGFyZW50GAEgASgJQgPgQQISLwoHd2ViaG9vaxgCIAEoCzIZLm1lbW9zLmFwaS52MS5Vc2VyV2ViaG9va0ID4EECInwKGFVwZGF0ZVVzZXJXZWJob29rUmVxdWVzdBIvCgd3ZWJob29rGAEgASgLMhkubWVtb3MuYXBpLnYxLlVzZXJXZWJob29rQgPgQQISLwoLdXBkYXRlX21hc2sYAiABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrIi0KGERlbGV0ZVVzZXJXZWJob29rUmVxdWVzdBIRCgRuYW1lGAEgASgJQgPgQQIiigQKEFVzZXJOb3RpZmljYXRpb24SFAoEbmFtZRgBIAEoCUIG4EED4EEIEikKBnNlbmRlchgCIAEoCUIZ4EED+kETChFtZW1vcy5hcGkudjEvVXNlchI6CgZzdGF0dXMYAyABKA4yJS5tZW1vcy5hcGkudjEuVXNlck5vdGlmaWNhdGlvbi5TdGF0dXNCA+BBARI0CgtjcmVhdGVfdGltZRgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxI2CgR0eXBlGAUgASgOMiMubWVtb3MuYXBpLnYxLlVzZXJOb3RpZmljYXRpb24uVHlwZUID4EEDEh0KC2FjdGl2aXR5X2lkGAYgASgFQgPgQQFIAIgBASI6CgZTdGF0dXMSFgoSU1RBVFVTX1VOU1BFQ0lGSUVEEAASCgoGVU5SRUFEEAESDAoIQVJDSElWRUQQAiIuCgRUeXBlEhQKEFRZUEVfVU5TUEVDSUZJRUQQABIQCgxNRU1PX0NPTU1FTlQQATpw6kFtCh1tZW1vcy5hcGkudjEvVXNlck5vdGlmaWNhdGlvbhIpdXNlcnMve3VzZXJ9L25vdGlmaWNhdGlvbnMve25vdGlmaWNhdGlvbn0aBG5hbWUqDW5vdGlmaWNhdGlvbnMyDG5vdGlmaWNhdGlvbkIOCgxfYWN0aXZpdHlfaWQijwEKHExpc3RVc2VyTm90aWZpY2F0aW9uc1JlcXVlc3QSKQoGcGFyZW50GAEgASgJQhngQQL6QRMKEW1lbW9zLmFwaS52MS9Vc2VyEhYKCXBhZ2Vfc2l6ZRgCIAEoBUID4EEBEhcKCnBhZ2VfdG9rZW4YAyABKAlCA+BBARITCgZmaWx0ZXIYBCABKAlCA+BBASJvCh1MaXN0VXNlck5vdGlmaWNhdGlvbnNSZXNwb25zZRI1Cg1ub3RpZmljYXRpb25zGAEgAygLMh4ubWVtb3MuYXBpLnYxLlVzZXJOb3RpZmljYXRpb24SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJIpABCh1VcGRhdGVVc2VyTm90aWZpY2F0aW9uUmVxdWVzdBI5Cgxub3RpZmljYXRpb24YASABKAsyHi5tZW1vcy5hcGkudjEuVXNlck5vdGlmaWNhdGlvbkID4EECEjQKC3VwZGF0ZV9tYXNrGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkZpZWxkTWFza0ID4EECIlQKHURlbGV0ZVVzZXJOb3RpZmljYXRpb25SZXF1ZXN0EjMKBG5hbWUYASABKAlCJeBBAvpBHwodbWVtb3MuYXBpLnYxL1VzZXJOb3RpZmljYXRpb24y/hgKC1VzZXJTZXJ2aWNlEmMKCUxpc3RVc2VycxIeLm1lbW9zLmFwaS52MS5MaXN0VXNlcnNSZXF1ZXN0Gh8ubWVtb3MuYXBpLnYxLkxpc3RVc2Vyc1Jlc3BvbnNlIhWC0+STAg8SDS9hcGkvdjEvdXNlcnMSYgoHR2V0VXNlchIcLm1lbW9zLmFwaS52MS5HZXRVc2VyUmVxdWVzdBoSLm1lbW9zLmFwaS52MS5Vc2VyIiXaQQRuYW1lgtPkkwIYEhYvYXBpL3YxL3tuYW1lPXVzZXJzLyp9EmUKCkNyZWF0ZVVzZXISHy5tZW1vcy5hcGkudjEuQ3JlYXRlVXNlclJlcXVlc3QaEi5tZW1vcy5hcGkudjEuVXNlciIi2kEEdXNlcoLT5JMCFToEdXNlciINL2FwaS92MS91c2VycxJ/CgpVcGRhdGVVc2VyEh8ubWVtb3MuYXBpLnYxLlVwZGF0ZVVzZXJSZXF1ZXN0GhIubWVtb3MuYXBpLnYxLlVzZXIiPNpBEHVzZXIsdXBkYXRlX21hc2uC0+STAiM6BHVzZXIyGy9hcGkvdjEve3VzZXIubmFtZT11c2Vycy8qfRJsCgpEZWxldGVVc2VyEh8ubWVtb3MuYXBpLnYxLkRlbGV0ZVVzZXJSZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IiXaQQRuYW1lgtPkkwIYKhYvYXBpL3YxL3tuYW1lPXVzZXJzLyp9En4KEExpc3RBbGxVc2VyU3RhdHMSJS5tZW1vcy5hcGkudjEuTGlzdEFsbFVzZXJTdGF0c1JlcXVlc3QaJi5tZW1vcy5hcGkudjEuTGlzdEFsbFVzZXJTdGF0c1Jlc3BvbnNlIhuC0+STAhUSEy9hcGkvdjEvdXNlcnM6c3RhdHMSegoMR2V0VXNlclN0YXRzEiEubWVtb3MuYXBpLnYxLkdldFVzZXJTdGF0c1JlcXVlc3QaFy5tZW1vcy5hcGkudjEuVXNlclN0YXRzIi7aQQRuYW1lgtPkkwIhEh8vYXBpL3YxL3tuYW1lPXVzZXJzLyp9OmdldFN0YXRzEoIBCg5HZXRVc2VyU2V0dGluZxIjLm1lbW9zLmFwaS52MS5HZXRVc2VyU2V0dGluZ1JlcXVlc3QaGS5tZW1vcy5hcGkudjEuVXNlclNldHRpbmciMNpBBG5hbWWC0+STAiMSIS9hcGkvdjEve25hbWU9dXNlcnMvKi9zZXR0aW5ncy8qfRKoAQoRVXBkYXRlVXNlclNldHRpbmcSJi5tZW1vcy5hcGkudjEuVXBkYXRlVXNlclNldHRpbmdSZXF1ZXN0GhkubWVtb3MuYXBpLnYxLlVzZXJTZXR0aW5nIlDaQRNzZXR0aW5nLHVwZGF0ZV9tYXNrgtPkkwI0OgdzZXR0aW5nMikvYXBpL3YxL3tzZXR0aW5nLm5hbWU9dXNlcnMvKi9zZXR0aW5ncy8qfRKVAQoQTGlzdFVzZXJTZXR0aW5ncxIlLm1lbW9zLmFwaS52MS5MaXN0VXNlclNldHRpbmdzUmVxdWVzdBomLm1lbW9zLmFwaS52MS5MaXN0VXNlclNldHRpbmdzUmVzcG9uc2UiMtpBBnBhcmVudILT5JMCIxIhL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L3NldHRpbmdzEqUBChRMaXN0VXNlckFjY2Vzc1Rva2VucxIpLm1lbW9zLmFwaS52MS5MaXN0VXNlckFjY2Vzc1Rva2Vuc1JlcXVlc3QaKi5tZW1vcy5hcGkudjEuTGlzdFVzZXJBY2Nlc3NUb2tlbnNSZXNwb25zZSI22kEGcGFyZW50gtPkkwInEiUvYXBpL3YxL3twYXJlbnQ9dXNlcnMvKn0vYWNjZXNzVG9rZW5zErUBChVDcmVhdGVVc2VyQWNjZXNzVG9rZW4SKi5tZW1vcy5hcGkudjEuQ3JlYXRlVXNlckFjY2Vzc1Rva2VuUmVxdWVzdBodLm1lbW9zLmFwaS52MS5Vc2VyQWNjZXNzVG9rZW4iUdpBE3BhcmVudCxhY2Nlc3NfdG9rZW6C0+STAjU6DGFjY2Vzc190b2tlbiIlL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L2FjY2Vzc1Rva2VucxKRAQoVRGVsZXRlVXNlckFjY2Vzc1Rva2VuEioubWVtb3MuYXBpLnYxLkRlbGV0ZVVzZXJBY2Nlc3NUb2tlblJlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiNNpBBG5hbWWC0+STAicqJS9hcGkvdjEve25hbWU9dXNlcnMvKi9hY2Nlc3NUb2tlbnMvKn0SlQEKEExpc3RVc2VyU2Vzc2lvbnMSJS5tZW1vcy5hcGkudjEuTGlzdFVzZXJTZXNzaW9uc1JlcXVlc3QaJi5tZW1vcy5hcGkudjEuTGlzdFVzZXJTZXNzaW9uc1Jlc3BvbnNlIjLaQQZwYXJlbnSC0+STAiMSIS9hcGkvdjEve3BhcmVudD11c2Vycy8qfS9zZXNzaW9ucxKFAQoRUmV2b2tlVXNlclNlc3Npb24SJi5tZW1vcy5hcGkudjEuUmV2b2tlVXNlclNlc3Npb25SZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IjDaQQRuYW1lgtPkkwIjKiEvYXBpL3YxL3tuYW1lPXVzZXJzLyovc2Vzc2lvbnMvKn0SlQEKEExpc3RVc2VyV2ViaG9va3MSJS5tZW1vcy5hcGkudjEuTGlzdFVzZXJXZWJob29rc1JlcXVlc3QaJi5tZW1vcy5hcGkudjEuTGlzdFVzZXJXZWJob29rc1Jlc3BvbnNlIjLaQQZwYXJlbnSC0+STAiMSIS9hcGkvdjEve3BhcmVudD11c2Vycy8qfS93ZWJob29rcxKbAQoRQ3JlYXRlVXNlcldlYmhvb2sSJi5tZW1vcy5hcGkudjEuQ3JlYXRlVXNlcldlYmhvb2tSZXF1ZXN0GhkubWVtb3MuYXBpLnYxLlVzZXJXZWJob29rIkPaQQ5wYXJlbnQsd2ViaG9va4LT5JMCLDoHd2ViaG9vayIhL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L3dlYmhvb2tzEqgBChFVcGRhdGVVc2VyV2ViaG9vaxImLm1lbW9zLmFwaS52MS5VcGRhdGVVc2VyV2ViaG9va1JlcXVlc3QaGS5tZW1vcy5hcGkudjEuVXNlcldlYmhvb2siUNpBE3dlYmhvb2ssdXBkYXRlX21hc2uC0+STAjQ6B3dlYmhvb2syKS9hcGkvdjEve3dlYmhvb2submFtZT11c2Vycy8qL3dlYmhvb2tzLyp9EoUBChFEZWxldGVVc2VyV2ViaG9vaxImLm1lbW9zLmFwaS52MS5EZWxldGVVc2VyV2ViaG9va1JlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiMNpBBG5hbWWC0+STAiMqIS9hcGkvdjEve25hbWU9dXNlcnMvKi93ZWJob29rcy8qfRKpAQoVTGlzdFVzZXJOb3RpZmljYXRpb25zEioubWVtb3MuYXBpLnYxLkxpc3RVc2VyTm90aWZpY2F0aW9uc1JlcXVlc3QaKy5tZW1vcy5hcGkudjEuTGlzdFVzZXJOb3RpZmljYXRpb25zUmVzcG9uc2UiN9pBBnBhcmVudILT5JMCKBImL2FwaS92MS97cGFyZW50PXVzZXJzLyp9L25vdGlmaWNhdGlvbnMSywEKFlVwZGF0ZVVzZXJOb3RpZmljYXRpb24SKy5tZW1vcy5hcGkudjEuVXBkYXRlVXNlck5vdGlmaWNhdGlvblJlcXVlc3QaHi5tZW1vcy5hcGkudjEuVXNlck5vdGlmaWNhdGlvbiJk2kEYbm90aWZpY2F0aW9uLHVwZGF0ZV9tYXNrgtPkkwJDOgxub3RpZmljYXRpb24yMy9hcGkvdjEve25vdGlmaWNhdGlvbi5uYW1lPXVzZXJzLyovbm90aWZpY2F0aW9ucy8qfRKUAQoWRGVsZXRlVXNlck5vdGlmaWNhdGlvbhIrLm1lbW9zLmFwaS52MS5EZWxldGVVc2VyTm90aWZpY2F0aW9uUmVxdWVzdBoWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eSI12kEEbmFtZYLT5JMCKComL2FwaS92MS97bmFtZT11c2Vycy8qL25vdGlmaWNhdGlvbnMvKn1CqAEKEGNvbS5tZW1vcy5hcGkudjFCEFVzZXJTZXJ2aWNlUHJvdG9QAVowZ2l0aHViLmNvbS91c2VtZW1vcy9tZW1vcy9wcm90by9nZW4vYXBpL3YxO2FwaXYxogIDTUFYqgIMTWVtb3MuQXBpLlYxygIMTWVtb3NcQXBpXFYx4gIYTWVtb3NcQXBpXFYxXEdQQk1ldGFkYXRh6gIOTWVtb3M6OkFwaTo6VjFiBnByb3RvMw", [file_api_v1_common, file_google_api_annotations, file_google_api_client, file_google_api_field_behavior, file_google_api_resource, file_google_protobuf_empty, file_google_protobuf_field_mask, file_google_protobuf_timestamp]); /** * @generated from message memos.api.v1.User @@ -591,6 +591,13 @@ export type UserSetting_GeneralSetting = Message<"memos.api.v1.UserSetting.Gener * @generated from field: string theme = 4; */ theme: string; + + /** + * Auto-refresh interval in seconds. 0 = disabled, default = 30. + * + * @generated from field: int32 auto_refresh_interval = 5; + */ + autoRefreshInterval: number; }; /** From e90f3ce930619c57c0d97a135babad84f1b43e62 Mon Sep 17 00:00:00 2001 From: AobaIwaki Date: Mon, 15 Dec 2025 02:11:33 +0900 Subject: [PATCH 2/3] feat(hook): add useAutoRefresh hook --- web/src/helpers/consts.ts | 6 ++ web/src/hooks/index.ts | 1 + web/src/hooks/useAutoRefresh.ts | 128 ++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 web/src/hooks/useAutoRefresh.ts diff --git a/web/src/helpers/consts.ts b/web/src/helpers/consts.ts index 13c203dec..0d07b8267 100644 --- a/web/src/helpers/consts.ts +++ b/web/src/helpers/consts.ts @@ -3,3 +3,9 @@ export const TAB_SPACE_WIDTH = 2; // DEFAULT_LIST_MEMOS_PAGE_SIZE is the default page size for list memos request. export const DEFAULT_LIST_MEMOS_PAGE_SIZE = 16; + +// DEFAULT_AUTO_REFRESH_INTERVAL is the default auto-refresh interval in seconds. +export const DEFAULT_AUTO_REFRESH_INTERVAL = 10; + +// DEFAULT_MIN_AUTO_REFRESH_INTERVAL is the default minimum auto-refresh interval in seconds. +export const DEFAULT_MIN_AUTO_REFRESH_INTERVAL = 1; diff --git a/web/src/hooks/index.ts b/web/src/hooks/index.ts index bfd97a59b..667bf01e7 100644 --- a/web/src/hooks/index.ts +++ b/web/src/hooks/index.ts @@ -1,4 +1,5 @@ export * from "./useAsyncEffect"; +export * from "./useAutoRefresh"; export * from "./useCurrentUser"; export * from "./useFilteredMemoStats"; export * from "./useLoading"; diff --git a/web/src/hooks/useAutoRefresh.ts b/web/src/hooks/useAutoRefresh.ts new file mode 100644 index 000000000..cfbccfdee --- /dev/null +++ b/web/src/hooks/useAutoRefresh.ts @@ -0,0 +1,128 @@ +import { create } from "@bufbuild/protobuf"; +import { useCallback, useEffect, useRef } from "react"; +import { memoServiceClient } from "@/grpcweb"; +import { instanceStore } from "@/store"; +import { State } from "@/types/proto/api/v1/common_pb"; +import { ListMemosRequestSchema, Memo } from "@/types/proto/api/v1/memo_service_pb"; + +interface UseAutoRefreshOptions { + filter?: string; + orderBy?: string; + state?: State; + enabled?: boolean; + intervalSeconds: number; + onRefresh: () => Promise; +} + +const shouldSkipRefreshCheck = (isRefreshing: boolean): boolean => { + if (isRefreshing) return true; + if (document.hidden) return true; + if (!navigator.onLine) return true; + return false; +}; + +const checkMemoUpdate = ( + latestMemo: Memo | undefined, + previousUpdateTime: bigint | undefined, +): { shouldRefresh: boolean; newUpdateTime?: bigint } => { + if (!latestMemo) { + return { shouldRefresh: false }; + } + + const currentUpdateTime = latestMemo.updateTime?.seconds; + + if (previousUpdateTime === undefined) { + return { shouldRefresh: false, newUpdateTime: currentUpdateTime }; + } + + const hasNewerMemo = currentUpdateTime !== undefined && currentUpdateTime > previousUpdateTime; + return { + shouldRefresh: hasNewerMemo, + newUpdateTime: currentUpdateTime, + }; +}; + +const useAutoRefresh = (options: UseAutoRefreshOptions) => { + const { filter, orderBy, state = State.NORMAL, enabled = true, intervalSeconds, onRefresh } = options; + + const isAutoRefreshDisabled = intervalSeconds === 0; + + const latestUpdateTimeRef = useRef(undefined); + const isRefreshingRef = useRef(false); + + const optionsRef = useRef({ filter, orderBy, state, onRefresh }); + optionsRef.current = { filter, orderBy, state, onRefresh }; + + const checkForUpdates = useCallback(async () => { + if (shouldSkipRefreshCheck(isRefreshingRef.current)) { + return; + } + + const { filter, orderBy, state, onRefresh } = optionsRef.current; + + try { + const response = await memoServiceClient.listMemos( + create(ListMemosRequestSchema, { + pageSize: 1, + orderBy: orderBy || "display_time desc", + filter, + state, + }), + ); + + const latestMemo = response.memos[0]; + const { shouldRefresh, newUpdateTime } = checkMemoUpdate(latestMemo, latestUpdateTimeRef.current); + + if (newUpdateTime !== undefined) { + latestUpdateTimeRef.current = newUpdateTime; + } + + if (shouldRefresh) { + isRefreshingRef.current = true; + try { + await onRefresh(); + } finally { + isRefreshingRef.current = false; + } + } + } catch { + // Silently ignore polling errors + } + }, []); + + useEffect(() => { + if (!enabled || isAutoRefreshDisabled) { + return; + } + + checkForUpdates(); + + const intervalId = setInterval(checkForUpdates, intervalSeconds * 1000); + + const handleVisibilityChange = () => { + if (!document.hidden) { + checkForUpdates(); + } + }; + document.addEventListener("visibilitychange", handleVisibilityChange); + + const handleOnline = () => checkForUpdates(); + window.addEventListener("online", handleOnline); + + return () => { + clearInterval(intervalId); + document.removeEventListener("visibilitychange", handleVisibilityChange); + window.removeEventListener("online", handleOnline); + }; + }, [enabled, isAutoRefreshDisabled, intervalSeconds, checkForUpdates]); + + useEffect(() => { + latestUpdateTimeRef.current = undefined; + }, [filter, orderBy, state]); +}; + +export const isExploreAutoRefreshEnabled = (): boolean => { + return instanceStore.state.generalSetting?.enableExploreAutoRefresh !== false; +}; + +export default useAutoRefresh; \ No newline at end of file From 5ca4e46abda76fccf46af6b4ac6655e0cf4f49a0 Mon Sep 17 00:00:00 2001 From: AobaIwaki Date: Mon, 15 Dec 2025 02:12:36 +0900 Subject: [PATCH 3/3] feat(web): enable auto refresh on home and explore and add en,ja locales --- server/router/api/v1/instance_service.go | 32 +++++++++++-------- server/router/api/v1/user_service.go | 23 +++++++------ .../PagedMemoList/PagedMemoList.tsx | 21 ++++++++++-- .../components/Settings/InstanceSection.tsx | 22 +++++++++++++ .../Settings/PreferencesSection.tsx | 15 +++++++++ web/src/locales/en.json | 10 ++++-- web/src/locales/ja.json | 20 ++++++++---- web/src/pages/Explore.tsx | 6 +++- web/src/pages/Home.tsx | 2 ++ 9 files changed, 115 insertions(+), 36 deletions(-) diff --git a/server/router/api/v1/instance_service.go b/server/router/api/v1/instance_service.go index cf5798499..ec71589f0 100644 --- a/server/router/api/v1/instance_service.go +++ b/server/router/api/v1/instance_service.go @@ -156,13 +156,15 @@ func convertInstanceGeneralSettingFromStore(setting *storepb.InstanceGeneralSett } generalSetting := &v1pb.InstanceSetting_GeneralSetting{ - DisallowUserRegistration: setting.DisallowUserRegistration, - DisallowPasswordAuth: setting.DisallowPasswordAuth, - AdditionalScript: setting.AdditionalScript, - AdditionalStyle: setting.AdditionalStyle, - WeekStartDayOffset: setting.WeekStartDayOffset, - DisallowChangeUsername: setting.DisallowChangeUsername, - DisallowChangeNickname: setting.DisallowChangeNickname, + DisallowUserRegistration: setting.DisallowUserRegistration, + DisallowPasswordAuth: setting.DisallowPasswordAuth, + AdditionalScript: setting.AdditionalScript, + AdditionalStyle: setting.AdditionalStyle, + WeekStartDayOffset: setting.WeekStartDayOffset, + DisallowChangeUsername: setting.DisallowChangeUsername, + DisallowChangeNickname: setting.DisallowChangeNickname, + EnableExploreAutoRefresh: setting.EnableExploreAutoRefresh, + MinAutoRefreshInterval: setting.MinAutoRefreshInterval, } if setting.CustomProfile != nil { generalSetting.CustomProfile = &v1pb.InstanceSetting_GeneralSetting_CustomProfile{ @@ -179,13 +181,15 @@ func convertInstanceGeneralSettingToStore(setting *v1pb.InstanceSetting_GeneralS return nil } generalSetting := &storepb.InstanceGeneralSetting{ - DisallowUserRegistration: setting.DisallowUserRegistration, - DisallowPasswordAuth: setting.DisallowPasswordAuth, - AdditionalScript: setting.AdditionalScript, - AdditionalStyle: setting.AdditionalStyle, - WeekStartDayOffset: setting.WeekStartDayOffset, - DisallowChangeUsername: setting.DisallowChangeUsername, - DisallowChangeNickname: setting.DisallowChangeNickname, + DisallowUserRegistration: setting.DisallowUserRegistration, + DisallowPasswordAuth: setting.DisallowPasswordAuth, + AdditionalScript: setting.AdditionalScript, + AdditionalStyle: setting.AdditionalStyle, + WeekStartDayOffset: setting.WeekStartDayOffset, + DisallowChangeUsername: setting.DisallowChangeUsername, + DisallowChangeNickname: setting.DisallowChangeNickname, + EnableExploreAutoRefresh: setting.EnableExploreAutoRefresh, + MinAutoRefreshInterval: setting.MinAutoRefreshInterval, } if setting.CustomProfile != nil { generalSetting.CustomProfile = &storepb.InstanceCustomProfile{ diff --git a/server/router/api/v1/user_service.go b/server/router/api/v1/user_service.go index 349f4b957..9c4999fa4 100644 --- a/server/router/api/v1/user_service.go +++ b/server/router/api/v1/user_service.go @@ -396,9 +396,10 @@ func (s *APIV1Service) UpdateUserSetting(ctx context.Context, request *v1pb.Upda } updatedGeneral := &v1pb.UserSetting_GeneralSetting{ - MemoVisibility: generalSetting.GetMemoVisibility(), - Locale: generalSetting.GetLocale(), - Theme: generalSetting.GetTheme(), + MemoVisibility: generalSetting.GetMemoVisibility(), + Locale: generalSetting.GetLocale(), + Theme: generalSetting.GetTheme(), + AutoRefreshInterval: generalSetting.GetAutoRefreshInterval(), } // Apply updates for fields specified in the update mask @@ -411,6 +412,8 @@ func (s *APIV1Service) UpdateUserSetting(ctx context.Context, request *v1pb.Upda updatedGeneral.Theme = incomingGeneral.Theme case "locale": updatedGeneral.Locale = incomingGeneral.Locale + case "auto_refresh_interval": + updatedGeneral.AutoRefreshInterval = incomingGeneral.AutoRefreshInterval default: // Ignore unsupported fields } @@ -1263,9 +1266,10 @@ func convertUserSettingFromStore(storeSetting *storepb.UserSetting, userID int32 if general := storeSetting.GetGeneral(); general != nil { setting.Value = &v1pb.UserSetting_GeneralSetting_{ GeneralSetting: &v1pb.UserSetting_GeneralSetting{ - Locale: general.Locale, - MemoVisibility: general.MemoVisibility, - Theme: general.Theme, + Locale: general.Locale, + MemoVisibility: general.MemoVisibility, + Theme: general.Theme, + AutoRefreshInterval: general.AutoRefreshInterval, }, } } else { @@ -1351,9 +1355,10 @@ func convertUserSettingToStore(apiSetting *v1pb.UserSetting, userID int32, key s if general := apiSetting.GetGeneralSetting(); general != nil { storeSetting.Value = &storepb.UserSetting_General{ General: &storepb.GeneralUserSetting{ - Locale: general.Locale, - MemoVisibility: general.MemoVisibility, - Theme: general.Theme, + Locale: general.Locale, + MemoVisibility: general.MemoVisibility, + Theme: general.Theme, + AutoRefreshInterval: general.AutoRefreshInterval, }, } } else { diff --git a/web/src/components/PagedMemoList/PagedMemoList.tsx b/web/src/components/PagedMemoList/PagedMemoList.tsx index 1cb49178e..62c7978af 100644 --- a/web/src/components/PagedMemoList/PagedMemoList.tsx +++ b/web/src/components/PagedMemoList/PagedMemoList.tsx @@ -4,10 +4,11 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { matchPath } from "react-router-dom"; import PullToRefresh from "react-simple-pull-to-refresh"; import { Button } from "@/components/ui/button"; -import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts"; +import { DEFAULT_AUTO_REFRESH_INTERVAL, DEFAULT_LIST_MEMOS_PAGE_SIZE, DEFAULT_MIN_AUTO_REFRESH_INTERVAL } from "@/helpers/consts"; import useResponsiveWidth from "@/hooks/useResponsiveWidth"; +import useAutoRefresh from "@/hooks/useAutoRefresh"; import { Routes } from "@/router"; -import { memoStore, userStore, viewStore } from "@/store"; +import { instanceStore, memoStore, userStore, viewStore } from "@/store"; import { State } from "@/types/proto/api/v1/common_pb"; import type { Memo } from "@/types/proto/api/v1/memo_service_pb"; import { useTranslate } from "@/utils/i18n"; @@ -26,6 +27,7 @@ interface Props { filter?: string; pageSize?: number; showCreator?: boolean; + autoRefresh?: boolean; } const PagedMemoList = observer((props: Props) => { @@ -161,10 +163,25 @@ const PagedMemoList = observer((props: Props) => { } }; + window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, [nextPageToken, isRequesting, fetchMoreMemos]); + const userInterval = userStore.state.userGeneralSetting?.autoRefreshInterval ?? DEFAULT_AUTO_REFRESH_INTERVAL; + const minInterval = instanceStore.state.generalSetting?.minAutoRefreshInterval ?? DEFAULT_MIN_AUTO_REFRESH_INTERVAL; + const effectiveInterval = userInterval === 0 ? 0 : Math.max(userInterval, minInterval); + + // Auto-refresh: periodically check for new memos and refresh the list + useAutoRefresh({ + state: props.state || State.NORMAL, + orderBy: props.orderBy || "display_time desc", + filter: props.filter, + enabled: props.autoRefresh ?? false, + intervalSeconds: effectiveInterval, + onRefresh: refreshList, + }); + const children = (
{/* Show skeleton loader during initial load */} diff --git a/web/src/components/Settings/InstanceSection.tsx b/web/src/components/Settings/InstanceSection.tsx index a81b5656e..6c65ed5d3 100644 --- a/web/src/components/Settings/InstanceSection.tsx +++ b/web/src/components/Settings/InstanceSection.tsx @@ -4,6 +4,7 @@ import { observer } from "mobx-react-lite"; import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; @@ -170,6 +171,27 @@ const InstanceSection = observer(() => { + + + updatePartialSetting({ enableExploreAutoRefresh: checked })} + /> + + + +
+ { + const value = parseInt(e.target.value) || 1; + updatePartialSetting({ minAutoRefreshInterval: value }); + }} + /> + {t("setting.preference-section.seconds")} +
+
diff --git a/web/src/components/Settings/PreferencesSection.tsx b/web/src/components/Settings/PreferencesSection.tsx index 1b11cfe37..0f5386ae9 100644 --- a/web/src/components/Settings/PreferencesSection.tsx +++ b/web/src/components/Settings/PreferencesSection.tsx @@ -1,5 +1,6 @@ import { create } from "@bufbuild/protobuf"; import { observer } from "mobx-react-lite"; +import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { userStore } from "@/store"; import { Visibility } from "@/types/proto/api/v1/memo_service_pb"; @@ -78,6 +79,20 @@ const PreferencesSection = observer(() => { + + +
+ { + const value = parseInt(e.target.value) || 0; + await userStore.updateUserGeneralSetting({ autoRefreshInterval: value }, ["auto_refresh_interval"]); + }} + /> + {t("setting.preference-section.seconds")} +
+
diff --git a/web/src/locales/en.json b/web/src/locales/en.json index 757bc0db4..979024837 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -330,7 +330,9 @@ "preference-section": { "default-memo-sort-option": "Memo display time", "default-memo-visibility": "Default memo visibility", - "theme": "Theme" + "theme": "Theme", + "auto-refresh-interval": "Auto-refresh interval", + "seconds": "seconds" }, "shortcut": { "delete-confirm": "Are you sure you want to delete shortcut `{{title}}`?", @@ -452,7 +454,9 @@ "monday": "Monday", "saturday": "Saturday", "sunday": "Sunday", - "week-start-day": "Week start day" + "week-start-day": "Week start day", + "enable-explore-auto-refresh": "Enable Explore page auto-refresh", + "min-auto-refresh-interval": "Minimum auto-refresh interval" } }, "tag": { @@ -479,4 +483,4 @@ "tags": "Tags", "upload-attachment": "Upload Attachment(s)" } -} +} \ No newline at end of file diff --git a/web/src/locales/ja.json b/web/src/locales/ja.json index 680206966..76c11699b 100644 --- a/web/src/locales/ja.json +++ b/web/src/locales/ja.json @@ -18,7 +18,7 @@ "about": "Memos について", "add": "追加", "admin": "管理者設定", - "archive": "アーカイブにする", + "archive": "アーカイブする", "archived": "ゴミ箱", "attachments": "添付ファイル", "avatar": "アイコン", @@ -30,6 +30,7 @@ "close": "閉じる", "collapse": "折りたたむ", "confirm": "確認する", + "copy": "コピー", "create": "作成する", "created-at": "作成日時", "database": "データベース", @@ -99,7 +100,7 @@ "username": "ユーザーネーム", "version": "バージョン", "visibility": "公開範囲", - "yourself": "あなた自身の" + "yourself": "あなた自身" }, "days": { "fri": "金", @@ -132,14 +133,15 @@ }, "memo": { "archived-at": "アーカイブ:", - "click-to-hide-nsfw-content": "クリックしてセンシティブ内容を隠す", - "click-to-show-nsfw-content": "クリックしてセンシティブ内容を表示", + "click-to-hide-nsfw-content": "クリックしてセンシティブな内容を隠す", + "click-to-show-nsfw-content": "クリックしてセンシティブな内容を表示", "code": "コード", "comment": { "self": "コメント", "write-a-comment": "コメントを書く" }, "copy-link": "リンクをコピー", + "copy-content": "内容をコピー", "count-memos-in-date": "{{date}} 日に {{count}} 件のメモ", "delete-confirm": "本当に削除しますか? この操作は元に戻せません。", "direction": "並び順", @@ -293,7 +295,7 @@ "memo-related": "Memo", "memo-related-settings": { "content-lenght-limit": "内容の最大長(バイト)", - "enable-blur-nsfw-content": "センシティブ(NSFW)内容のぼかしを有効化", + "enable-blur-nsfw-content": "センシティブ(NSFW)な内容のぼかしを有効化", "enable-memo-comments": "メモコメントを有効化", "enable-memo-location": "メモの位置情報を有効化", "reactions": "リアクション", @@ -304,7 +306,9 @@ "preference-section": { "default-memo-sort-option": "メモの表示時間", "default-memo-visibility": "公開範囲の初期設定", - "theme": "テーマ" + "theme": "テーマ", + "auto-refresh-interval": "更新の間隔", + "seconds": "秒" }, "sso": "SSO", "sso-section": { @@ -416,7 +420,9 @@ "monday": "月曜日", "saturday": "土曜日", "sunday": "日曜日", - "week-start-day": "週の開始日" + "week-start-day": "週の開始日", + "enable-explore-auto-refresh": "共有メモページのオートリロードを有効化", + "min-auto-refresh-interval": "オートリロード間隔の最小値を設定" } }, "tag": { diff --git a/web/src/pages/Explore.tsx b/web/src/pages/Explore.tsx index 9d4b85e5a..7cf784e8c 100644 --- a/web/src/pages/Explore.tsx +++ b/web/src/pages/Explore.tsx @@ -2,7 +2,7 @@ import { observer } from "mobx-react-lite"; import { MemoRenderContext } from "@/components/MasonryView"; import MemoView from "@/components/MemoView"; import PagedMemoList from "@/components/PagedMemoList"; -import { useMemoFilters, useMemoSorting } from "@/hooks"; +import { useMemoFilters, useMemoSorting, isExploreAutoRefreshEnabled } from "@/hooks"; import useCurrentUser from "@/hooks/useCurrentUser"; import { State } from "@/types/proto/api/v1/common_pb"; import { Memo, Visibility } from "@/types/proto/api/v1/memo_service_pb"; @@ -29,6 +29,8 @@ const Explore = observer(() => { state: State.NORMAL, }); + const enableAutoRefresh = isExploreAutoRefreshEnabled(); + return ( ( @@ -38,8 +40,10 @@ const Explore = observer(() => { orderBy={orderBy} filter={memoFilter} showCreator + autoRefresh={enableAutoRefresh} /> ); }); export default Explore; + diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index e3ab86b73..2732c007e 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -32,9 +32,11 @@ const Home = observer(() => { listSort={listSort} orderBy={orderBy} filter={memoFilter} + autoRefresh />
); }); export default Home; +