From ef41d34d5312b6a3bcc4af536f64275cd20da657 Mon Sep 17 00:00:00 2001 From: garethgeorge Date: Mon, 19 Feb 2024 22:28:55 -0800 Subject: [PATCH] fix: migrate prune policy options to oneof --- gen/go/v1/config.pb.go | 547 ++++++++++++------ internal/config/migrations/001prunepolicy.go | 41 ++ .../config/migrations/001prunepolicy_test.go | 111 ++++ internal/config/migrations/migrations.go | 10 + proto/v1/config.proto | 34 +- webui/gen/ts/v1/config_pb.ts | 145 ++++- webui/src/components/OperationList.tsx | 1 - 7 files changed, 681 insertions(+), 208 deletions(-) create mode 100644 internal/config/migrations/001prunepolicy.go create mode 100644 internal/config/migrations/001prunepolicy_test.go create mode 100644 internal/config/migrations/migrations.go diff --git a/gen/go/v1/config.pb.go b/gen/go/v1/config.pb.go index d2c9e6f7..287e82a5 100644 --- a/gen/go/v1/config.pb.go +++ b/gen/go/v1/config.pb.go @@ -82,7 +82,8 @@ type Config struct { unknownFields protoimpl.UnknownFields // modification number, used for read-modify-write consistency in the UI. Incremented on every write. - Modno int32 `protobuf:"varint,1,opt,name=modno,proto3" json:"modno,omitempty"` + Modno int32 `protobuf:"varint,1,opt,name=modno,proto3" json:"modno,omitempty"` + Version int32 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` // version of the config file format. Used to determine when to run migrations. // override the hostname tagged on backups. If provided it will be used in addition to tags to group backups. Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` Repos []*Repo `protobuf:"bytes,3,rep,name=repos,proto3" json:"repos,omitempty"` @@ -129,6 +130,13 @@ func (x *Config) GetModno() int32 { return 0 } +func (x *Config) GetVersion() int32 { + if x != nil { + return x.Version + } + return 0 +} + func (x *Config) GetHost() string { if x != nil { return x.Host @@ -368,15 +376,28 @@ type RetentionPolicy struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // max_unused_limit is used to decide when forget should be run. - MaxUnusedLimit string `protobuf:"bytes,1,opt,name=max_unused_limit,json=maxUnusedLimit,proto3" json:"max_unused_limit,omitempty"` // e.g. a percentage i.e. 25% or a number of megabytes. - KeepLastN int32 `protobuf:"varint,2,opt,name=keep_last_n,json=keepLastN,proto3" json:"keep_last_n,omitempty"` // keep the last n snapshots. - KeepHourly int32 `protobuf:"varint,3,opt,name=keep_hourly,json=keepHourly,proto3" json:"keep_hourly,omitempty"` // keep the last n hourly snapshots. - KeepDaily int32 `protobuf:"varint,4,opt,name=keep_daily,json=keepDaily,proto3" json:"keep_daily,omitempty"` // keep the last n daily snapshots. - KeepWeekly int32 `protobuf:"varint,5,opt,name=keep_weekly,json=keepWeekly,proto3" json:"keep_weekly,omitempty"` // keep the last n weekly snapshots. - KeepMonthly int32 `protobuf:"varint,6,opt,name=keep_monthly,json=keepMonthly,proto3" json:"keep_monthly,omitempty"` // keep the last n monthly snapshots. - KeepYearly int32 `protobuf:"varint,7,opt,name=keep_yearly,json=keepYearly,proto3" json:"keep_yearly,omitempty"` // keep the last n yearly snapshots. + // Deprecated: Marked as deprecated in v1/config.proto. + MaxUnusedLimit string `protobuf:"bytes,1,opt,name=max_unused_limit,json=maxUnusedLimit,proto3" json:"max_unused_limit,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. + KeepLastN int32 `protobuf:"varint,2,opt,name=keep_last_n,json=keepLastN,proto3" json:"keep_last_n,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. + KeepHourly int32 `protobuf:"varint,3,opt,name=keep_hourly,json=keepHourly,proto3" json:"keep_hourly,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. + KeepDaily int32 `protobuf:"varint,4,opt,name=keep_daily,json=keepDaily,proto3" json:"keep_daily,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. + KeepWeekly int32 `protobuf:"varint,5,opt,name=keep_weekly,json=keepWeekly,proto3" json:"keep_weekly,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. + KeepMonthly int32 `protobuf:"varint,6,opt,name=keep_monthly,json=keepMonthly,proto3" json:"keep_monthly,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. + KeepYearly int32 `protobuf:"varint,7,opt,name=keep_yearly,json=keepYearly,proto3" json:"keep_yearly,omitempty"` + // Deprecated: Marked as deprecated in v1/config.proto. KeepWithinDuration string `protobuf:"bytes,8,opt,name=keep_within_duration,json=keepWithinDuration,proto3" json:"keep_within_duration,omitempty"` // keep snapshots within a duration e.g. 1y2m3d4h5m6s + // Types that are assignable to Policy: + // + // *RetentionPolicy_PolicyKeepLastN + // *RetentionPolicy_PolicyTimeBucketed + // *RetentionPolicy_PolicyKeepAll + Policy isRetentionPolicy_Policy `protobuf_oneof:"policy"` } func (x *RetentionPolicy) Reset() { @@ -411,6 +432,7 @@ func (*RetentionPolicy) Descriptor() ([]byte, []int) { return file_v1_config_proto_rawDescGZIP(), []int{3} } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetMaxUnusedLimit() string { if x != nil { return x.MaxUnusedLimit @@ -418,6 +440,7 @@ func (x *RetentionPolicy) GetMaxUnusedLimit() string { return "" } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepLastN() int32 { if x != nil { return x.KeepLastN @@ -425,6 +448,7 @@ func (x *RetentionPolicy) GetKeepLastN() int32 { return 0 } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepHourly() int32 { if x != nil { return x.KeepHourly @@ -432,6 +456,7 @@ func (x *RetentionPolicy) GetKeepHourly() int32 { return 0 } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepDaily() int32 { if x != nil { return x.KeepDaily @@ -439,6 +464,7 @@ func (x *RetentionPolicy) GetKeepDaily() int32 { return 0 } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepWeekly() int32 { if x != nil { return x.KeepWeekly @@ -446,6 +472,7 @@ func (x *RetentionPolicy) GetKeepWeekly() int32 { return 0 } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepMonthly() int32 { if x != nil { return x.KeepMonthly @@ -453,6 +480,7 @@ func (x *RetentionPolicy) GetKeepMonthly() int32 { return 0 } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepYearly() int32 { if x != nil { return x.KeepYearly @@ -460,6 +488,7 @@ func (x *RetentionPolicy) GetKeepYearly() int32 { return 0 } +// Deprecated: Marked as deprecated in v1/config.proto. func (x *RetentionPolicy) GetKeepWithinDuration() string { if x != nil { return x.KeepWithinDuration @@ -467,6 +496,56 @@ func (x *RetentionPolicy) GetKeepWithinDuration() string { return "" } +func (m *RetentionPolicy) GetPolicy() isRetentionPolicy_Policy { + if m != nil { + return m.Policy + } + return nil +} + +func (x *RetentionPolicy) GetPolicyKeepLastN() int32 { + if x, ok := x.GetPolicy().(*RetentionPolicy_PolicyKeepLastN); ok { + return x.PolicyKeepLastN + } + return 0 +} + +func (x *RetentionPolicy) GetPolicyTimeBucketed() *RetentionPolicy_TimeBucketedCounts { + if x, ok := x.GetPolicy().(*RetentionPolicy_PolicyTimeBucketed); ok { + return x.PolicyTimeBucketed + } + return nil +} + +func (x *RetentionPolicy) GetPolicyKeepAll() bool { + if x, ok := x.GetPolicy().(*RetentionPolicy_PolicyKeepAll); ok { + return x.PolicyKeepAll + } + return false +} + +type isRetentionPolicy_Policy interface { + isRetentionPolicy_Policy() +} + +type RetentionPolicy_PolicyKeepLastN struct { + PolicyKeepLastN int32 `protobuf:"varint,10,opt,name=policy_keep_last_n,json=policyKeepLastN,proto3,oneof"` +} + +type RetentionPolicy_PolicyTimeBucketed struct { + PolicyTimeBucketed *RetentionPolicy_TimeBucketedCounts `protobuf:"bytes,11,opt,name=policy_time_bucketed,json=policyTimeBucketed,proto3,oneof"` +} + +type RetentionPolicy_PolicyKeepAll struct { + PolicyKeepAll bool `protobuf:"varint,12,opt,name=policy_keep_all,json=policyKeepAll,proto3,oneof"` +} + +func (*RetentionPolicy_PolicyKeepLastN) isRetentionPolicy_Policy() {} + +func (*RetentionPolicy_PolicyTimeBucketed) isRetentionPolicy_Policy() {} + +func (*RetentionPolicy_PolicyKeepAll) isRetentionPolicy_Policy() {} + type PrunePolicy struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -783,6 +862,85 @@ type User_PasswordBcrypt struct { func (*User_PasswordBcrypt) isUser_Password() {} +type RetentionPolicy_TimeBucketedCounts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hourly int32 `protobuf:"varint,1,opt,name=hourly,proto3" json:"hourly,omitempty"` // keep the last n hourly snapshots. + Daily int32 `protobuf:"varint,2,opt,name=daily,proto3" json:"daily,omitempty"` // keep the last n daily snapshots. + Weekly int32 `protobuf:"varint,3,opt,name=weekly,proto3" json:"weekly,omitempty"` // keep the last n weekly snapshots. + Monthly int32 `protobuf:"varint,4,opt,name=monthly,proto3" json:"monthly,omitempty"` // keep the last n monthly snapshots. + Yearly int32 `protobuf:"varint,5,opt,name=yearly,proto3" json:"yearly,omitempty"` // keep the last n yearly snapshots. +} + +func (x *RetentionPolicy_TimeBucketedCounts) Reset() { + *x = RetentionPolicy_TimeBucketedCounts{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_config_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RetentionPolicy_TimeBucketedCounts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RetentionPolicy_TimeBucketedCounts) ProtoMessage() {} + +func (x *RetentionPolicy_TimeBucketedCounts) ProtoReflect() protoreflect.Message { + mi := &file_v1_config_proto_msgTypes[8] + 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 RetentionPolicy_TimeBucketedCounts.ProtoReflect.Descriptor instead. +func (*RetentionPolicy_TimeBucketedCounts) Descriptor() ([]byte, []int) { + return file_v1_config_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *RetentionPolicy_TimeBucketedCounts) GetHourly() int32 { + if x != nil { + return x.Hourly + } + return 0 +} + +func (x *RetentionPolicy_TimeBucketedCounts) GetDaily() int32 { + if x != nil { + return x.Daily + } + return 0 +} + +func (x *RetentionPolicy_TimeBucketedCounts) GetWeekly() int32 { + if x != nil { + return x.Weekly + } + return 0 +} + +func (x *RetentionPolicy_TimeBucketedCounts) GetMonthly() int32 { + if x != nil { + return x.Monthly + } + return 0 +} + +func (x *RetentionPolicy_TimeBucketedCounts) GetYearly() int32 { + if x != nil { + return x.Yearly + } + return 0 +} + type Hook_Command struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -794,7 +952,7 @@ type Hook_Command struct { func (x *Hook_Command) Reset() { *x = Hook_Command{} if protoimpl.UnsafeEnabled { - mi := &file_v1_config_proto_msgTypes[8] + mi := &file_v1_config_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -807,7 +965,7 @@ func (x *Hook_Command) String() string { func (*Hook_Command) ProtoMessage() {} func (x *Hook_Command) ProtoReflect() protoreflect.Message { - mi := &file_v1_config_proto_msgTypes[8] + mi := &file_v1_config_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -841,7 +999,7 @@ type Hook_Webhook struct { func (x *Hook_Webhook) Reset() { *x = Hook_Webhook{} if protoimpl.UnsafeEnabled { - mi := &file_v1_config_proto_msgTypes[9] + mi := &file_v1_config_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -854,7 +1012,7 @@ func (x *Hook_Webhook) String() string { func (*Hook_Webhook) ProtoMessage() {} func (x *Hook_Webhook) ProtoReflect() protoreflect.Message { - mi := &file_v1_config_proto_msgTypes[9] + mi := &file_v1_config_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -889,7 +1047,7 @@ type Hook_Discord struct { func (x *Hook_Discord) Reset() { *x = Hook_Discord{} if protoimpl.UnsafeEnabled { - mi := &file_v1_config_proto_msgTypes[10] + mi := &file_v1_config_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -902,7 +1060,7 @@ func (x *Hook_Discord) String() string { func (*Hook_Discord) ProtoMessage() {} func (x *Hook_Discord) ProtoReflect() protoreflect.Message { - mi := &file_v1_config_proto_msgTypes[10] + mi := &file_v1_config_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -946,7 +1104,7 @@ type Hook_Gotify struct { func (x *Hook_Gotify) Reset() { *x = Hook_Gotify{} if protoimpl.UnsafeEnabled { - mi := &file_v1_config_proto_msgTypes[11] + mi := &file_v1_config_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -959,7 +1117,7 @@ func (x *Hook_Gotify) String() string { func (*Hook_Gotify) ProtoMessage() {} func (x *Hook_Gotify) ProtoReflect() protoreflect.Message { - mi := &file_v1_config_proto_msgTypes[11] + mi := &file_v1_config_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1015,7 +1173,7 @@ type Hook_Slack struct { func (x *Hook_Slack) Reset() { *x = Hook_Slack{} if protoimpl.UnsafeEnabled { - mi := &file_v1_config_proto_msgTypes[12] + mi := &file_v1_config_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1028,7 +1186,7 @@ func (x *Hook_Slack) String() string { func (*Hook_Slack) ProtoMessage() {} func (x *Hook_Slack) ProtoReflect() protoreflect.Message { - mi := &file_v1_config_proto_msgTypes[12] + mi := &file_v1_config_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1062,138 +1220,162 @@ var File_v1_config_proto protoreflect.FileDescriptor var file_v1_config_proto_rawDesc = []byte{ 0x0a, 0x0f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0x90, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0xaa, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x72, 0x65, - 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x70, 0x6f, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x6c, - 0x61, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x6c, 0x61, 0x6e, 0x52, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, - 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, - 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0xe1, 0x01, 0x0a, 0x04, 0x52, 0x65, 0x70, - 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, - 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, - 0x76, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x70, 0x72, 0x75, 0x6e, 0x65, - 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0b, - 0x70, 0x72, 0x75, 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x0a, 0x05, 0x68, - 0x6f, 0x6f, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, - 0x48, 0x6f, 0x6f, 0x6b, 0x52, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, - 0x75, 0x74, 0x6f, 0x5f, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xe1, 0x01, 0x0a, - 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, - 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, - 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, - 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x31, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x52, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, - 0x22, 0xb2, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, - 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1e, - 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, 0x12, 0x1f, - 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x48, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x12, - 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x1f, - 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x12, - 0x21, 0x0a, 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x6f, 0x6e, 0x74, 0x68, - 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x6c, - 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x59, 0x65, 0x61, - 0x72, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77, 0x69, 0x74, 0x68, - 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x12, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x93, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x44, - 0x61, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, - 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x10, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x65, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, - 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd5, 0x06, 0x0a, 0x04, - 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, - 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, - 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x65, - 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x65, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, - 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x48, 0x00, 0x52, - 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x39, - 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, - 0x18, 0x66, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, - 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x0d, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x67, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x47, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x12, 0x33, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6c, 0x61, 0x63, - 0x6b, 0x18, 0x68, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, - 0x6b, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x1a, 0x23, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x2a, 0x0a, 0x07, 0x57, - 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, - 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, - 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x1a, 0x46, 0x0a, 0x07, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x72, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, - 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, - 0x7c, 0x0a, 0x06, 0x47, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, - 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x73, - 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x5f, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x0a, - 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, - 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, - 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x44, - 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4e, 0x59, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, - 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, - 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x02, 0x12, - 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, - 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x43, - 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, - 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x05, 0x75, - 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x04, 0x55, - 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x0e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x2c, - 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, - 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65, - 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x05, 0x72, + 0x65, 0x70, 0x6f, 0x73, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x05, 0x70, + 0x6c, 0x61, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, + 0x74, 0x68, 0x22, 0xe1, 0x01, 0x0a, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x14, 0x0a, 0x05, 0x66, + 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, + 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x75, + 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0b, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x18, 0x07, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x52, 0x05, + 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x75, 0x6e, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, + 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xe1, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, + 0x65, 0x70, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, + 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, + 0x6f, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, + 0x6f, 0x6f, 0x6b, 0x52, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0xa0, 0x05, 0x0a, 0x0f, 0x52, + 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, + 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x6d, 0x61, + 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x22, 0x0a, 0x0b, + 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, + 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x48, + 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61, + 0x69, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6b, + 0x65, 0x65, 0x70, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, + 0x5f, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x12, 0x25, 0x0a, + 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x6f, 0x6e, + 0x74, 0x68, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x79, 0x65, 0x61, + 0x72, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6b, + 0x65, 0x65, 0x70, 0x59, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x14, 0x6b, 0x65, 0x65, + 0x70, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x6b, 0x65, 0x65, + 0x70, 0x57, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x2d, 0x0a, 0x12, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, 0x12, 0x5a, + 0x0a, 0x14, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x62, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x73, 0x48, 0x00, 0x52, 0x12, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x69, + 0x6d, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4b, 0x65, 0x65, + 0x70, 0x41, 0x6c, 0x6c, 0x1a, 0x8c, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x68, + 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x6f, 0x75, + 0x72, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x65, + 0x6b, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x77, 0x65, 0x65, 0x6b, 0x6c, + 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x07, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x79, + 0x65, 0x61, 0x72, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x79, 0x65, 0x61, + 0x72, 0x6c, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x93, 0x01, + 0x0a, 0x0b, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, 0x0a, + 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x64, + 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x46, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x61, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6d, + 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, + 0x65, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, + 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x65, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x22, 0xd5, 0x06, 0x0a, 0x04, 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x32, 0x0a, 0x0a, + 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, + 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, + 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0e, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x65, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x57, 0x65, + 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x57, + 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x66, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, + 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, + 0x64, 0x12, 0x36, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x18, 0x67, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, + 0x6f, 0x6b, 0x2e, 0x47, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x47, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x33, 0x0a, 0x0c, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x18, 0x68, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x48, + 0x00, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x1a, 0x23, + 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x1a, 0x2a, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x1f, + 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x1a, + 0x46, 0x0a, 0x07, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65, + 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x7c, 0x0a, 0x06, 0x47, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x64, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x25, + 0x0a, 0x0e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x1f, + 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, + 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x09, + 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4e, + 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4e, + 0x59, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4e, + 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, + 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x44, 0x49, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x4e, + 0x44, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, + 0x04, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x04, 0x41, + 0x75, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x29, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x62, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, + 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, + 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1209,7 +1391,7 @@ func file_v1_config_proto_rawDescGZIP() []byte { } var file_v1_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_v1_config_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_v1_config_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_v1_config_proto_goTypes = []interface{}{ (Hook_Condition)(0), // 0: v1.Hook.Condition (*Config)(nil), // 1: v1.Config @@ -1220,11 +1402,12 @@ var file_v1_config_proto_goTypes = []interface{}{ (*Hook)(nil), // 6: v1.Hook (*Auth)(nil), // 7: v1.Auth (*User)(nil), // 8: v1.User - (*Hook_Command)(nil), // 9: v1.Hook.Command - (*Hook_Webhook)(nil), // 10: v1.Hook.Webhook - (*Hook_Discord)(nil), // 11: v1.Hook.Discord - (*Hook_Gotify)(nil), // 12: v1.Hook.Gotify - (*Hook_Slack)(nil), // 13: v1.Hook.Slack + (*RetentionPolicy_TimeBucketedCounts)(nil), // 9: v1.RetentionPolicy.TimeBucketedCounts + (*Hook_Command)(nil), // 10: v1.Hook.Command + (*Hook_Webhook)(nil), // 11: v1.Hook.Webhook + (*Hook_Discord)(nil), // 12: v1.Hook.Discord + (*Hook_Gotify)(nil), // 13: v1.Hook.Gotify + (*Hook_Slack)(nil), // 14: v1.Hook.Slack } var file_v1_config_proto_depIdxs = []int32{ 2, // 0: v1.Config.repos:type_name -> v1.Repo @@ -1234,18 +1417,19 @@ var file_v1_config_proto_depIdxs = []int32{ 6, // 4: v1.Repo.hooks:type_name -> v1.Hook 4, // 5: v1.Plan.retention:type_name -> v1.RetentionPolicy 6, // 6: v1.Plan.hooks:type_name -> v1.Hook - 0, // 7: v1.Hook.conditions:type_name -> v1.Hook.Condition - 9, // 8: v1.Hook.action_command:type_name -> v1.Hook.Command - 10, // 9: v1.Hook.action_webhook:type_name -> v1.Hook.Webhook - 11, // 10: v1.Hook.action_discord:type_name -> v1.Hook.Discord - 12, // 11: v1.Hook.action_gotify:type_name -> v1.Hook.Gotify - 13, // 12: v1.Hook.action_slack:type_name -> v1.Hook.Slack - 8, // 13: v1.Auth.users:type_name -> v1.User - 14, // [14:14] is the sub-list for method output_type - 14, // [14:14] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 9, // 7: v1.RetentionPolicy.policy_time_bucketed:type_name -> v1.RetentionPolicy.TimeBucketedCounts + 0, // 8: v1.Hook.conditions:type_name -> v1.Hook.Condition + 10, // 9: v1.Hook.action_command:type_name -> v1.Hook.Command + 11, // 10: v1.Hook.action_webhook:type_name -> v1.Hook.Webhook + 12, // 11: v1.Hook.action_discord:type_name -> v1.Hook.Discord + 13, // 12: v1.Hook.action_gotify:type_name -> v1.Hook.Gotify + 14, // 13: v1.Hook.action_slack:type_name -> v1.Hook.Slack + 8, // 14: v1.Auth.users:type_name -> v1.User + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_v1_config_proto_init() } @@ -1351,7 +1535,7 @@ func file_v1_config_proto_init() { } } file_v1_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hook_Command); i { + switch v := v.(*RetentionPolicy_TimeBucketedCounts); i { case 0: return &v.state case 1: @@ -1363,7 +1547,7 @@ func file_v1_config_proto_init() { } } file_v1_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hook_Webhook); i { + switch v := v.(*Hook_Command); i { case 0: return &v.state case 1: @@ -1375,7 +1559,7 @@ func file_v1_config_proto_init() { } } file_v1_config_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hook_Discord); i { + switch v := v.(*Hook_Webhook); i { case 0: return &v.state case 1: @@ -1387,7 +1571,7 @@ func file_v1_config_proto_init() { } } file_v1_config_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hook_Gotify); i { + switch v := v.(*Hook_Discord); i { case 0: return &v.state case 1: @@ -1399,6 +1583,18 @@ func file_v1_config_proto_init() { } } file_v1_config_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Hook_Gotify); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_config_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Hook_Slack); i { case 0: return &v.state @@ -1411,6 +1607,11 @@ func file_v1_config_proto_init() { } } } + file_v1_config_proto_msgTypes[3].OneofWrappers = []interface{}{ + (*RetentionPolicy_PolicyKeepLastN)(nil), + (*RetentionPolicy_PolicyTimeBucketed)(nil), + (*RetentionPolicy_PolicyKeepAll)(nil), + } file_v1_config_proto_msgTypes[5].OneofWrappers = []interface{}{ (*Hook_ActionCommand)(nil), (*Hook_ActionWebhook)(nil), @@ -1427,7 +1628,7 @@ func file_v1_config_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_v1_config_proto_rawDesc, NumEnums: 1, - NumMessages: 13, + NumMessages: 14, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/config/migrations/001prunepolicy.go b/internal/config/migrations/001prunepolicy.go new file mode 100644 index 00000000..db779479 --- /dev/null +++ b/internal/config/migrations/001prunepolicy.go @@ -0,0 +1,41 @@ +package migrations + +import v1 "github.com/garethgeorge/backrest/gen/go/v1" + +func migration001PrunePolicy(config *v1.Config) { + // loop over plans and examine prune policy's + for _, plan := range config.Plans { + policy := plan.GetRetention() + if policy == nil { + continue + } + + if policy.Policy != nil { + continue // already migrated + } + + if policy.KeepLastN != 0 { + plan.Retention = &v1.RetentionPolicy{ + Policy: &v1.RetentionPolicy_PolicyKeepLastN{ + PolicyKeepLastN: policy.KeepLastN, + }, + } + } else if policy.KeepDaily != 0 || policy.KeepHourly != 0 || policy.KeepMonthly != 0 || policy.KeepWeekly != 0 || policy.KeepYearly != 0 { + plan.Retention = &v1.RetentionPolicy{ + Policy: &v1.RetentionPolicy_PolicyTimeBucketed{ + PolicyTimeBucketed: &v1.RetentionPolicy_TimeBucketedCounts{ + Hourly: policy.KeepHourly, + Daily: policy.KeepDaily, + Weekly: policy.KeepWeekly, + Monthly: policy.KeepMonthly, + Yearly: policy.KeepYearly, + }, + }, + } + } else { + policy.Policy = &v1.RetentionPolicy_PolicyKeepAll{ + PolicyKeepAll: true, + } + } + } +} diff --git a/internal/config/migrations/001prunepolicy_test.go b/internal/config/migrations/001prunepolicy_test.go new file mode 100644 index 00000000..1b3b97fc --- /dev/null +++ b/internal/config/migrations/001prunepolicy_test.go @@ -0,0 +1,111 @@ +package migrations + +import ( + "testing" + + v1 "github.com/garethgeorge/backrest/gen/go/v1" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +func Test001Migration(t *testing.T) { + cases := []struct { + name string + config string + want *v1.Config + }{ + { + name: "time bucketed policy", + config: `{ + "plans": [ + { + "retention": { + "keepHourly": 1, + "keepDaily": 2, + "keepWeekly": 3, + "keepMonthly": 4, + "keepYearly": 5 + } + } + ] + }`, + want: &v1.Config{ + Plans: []*v1.Plan{ + { + Retention: &v1.RetentionPolicy{ + Policy: &v1.RetentionPolicy_PolicyTimeBucketed{ + PolicyTimeBucketed: &v1.RetentionPolicy_TimeBucketedCounts{ + Hourly: 1, + Daily: 2, + Weekly: 3, + Monthly: 4, + Yearly: 5, + }, + }, + }, + }, + }, + }, + }, + { + name: "keep all policy", + config: `{ + "plans": [ + { + "retention": {} + } + ] + }`, + want: &v1.Config{ + Plans: []*v1.Plan{ + { + Retention: &v1.RetentionPolicy{ + Policy: &v1.RetentionPolicy_PolicyKeepAll{ + PolicyKeepAll: true, + }, + }, + }, + }, + }, + }, + { + name: "keep by count", + config: `{ + "plans": [ + { + "retention": { + "keepLastN": 5 + } + } + ] + }`, + want: &v1.Config{ + Plans: []*v1.Plan{ + { + Retention: &v1.RetentionPolicy{ + Policy: &v1.RetentionPolicy_PolicyKeepLastN{ + PolicyKeepLastN: 5, + }, + }, + }, + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + config := v1.Config{} + err := protojson.Unmarshal([]byte(tc.config), &config) + if err != nil { + t.Fatalf("failed to unmarshal config: %v", err) + } + + migration001PrunePolicy(&config) + + if !proto.Equal(&config, tc.want) { + t.Errorf("got: %+v, want: %+v", &config, tc.want) + } + }) + } +} diff --git a/internal/config/migrations/migrations.go b/internal/config/migrations/migrations.go new file mode 100644 index 00000000..cf4bc0e6 --- /dev/null +++ b/internal/config/migrations/migrations.go @@ -0,0 +1,10 @@ +package migrations + +import v1 "github.com/garethgeorge/backrest/gen/go/v1" + +func ApplyMigrations(config *v1.Config) { + if config.Version <= 1 { + migration001PrunePolicy(config) + } + config.Version = 1 +} diff --git a/proto/v1/config.proto b/proto/v1/config.proto index e3bc05ee..00d580ab 100644 --- a/proto/v1/config.proto +++ b/proto/v1/config.proto @@ -8,6 +8,7 @@ option go_package = "github.com/garethgeorge/backrest/gen/go/v1"; message Config { // modification number, used for read-modify-write consistency in the UI. Incremented on every write. int32 modno = 1 [json_name="modno"]; + int32 version = 6 [json_name="version"]; // version of the config file format. Used to determine when to run migrations. // override the hostname tagged on backups. If provided it will be used in addition to tags to group backups. string host = 2 [json_name="host"]; @@ -40,16 +41,29 @@ message Plan { } message RetentionPolicy { - // max_unused_limit is used to decide when forget should be run. - string max_unused_limit = 1 [json_name="maxUnusedLimit"]; // e.g. a percentage i.e. 25% or a number of megabytes. - - int32 keep_last_n = 2 [json_name="keepLastN"]; // keep the last n snapshots. - int32 keep_hourly = 3 [json_name="keepHourly"]; // keep the last n hourly snapshots. - int32 keep_daily = 4 [json_name="keepDaily"]; // keep the last n daily snapshots. - int32 keep_weekly = 5 [json_name="keepWeekly"]; // keep the last n weekly snapshots. - int32 keep_monthly = 6 [json_name="keepMonthly"]; // keep the last n monthly snapshots. - int32 keep_yearly = 7 [json_name="keepYearly"]; // keep the last n yearly snapshots. - string keep_within_duration = 8 [json_name="keepWithinDuration"]; // keep snapshots within a duration e.g. 1y2m3d4h5m6s + string max_unused_limit = 1 [json_name="maxUnusedLimit", deprecated = true]; + + int32 keep_last_n = 2 [json_name="keepLastN", deprecated = true]; + int32 keep_hourly = 3 [json_name="keepHourly", deprecated = true]; + int32 keep_daily = 4 [json_name="keepDaily", deprecated = true]; + int32 keep_weekly = 5 [json_name="keepWeekly", deprecated = true]; + int32 keep_monthly = 6 [json_name="keepMonthly", deprecated = true]; + int32 keep_yearly = 7 [json_name="keepYearly", deprecated = true]; + string keep_within_duration = 8 [json_name="keepWithinDuration", deprecated = true]; // keep snapshots within a duration e.g. 1y2m3d4h5m6s + + oneof policy { + int32 policy_keep_last_n = 10 [json_name="policyKeepLastN"]; + TimeBucketedCounts policy_time_bucketed = 11 [json_name="policyTimeBucketed"]; + bool policy_keep_all = 12 [json_name="policyKeepAll"]; + } + + message TimeBucketedCounts { + int32 hourly = 1 [json_name="hourly"]; // keep the last n hourly snapshots. + int32 daily = 2 [json_name="daily"]; // keep the last n daily snapshots. + int32 weekly = 3 [json_name="weekly"]; // keep the last n weekly snapshots. + int32 monthly = 4 [json_name="monthly"]; // keep the last n monthly snapshots. + int32 yearly = 5 [json_name="yearly"]; // keep the last n yearly snapshots. + } } message PrunePolicy { diff --git a/webui/gen/ts/v1/config_pb.ts b/webui/gen/ts/v1/config_pb.ts index 8b54c8e8..850c3738 100644 --- a/webui/gen/ts/v1/config_pb.ts +++ b/webui/gen/ts/v1/config_pb.ts @@ -19,6 +19,13 @@ export class Config extends Message { */ modno = 0; + /** + * version of the config file format. Used to determine when to run migrations. + * + * @generated from field: int32 version = 6; + */ + version = 0; + /** * override the hostname tagged on backups. If provided it will be used in addition to tags to group backups. * @@ -50,6 +57,7 @@ export class Config extends Message { static readonly typeName = "v1.Config"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "modno", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 6, name: "version", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, { no: 2, name: "host", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "repos", kind: "message", T: Repo, repeated: true }, { no: 4, name: "plans", kind: "message", T: Plan, repeated: true }, @@ -268,63 +276,78 @@ export class Plan extends Message { */ export class RetentionPolicy extends Message { /** - * max_unused_limit is used to decide when forget should be run. - * - * e.g. a percentage i.e. 25% or a number of megabytes. - * - * @generated from field: string max_unused_limit = 1; + * @generated from field: string max_unused_limit = 1 [deprecated = true]; + * @deprecated */ maxUnusedLimit = ""; /** - * keep the last n snapshots. - * - * @generated from field: int32 keep_last_n = 2; + * @generated from field: int32 keep_last_n = 2 [deprecated = true]; + * @deprecated */ keepLastN = 0; /** - * keep the last n hourly snapshots. - * - * @generated from field: int32 keep_hourly = 3; + * @generated from field: int32 keep_hourly = 3 [deprecated = true]; + * @deprecated */ keepHourly = 0; /** - * keep the last n daily snapshots. - * - * @generated from field: int32 keep_daily = 4; + * @generated from field: int32 keep_daily = 4 [deprecated = true]; + * @deprecated */ keepDaily = 0; /** - * keep the last n weekly snapshots. - * - * @generated from field: int32 keep_weekly = 5; + * @generated from field: int32 keep_weekly = 5 [deprecated = true]; + * @deprecated */ keepWeekly = 0; /** - * keep the last n monthly snapshots. - * - * @generated from field: int32 keep_monthly = 6; + * @generated from field: int32 keep_monthly = 6 [deprecated = true]; + * @deprecated */ keepMonthly = 0; /** - * keep the last n yearly snapshots. - * - * @generated from field: int32 keep_yearly = 7; + * @generated from field: int32 keep_yearly = 7 [deprecated = true]; + * @deprecated */ keepYearly = 0; /** * keep snapshots within a duration e.g. 1y2m3d4h5m6s * - * @generated from field: string keep_within_duration = 8; + * @generated from field: string keep_within_duration = 8 [deprecated = true]; + * @deprecated */ keepWithinDuration = ""; + /** + * @generated from oneof v1.RetentionPolicy.policy + */ + policy: { + /** + * @generated from field: int32 policy_keep_last_n = 10; + */ + value: number; + case: "policyKeepLastN"; + } | { + /** + * @generated from field: v1.RetentionPolicy.TimeBucketedCounts policy_time_bucketed = 11; + */ + value: RetentionPolicy_TimeBucketedCounts; + case: "policyTimeBucketed"; + } | { + /** + * @generated from field: bool policy_keep_all = 12; + */ + value: boolean; + case: "policyKeepAll"; + } | { case: undefined; value?: undefined } = { case: undefined }; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -341,6 +364,9 @@ export class RetentionPolicy extends Message { { no: 6, name: "keep_monthly", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, { no: 7, name: "keep_yearly", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, { no: 8, name: "keep_within_duration", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 10, name: "policy_keep_last_n", kind: "scalar", T: 5 /* ScalarType.INT32 */, oneof: "policy" }, + { no: 11, name: "policy_time_bucketed", kind: "message", T: RetentionPolicy_TimeBucketedCounts, oneof: "policy" }, + { no: 12, name: "policy_keep_all", kind: "scalar", T: 8 /* ScalarType.BOOL */, oneof: "policy" }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): RetentionPolicy { @@ -360,6 +386,77 @@ export class RetentionPolicy extends Message { } } +/** + * @generated from message v1.RetentionPolicy.TimeBucketedCounts + */ +export class RetentionPolicy_TimeBucketedCounts extends Message { + /** + * keep the last n hourly snapshots. + * + * @generated from field: int32 hourly = 1; + */ + hourly = 0; + + /** + * keep the last n daily snapshots. + * + * @generated from field: int32 daily = 2; + */ + daily = 0; + + /** + * keep the last n weekly snapshots. + * + * @generated from field: int32 weekly = 3; + */ + weekly = 0; + + /** + * keep the last n monthly snapshots. + * + * @generated from field: int32 monthly = 4; + */ + monthly = 0; + + /** + * keep the last n yearly snapshots. + * + * @generated from field: int32 yearly = 5; + */ + yearly = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "v1.RetentionPolicy.TimeBucketedCounts"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "hourly", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 2, name: "daily", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 3, name: "weekly", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 4, name: "monthly", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 5, name: "yearly", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): RetentionPolicy_TimeBucketedCounts { + return new RetentionPolicy_TimeBucketedCounts().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): RetentionPolicy_TimeBucketedCounts { + return new RetentionPolicy_TimeBucketedCounts().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): RetentionPolicy_TimeBucketedCounts { + return new RetentionPolicy_TimeBucketedCounts().fromJsonString(jsonString, options); + } + + static equals(a: RetentionPolicy_TimeBucketedCounts | PlainMessage | undefined, b: RetentionPolicy_TimeBucketedCounts | PlainMessage | undefined): boolean { + return proto3.util.equals(RetentionPolicy_TimeBucketedCounts, a, b); + } +} + /** * @generated from message v1.PrunePolicy */ diff --git a/webui/src/components/OperationList.tsx b/webui/src/components/OperationList.tsx index 8c30b1e6..636a275b 100644 --- a/webui/src/components/OperationList.tsx +++ b/webui/src/components/OperationList.tsx @@ -490,7 +490,6 @@ const ForgetOperationDetails = ({ forgetOp }: { forgetOp: OperationForget }) => } const RunHookOperationStatus = ({ op }: { op: Operation }) => { - if (op.op.case !== "operationRunHook") { return <>Wrong operation type; }