feat(memos): choose created or updated time for memos (#5894)
This commit is contained in:
@@ -158,8 +158,8 @@ message InstanceSetting {
|
||||
|
||||
// Memo-related instance settings and policies.
|
||||
message MemoRelatedSetting {
|
||||
// display_with_update_time orders and displays memo with update time.
|
||||
bool display_with_update_time = 2;
|
||||
reserved 2;
|
||||
reserved "display_with_update_time";
|
||||
// content_length_limit is the limit of content length. Unit is byte.
|
||||
int32 content_length_limit = 3;
|
||||
// enable_double_click_edit enables editing on double click.
|
||||
|
||||
@@ -204,8 +204,8 @@ message Memo {
|
||||
// If not set on creation, the server will set it to the current time.
|
||||
google.protobuf.Timestamp update_time = 5 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// The display timestamp of the memo.
|
||||
google.protobuf.Timestamp display_time = 6 [(google.api.field_behavior) = OPTIONAL];
|
||||
reserved 6;
|
||||
reserved "display_time";
|
||||
|
||||
// Required. The content of the memo in Markdown format.
|
||||
string content = 7 [(google.api.field_behavior) = REQUIRED];
|
||||
@@ -291,10 +291,10 @@ message ListMemosRequest {
|
||||
State state = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Optional. The order to sort results by.
|
||||
// Default to "display_time desc".
|
||||
// Default to "create_time desc".
|
||||
// Supports comma-separated list of fields following AIP-132.
|
||||
// Example: "pinned desc, display_time desc" or "create_time asc"
|
||||
// Supported fields: pinned, display_time, create_time, update_time, name
|
||||
// Example: "pinned desc, create_time desc" or "update_time asc"
|
||||
// Supported fields: pinned, create_time, update_time, name
|
||||
string order_by = 4 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Optional. Filter to apply to the list results.
|
||||
|
||||
@@ -354,8 +354,8 @@ message UserStats {
|
||||
// Format: users/{user}
|
||||
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
|
||||
|
||||
// The timestamps when the memos were displayed.
|
||||
repeated google.protobuf.Timestamp memo_display_timestamps = 2;
|
||||
reserved 2;
|
||||
reserved "memo_display_timestamps";
|
||||
|
||||
// The stats of memo types.
|
||||
MemoTypeStats memo_type_stats = 3;
|
||||
@@ -363,6 +363,9 @@ message UserStats {
|
||||
// The count of tags.
|
||||
map<string, int32> tag_count = 4;
|
||||
|
||||
// The creation timestamps of the user's memos.
|
||||
repeated google.protobuf.Timestamp memo_created_timestamps = 7;
|
||||
|
||||
// The pinned memos of the user.
|
||||
repeated string pinned_memos = 5;
|
||||
|
||||
|
||||
@@ -756,8 +756,6 @@ func (x *InstanceSetting_StorageSetting) GetS3Config() *InstanceSetting_StorageS
|
||||
// Memo-related instance settings and policies.
|
||||
type InstanceSetting_MemoRelatedSetting struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// display_with_update_time orders and displays memo with update time.
|
||||
DisplayWithUpdateTime bool `protobuf:"varint,2,opt,name=display_with_update_time,json=displayWithUpdateTime,proto3" json:"display_with_update_time,omitempty"`
|
||||
// content_length_limit is the limit of content length. Unit is byte.
|
||||
ContentLengthLimit int32 `protobuf:"varint,3,opt,name=content_length_limit,json=contentLengthLimit,proto3" json:"content_length_limit,omitempty"`
|
||||
// enable_double_click_edit enables editing on double click.
|
||||
@@ -798,13 +796,6 @@ func (*InstanceSetting_MemoRelatedSetting) Descriptor() ([]byte, []int) {
|
||||
return file_api_v1_instance_service_proto_rawDescGZIP(), []int{2, 2}
|
||||
}
|
||||
|
||||
func (x *InstanceSetting_MemoRelatedSetting) GetDisplayWithUpdateTime() bool {
|
||||
if x != nil {
|
||||
return x.DisplayWithUpdateTime
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *InstanceSetting_MemoRelatedSetting) GetContentLengthLimit() int32 {
|
||||
if x != nil {
|
||||
return x.ContentLengthLimit
|
||||
@@ -1392,7 +1383,7 @@ const file_api_v1_instance_service_proto_rawDesc = "" +
|
||||
"\x04demo\x18\x03 \x01(\bR\x04demo\x12!\n" +
|
||||
"\finstance_url\x18\x06 \x01(\tR\vinstanceUrl\x12(\n" +
|
||||
"\x05admin\x18\a \x01(\v2\x12.memos.api.v1.UserR\x05admin\"\x1b\n" +
|
||||
"\x19GetInstanceProfileRequest\"\xff\x19\n" +
|
||||
"\x19GetInstanceProfileRequest\"\xe6\x19\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" +
|
||||
@@ -1431,12 +1422,11 @@ const file_api_v1_instance_service_proto_rawDesc = "" +
|
||||
"\x18STORAGE_TYPE_UNSPECIFIED\x10\x00\x12\f\n" +
|
||||
"\bDATABASE\x10\x01\x12\t\n" +
|
||||
"\x05LOCAL\x10\x02\x12\x06\n" +
|
||||
"\x02S3\x10\x03\x1a\xd6\x01\n" +
|
||||
"\x12MemoRelatedSetting\x127\n" +
|
||||
"\x18display_with_update_time\x18\x02 \x01(\bR\x15displayWithUpdateTime\x120\n" +
|
||||
"\x02S3\x10\x03\x1a\xbd\x01\n" +
|
||||
"\x12MemoRelatedSetting\x120\n" +
|
||||
"\x14content_length_limit\x18\x03 \x01(\x05R\x12contentLengthLimit\x127\n" +
|
||||
"\x18enable_double_click_edit\x18\x04 \x01(\bR\x15enableDoubleClickEdit\x12\x1c\n" +
|
||||
"\treactions\x18\a \x03(\tR\treactions\x1ao\n" +
|
||||
"\treactions\x18\a \x03(\tR\treactionsJ\x04\b\x02\x10\x03R\x18display_with_update_time\x1ao\n" +
|
||||
"\vTagMetadata\x12=\n" +
|
||||
"\x10background_color\x18\x01 \x01(\v2\x12.google.type.ColorR\x0fbackgroundColor\x12!\n" +
|
||||
"\fblur_content\x18\x02 \x01(\bR\vblurContent\x1a\xba\x01\n" +
|
||||
|
||||
@@ -228,8 +228,6 @@ type Memo struct {
|
||||
// The last update timestamp.
|
||||
// If not set on creation, the server will set it to the current time.
|
||||
UpdateTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"`
|
||||
// The display timestamp of the memo.
|
||||
DisplayTime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=display_time,json=displayTime,proto3" json:"display_time,omitempty"`
|
||||
// Required. The content of the memo in Markdown format.
|
||||
Content string `protobuf:"bytes,7,opt,name=content,proto3" json:"content,omitempty"`
|
||||
// The visibility of the memo.
|
||||
@@ -322,13 +320,6 @@ func (x *Memo) GetUpdateTime() *timestamppb.Timestamp {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Memo) GetDisplayTime() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.DisplayTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Memo) GetContent() string {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
@@ -538,10 +529,10 @@ type ListMemosRequest struct {
|
||||
// Default to `NORMAL`. Set to `ARCHIVED` to list archived memos.
|
||||
State State `protobuf:"varint,3,opt,name=state,proto3,enum=memos.api.v1.State" json:"state,omitempty"`
|
||||
// Optional. The order to sort results by.
|
||||
// Default to "display_time desc".
|
||||
// Default to "create_time desc".
|
||||
// Supports comma-separated list of fields following AIP-132.
|
||||
// Example: "pinned desc, display_time desc" or "create_time asc"
|
||||
// Supported fields: pinned, display_time, create_time, update_time, name
|
||||
// Example: "pinned desc, create_time desc" or "update_time asc"
|
||||
// Supported fields: pinned, create_time, update_time, name
|
||||
OrderBy string `protobuf:"bytes,4,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"`
|
||||
// Optional. Filter to apply to the list results.
|
||||
// Filter is a CEL expression to filter memos.
|
||||
@@ -2124,7 +2115,7 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||
"\rreaction_type\x18\x04 \x01(\tB\x03\xe0A\x02R\freactionType\x12@\n" +
|
||||
"\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x03R\n" +
|
||||
"createTime:X\xeaAU\n" +
|
||||
"\x15memos.api.v1/Reaction\x12!memos/{memo}/reactions/{reaction}\x1a\x04name*\treactions2\breaction\"\xee\b\n" +
|
||||
"\x15memos.api.v1/Reaction\x12!memos/{memo}/reactions/{reaction}\x1a\x04name*\treactions2\breaction\"\xbe\b\n" +
|
||||
"\x04Memo\x12\x17\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12.\n" +
|
||||
"\x05state\x18\x02 \x01(\x0e2\x13.memos.api.v1.StateB\x03\xe0A\x02R\x05state\x123\n" +
|
||||
@@ -2133,8 +2124,7 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||
"\vcreate_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x01R\n" +
|
||||
"createTime\x12@\n" +
|
||||
"\vupdate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x01R\n" +
|
||||
"updateTime\x12B\n" +
|
||||
"\fdisplay_time\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x01R\vdisplayTime\x12\x1d\n" +
|
||||
"updateTime\x12\x1d\n" +
|
||||
"\acontent\x18\a \x01(\tB\x03\xe0A\x02R\acontent\x12=\n" +
|
||||
"\n" +
|
||||
"visibility\x18\t \x01(\x0e2\x18.memos.api.v1.VisibilityB\x03\xe0A\x02R\n" +
|
||||
@@ -2158,7 +2148,7 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||
"\x05title\x18\x05 \x01(\tR\x05title:7\xeaA4\n" +
|
||||
"\x11memos.api.v1/Memo\x12\fmemos/{memo}\x1a\x04name*\x05memos2\x04memoB\t\n" +
|
||||
"\a_parentB\v\n" +
|
||||
"\t_location\"u\n" +
|
||||
"\t_locationJ\x04\b\x06\x10\aR\fdisplay_time\"u\n" +
|
||||
"\bLocation\x12%\n" +
|
||||
"\vplaceholder\x18\x01 \x01(\tB\x03\xe0A\x01R\vplaceholder\x12\x1f\n" +
|
||||
"\blatitude\x18\x02 \x01(\x01B\x03\xe0A\x01R\blatitude\x12!\n" +
|
||||
@@ -2377,74 +2367,73 @@ var file_api_v1_memo_service_proto_depIdxs = []int32{
|
||||
34, // 1: memos.api.v1.Memo.state:type_name -> memos.api.v1.State
|
||||
33, // 2: memos.api.v1.Memo.create_time:type_name -> google.protobuf.Timestamp
|
||||
33, // 3: memos.api.v1.Memo.update_time:type_name -> google.protobuf.Timestamp
|
||||
33, // 4: memos.api.v1.Memo.display_time:type_name -> google.protobuf.Timestamp
|
||||
0, // 5: memos.api.v1.Memo.visibility:type_name -> memos.api.v1.Visibility
|
||||
35, // 6: memos.api.v1.Memo.attachments:type_name -> memos.api.v1.Attachment
|
||||
14, // 7: memos.api.v1.Memo.relations:type_name -> memos.api.v1.MemoRelation
|
||||
2, // 8: memos.api.v1.Memo.reactions:type_name -> memos.api.v1.Reaction
|
||||
31, // 9: memos.api.v1.Memo.property:type_name -> memos.api.v1.Memo.Property
|
||||
4, // 10: memos.api.v1.Memo.location:type_name -> memos.api.v1.Location
|
||||
3, // 11: memos.api.v1.CreateMemoRequest.memo:type_name -> memos.api.v1.Memo
|
||||
34, // 12: memos.api.v1.ListMemosRequest.state:type_name -> memos.api.v1.State
|
||||
3, // 13: memos.api.v1.ListMemosResponse.memos:type_name -> memos.api.v1.Memo
|
||||
3, // 14: memos.api.v1.UpdateMemoRequest.memo:type_name -> memos.api.v1.Memo
|
||||
36, // 15: memos.api.v1.UpdateMemoRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
35, // 16: memos.api.v1.SetMemoAttachmentsRequest.attachments:type_name -> memos.api.v1.Attachment
|
||||
35, // 17: memos.api.v1.ListMemoAttachmentsResponse.attachments:type_name -> memos.api.v1.Attachment
|
||||
32, // 18: memos.api.v1.MemoRelation.memo:type_name -> memos.api.v1.MemoRelation.Memo
|
||||
32, // 19: memos.api.v1.MemoRelation.related_memo:type_name -> memos.api.v1.MemoRelation.Memo
|
||||
1, // 20: memos.api.v1.MemoRelation.type:type_name -> memos.api.v1.MemoRelation.Type
|
||||
14, // 21: memos.api.v1.SetMemoRelationsRequest.relations:type_name -> memos.api.v1.MemoRelation
|
||||
14, // 22: memos.api.v1.ListMemoRelationsResponse.relations:type_name -> memos.api.v1.MemoRelation
|
||||
3, // 23: memos.api.v1.CreateMemoCommentRequest.comment:type_name -> memos.api.v1.Memo
|
||||
3, // 24: memos.api.v1.ListMemoCommentsResponse.memos:type_name -> memos.api.v1.Memo
|
||||
2, // 25: memos.api.v1.ListMemoReactionsResponse.reactions:type_name -> memos.api.v1.Reaction
|
||||
2, // 26: memos.api.v1.UpsertMemoReactionRequest.reaction:type_name -> memos.api.v1.Reaction
|
||||
33, // 27: memos.api.v1.MemoShare.create_time:type_name -> google.protobuf.Timestamp
|
||||
33, // 28: memos.api.v1.MemoShare.expire_time:type_name -> google.protobuf.Timestamp
|
||||
25, // 29: memos.api.v1.CreateMemoShareRequest.memo_share:type_name -> memos.api.v1.MemoShare
|
||||
25, // 30: memos.api.v1.ListMemoSharesResponse.memo_shares:type_name -> memos.api.v1.MemoShare
|
||||
5, // 31: memos.api.v1.MemoService.CreateMemo:input_type -> memos.api.v1.CreateMemoRequest
|
||||
6, // 32: memos.api.v1.MemoService.ListMemos:input_type -> memos.api.v1.ListMemosRequest
|
||||
8, // 33: memos.api.v1.MemoService.GetMemo:input_type -> memos.api.v1.GetMemoRequest
|
||||
9, // 34: memos.api.v1.MemoService.UpdateMemo:input_type -> memos.api.v1.UpdateMemoRequest
|
||||
10, // 35: memos.api.v1.MemoService.DeleteMemo:input_type -> memos.api.v1.DeleteMemoRequest
|
||||
11, // 36: memos.api.v1.MemoService.SetMemoAttachments:input_type -> memos.api.v1.SetMemoAttachmentsRequest
|
||||
12, // 37: memos.api.v1.MemoService.ListMemoAttachments:input_type -> memos.api.v1.ListMemoAttachmentsRequest
|
||||
15, // 38: memos.api.v1.MemoService.SetMemoRelations:input_type -> memos.api.v1.SetMemoRelationsRequest
|
||||
16, // 39: memos.api.v1.MemoService.ListMemoRelations:input_type -> memos.api.v1.ListMemoRelationsRequest
|
||||
18, // 40: memos.api.v1.MemoService.CreateMemoComment:input_type -> memos.api.v1.CreateMemoCommentRequest
|
||||
19, // 41: memos.api.v1.MemoService.ListMemoComments:input_type -> memos.api.v1.ListMemoCommentsRequest
|
||||
21, // 42: memos.api.v1.MemoService.ListMemoReactions:input_type -> memos.api.v1.ListMemoReactionsRequest
|
||||
23, // 43: memos.api.v1.MemoService.UpsertMemoReaction:input_type -> memos.api.v1.UpsertMemoReactionRequest
|
||||
24, // 44: memos.api.v1.MemoService.DeleteMemoReaction:input_type -> memos.api.v1.DeleteMemoReactionRequest
|
||||
26, // 45: memos.api.v1.MemoService.CreateMemoShare:input_type -> memos.api.v1.CreateMemoShareRequest
|
||||
27, // 46: memos.api.v1.MemoService.ListMemoShares:input_type -> memos.api.v1.ListMemoSharesRequest
|
||||
29, // 47: memos.api.v1.MemoService.DeleteMemoShare:input_type -> memos.api.v1.DeleteMemoShareRequest
|
||||
30, // 48: memos.api.v1.MemoService.GetMemoByShare:input_type -> memos.api.v1.GetMemoByShareRequest
|
||||
3, // 49: memos.api.v1.MemoService.CreateMemo:output_type -> memos.api.v1.Memo
|
||||
7, // 50: memos.api.v1.MemoService.ListMemos:output_type -> memos.api.v1.ListMemosResponse
|
||||
3, // 51: memos.api.v1.MemoService.GetMemo:output_type -> memos.api.v1.Memo
|
||||
3, // 52: memos.api.v1.MemoService.UpdateMemo:output_type -> memos.api.v1.Memo
|
||||
37, // 53: memos.api.v1.MemoService.DeleteMemo:output_type -> google.protobuf.Empty
|
||||
37, // 54: memos.api.v1.MemoService.SetMemoAttachments:output_type -> google.protobuf.Empty
|
||||
13, // 55: memos.api.v1.MemoService.ListMemoAttachments:output_type -> memos.api.v1.ListMemoAttachmentsResponse
|
||||
37, // 56: memos.api.v1.MemoService.SetMemoRelations:output_type -> google.protobuf.Empty
|
||||
17, // 57: memos.api.v1.MemoService.ListMemoRelations:output_type -> memos.api.v1.ListMemoRelationsResponse
|
||||
3, // 58: memos.api.v1.MemoService.CreateMemoComment:output_type -> memos.api.v1.Memo
|
||||
20, // 59: memos.api.v1.MemoService.ListMemoComments:output_type -> memos.api.v1.ListMemoCommentsResponse
|
||||
22, // 60: memos.api.v1.MemoService.ListMemoReactions:output_type -> memos.api.v1.ListMemoReactionsResponse
|
||||
2, // 61: memos.api.v1.MemoService.UpsertMemoReaction:output_type -> memos.api.v1.Reaction
|
||||
37, // 62: memos.api.v1.MemoService.DeleteMemoReaction:output_type -> google.protobuf.Empty
|
||||
25, // 63: memos.api.v1.MemoService.CreateMemoShare:output_type -> memos.api.v1.MemoShare
|
||||
28, // 64: memos.api.v1.MemoService.ListMemoShares:output_type -> memos.api.v1.ListMemoSharesResponse
|
||||
37, // 65: memos.api.v1.MemoService.DeleteMemoShare:output_type -> google.protobuf.Empty
|
||||
3, // 66: memos.api.v1.MemoService.GetMemoByShare:output_type -> memos.api.v1.Memo
|
||||
49, // [49:67] is the sub-list for method output_type
|
||||
31, // [31:49] is the sub-list for method input_type
|
||||
31, // [31:31] is the sub-list for extension type_name
|
||||
31, // [31:31] is the sub-list for extension extendee
|
||||
0, // [0:31] is the sub-list for field type_name
|
||||
0, // 4: memos.api.v1.Memo.visibility:type_name -> memos.api.v1.Visibility
|
||||
35, // 5: memos.api.v1.Memo.attachments:type_name -> memos.api.v1.Attachment
|
||||
14, // 6: memos.api.v1.Memo.relations:type_name -> memos.api.v1.MemoRelation
|
||||
2, // 7: memos.api.v1.Memo.reactions:type_name -> memos.api.v1.Reaction
|
||||
31, // 8: memos.api.v1.Memo.property:type_name -> memos.api.v1.Memo.Property
|
||||
4, // 9: memos.api.v1.Memo.location:type_name -> memos.api.v1.Location
|
||||
3, // 10: memos.api.v1.CreateMemoRequest.memo:type_name -> memos.api.v1.Memo
|
||||
34, // 11: memos.api.v1.ListMemosRequest.state:type_name -> memos.api.v1.State
|
||||
3, // 12: memos.api.v1.ListMemosResponse.memos:type_name -> memos.api.v1.Memo
|
||||
3, // 13: memos.api.v1.UpdateMemoRequest.memo:type_name -> memos.api.v1.Memo
|
||||
36, // 14: memos.api.v1.UpdateMemoRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
35, // 15: memos.api.v1.SetMemoAttachmentsRequest.attachments:type_name -> memos.api.v1.Attachment
|
||||
35, // 16: memos.api.v1.ListMemoAttachmentsResponse.attachments:type_name -> memos.api.v1.Attachment
|
||||
32, // 17: memos.api.v1.MemoRelation.memo:type_name -> memos.api.v1.MemoRelation.Memo
|
||||
32, // 18: memos.api.v1.MemoRelation.related_memo:type_name -> memos.api.v1.MemoRelation.Memo
|
||||
1, // 19: memos.api.v1.MemoRelation.type:type_name -> memos.api.v1.MemoRelation.Type
|
||||
14, // 20: memos.api.v1.SetMemoRelationsRequest.relations:type_name -> memos.api.v1.MemoRelation
|
||||
14, // 21: memos.api.v1.ListMemoRelationsResponse.relations:type_name -> memos.api.v1.MemoRelation
|
||||
3, // 22: memos.api.v1.CreateMemoCommentRequest.comment:type_name -> memos.api.v1.Memo
|
||||
3, // 23: memos.api.v1.ListMemoCommentsResponse.memos:type_name -> memos.api.v1.Memo
|
||||
2, // 24: memos.api.v1.ListMemoReactionsResponse.reactions:type_name -> memos.api.v1.Reaction
|
||||
2, // 25: memos.api.v1.UpsertMemoReactionRequest.reaction:type_name -> memos.api.v1.Reaction
|
||||
33, // 26: memos.api.v1.MemoShare.create_time:type_name -> google.protobuf.Timestamp
|
||||
33, // 27: memos.api.v1.MemoShare.expire_time:type_name -> google.protobuf.Timestamp
|
||||
25, // 28: memos.api.v1.CreateMemoShareRequest.memo_share:type_name -> memos.api.v1.MemoShare
|
||||
25, // 29: memos.api.v1.ListMemoSharesResponse.memo_shares:type_name -> memos.api.v1.MemoShare
|
||||
5, // 30: memos.api.v1.MemoService.CreateMemo:input_type -> memos.api.v1.CreateMemoRequest
|
||||
6, // 31: memos.api.v1.MemoService.ListMemos:input_type -> memos.api.v1.ListMemosRequest
|
||||
8, // 32: memos.api.v1.MemoService.GetMemo:input_type -> memos.api.v1.GetMemoRequest
|
||||
9, // 33: memos.api.v1.MemoService.UpdateMemo:input_type -> memos.api.v1.UpdateMemoRequest
|
||||
10, // 34: memos.api.v1.MemoService.DeleteMemo:input_type -> memos.api.v1.DeleteMemoRequest
|
||||
11, // 35: memos.api.v1.MemoService.SetMemoAttachments:input_type -> memos.api.v1.SetMemoAttachmentsRequest
|
||||
12, // 36: memos.api.v1.MemoService.ListMemoAttachments:input_type -> memos.api.v1.ListMemoAttachmentsRequest
|
||||
15, // 37: memos.api.v1.MemoService.SetMemoRelations:input_type -> memos.api.v1.SetMemoRelationsRequest
|
||||
16, // 38: memos.api.v1.MemoService.ListMemoRelations:input_type -> memos.api.v1.ListMemoRelationsRequest
|
||||
18, // 39: memos.api.v1.MemoService.CreateMemoComment:input_type -> memos.api.v1.CreateMemoCommentRequest
|
||||
19, // 40: memos.api.v1.MemoService.ListMemoComments:input_type -> memos.api.v1.ListMemoCommentsRequest
|
||||
21, // 41: memos.api.v1.MemoService.ListMemoReactions:input_type -> memos.api.v1.ListMemoReactionsRequest
|
||||
23, // 42: memos.api.v1.MemoService.UpsertMemoReaction:input_type -> memos.api.v1.UpsertMemoReactionRequest
|
||||
24, // 43: memos.api.v1.MemoService.DeleteMemoReaction:input_type -> memos.api.v1.DeleteMemoReactionRequest
|
||||
26, // 44: memos.api.v1.MemoService.CreateMemoShare:input_type -> memos.api.v1.CreateMemoShareRequest
|
||||
27, // 45: memos.api.v1.MemoService.ListMemoShares:input_type -> memos.api.v1.ListMemoSharesRequest
|
||||
29, // 46: memos.api.v1.MemoService.DeleteMemoShare:input_type -> memos.api.v1.DeleteMemoShareRequest
|
||||
30, // 47: memos.api.v1.MemoService.GetMemoByShare:input_type -> memos.api.v1.GetMemoByShareRequest
|
||||
3, // 48: memos.api.v1.MemoService.CreateMemo:output_type -> memos.api.v1.Memo
|
||||
7, // 49: memos.api.v1.MemoService.ListMemos:output_type -> memos.api.v1.ListMemosResponse
|
||||
3, // 50: memos.api.v1.MemoService.GetMemo:output_type -> memos.api.v1.Memo
|
||||
3, // 51: memos.api.v1.MemoService.UpdateMemo:output_type -> memos.api.v1.Memo
|
||||
37, // 52: memos.api.v1.MemoService.DeleteMemo:output_type -> google.protobuf.Empty
|
||||
37, // 53: memos.api.v1.MemoService.SetMemoAttachments:output_type -> google.protobuf.Empty
|
||||
13, // 54: memos.api.v1.MemoService.ListMemoAttachments:output_type -> memos.api.v1.ListMemoAttachmentsResponse
|
||||
37, // 55: memos.api.v1.MemoService.SetMemoRelations:output_type -> google.protobuf.Empty
|
||||
17, // 56: memos.api.v1.MemoService.ListMemoRelations:output_type -> memos.api.v1.ListMemoRelationsResponse
|
||||
3, // 57: memos.api.v1.MemoService.CreateMemoComment:output_type -> memos.api.v1.Memo
|
||||
20, // 58: memos.api.v1.MemoService.ListMemoComments:output_type -> memos.api.v1.ListMemoCommentsResponse
|
||||
22, // 59: memos.api.v1.MemoService.ListMemoReactions:output_type -> memos.api.v1.ListMemoReactionsResponse
|
||||
2, // 60: memos.api.v1.MemoService.UpsertMemoReaction:output_type -> memos.api.v1.Reaction
|
||||
37, // 61: memos.api.v1.MemoService.DeleteMemoReaction:output_type -> google.protobuf.Empty
|
||||
25, // 62: memos.api.v1.MemoService.CreateMemoShare:output_type -> memos.api.v1.MemoShare
|
||||
28, // 63: memos.api.v1.MemoService.ListMemoShares:output_type -> memos.api.v1.ListMemoSharesResponse
|
||||
37, // 64: memos.api.v1.MemoService.DeleteMemoShare:output_type -> google.protobuf.Empty
|
||||
3, // 65: memos.api.v1.MemoService.GetMemoByShare:output_type -> memos.api.v1.Memo
|
||||
48, // [48:66] is the sub-list for method output_type
|
||||
30, // [30:48] is the sub-list for method input_type
|
||||
30, // [30:30] is the sub-list for extension type_name
|
||||
30, // [30:30] is the sub-list for extension extendee
|
||||
0, // [0:30] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_api_v1_memo_service_proto_init() }
|
||||
|
||||
@@ -849,12 +849,12 @@ type UserStats struct {
|
||||
// The resource name of the user whose stats these are.
|
||||
// Format: users/{user}
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// The timestamps when the memos were displayed.
|
||||
MemoDisplayTimestamps []*timestamppb.Timestamp `protobuf:"bytes,2,rep,name=memo_display_timestamps,json=memoDisplayTimestamps,proto3" json:"memo_display_timestamps,omitempty"`
|
||||
// The stats of memo types.
|
||||
MemoTypeStats *UserStats_MemoTypeStats `protobuf:"bytes,3,opt,name=memo_type_stats,json=memoTypeStats,proto3" json:"memo_type_stats,omitempty"`
|
||||
// The count of tags.
|
||||
TagCount map[string]int32 `protobuf:"bytes,4,rep,name=tag_count,json=tagCount,proto3" json:"tag_count,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
|
||||
// The creation timestamps of the user's memos.
|
||||
MemoCreatedTimestamps []*timestamppb.Timestamp `protobuf:"bytes,7,rep,name=memo_created_timestamps,json=memoCreatedTimestamps,proto3" json:"memo_created_timestamps,omitempty"`
|
||||
// The pinned memos of the user.
|
||||
PinnedMemos []string `protobuf:"bytes,5,rep,name=pinned_memos,json=pinnedMemos,proto3" json:"pinned_memos,omitempty"`
|
||||
// Total memo count.
|
||||
@@ -900,13 +900,6 @@ func (x *UserStats) GetName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UserStats) GetMemoDisplayTimestamps() []*timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.MemoDisplayTimestamps
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserStats) GetMemoTypeStats() *UserStats_MemoTypeStats {
|
||||
if x != nil {
|
||||
return x.MemoTypeStats
|
||||
@@ -921,6 +914,13 @@ func (x *UserStats) GetTagCount() map[string]int32 {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserStats) GetMemoCreatedTimestamps() []*timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.MemoCreatedTimestamps
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserStats) GetPinnedMemos() []string {
|
||||
if x != nil {
|
||||
return x.PinnedMemos
|
||||
@@ -3172,12 +3172,12 @@ const file_api_v1_user_service_proto_rawDesc = "" +
|
||||
"\x11DeleteUserRequest\x12-\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x19\xe0A\x02\xfaA\x13\n" +
|
||||
"\x11memos.api.v1/UserR\x04name\x12\x19\n" +
|
||||
"\x05force\x18\x02 \x01(\bB\x03\xe0A\x01R\x05force\"\xe4\x04\n" +
|
||||
"\x05force\x18\x02 \x01(\bB\x03\xe0A\x01R\x05force\"\x83\x05\n" +
|
||||
"\tUserStats\x12\x17\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12R\n" +
|
||||
"\x17memo_display_timestamps\x18\x02 \x03(\v2\x1a.google.protobuf.TimestampR\x15memoDisplayTimestamps\x12M\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12M\n" +
|
||||
"\x0fmemo_type_stats\x18\x03 \x01(\v2%.memos.api.v1.UserStats.MemoTypeStatsR\rmemoTypeStats\x12B\n" +
|
||||
"\ttag_count\x18\x04 \x03(\v2%.memos.api.v1.UserStats.TagCountEntryR\btagCount\x12!\n" +
|
||||
"\ttag_count\x18\x04 \x03(\v2%.memos.api.v1.UserStats.TagCountEntryR\btagCount\x12R\n" +
|
||||
"\x17memo_created_timestamps\x18\a \x03(\v2\x1a.google.protobuf.TimestampR\x15memoCreatedTimestamps\x12!\n" +
|
||||
"\fpinned_memos\x18\x05 \x03(\tR\vpinnedMemos\x12(\n" +
|
||||
"\x10total_memo_count\x18\x06 \x01(\x05R\x0etotalMemoCount\x1a\x8b\x01\n" +
|
||||
"\rMemoTypeStats\x12\x1d\n" +
|
||||
@@ -3192,7 +3192,7 @@ const file_api_v1_user_service_proto_rawDesc = "" +
|
||||
"\rTagCountEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\x05R\x05value:\x028\x01:?\xeaA<\n" +
|
||||
"\x16memos.api.v1/UserStats\x12\fusers/{user}*\tuserStats2\tuserStats\"D\n" +
|
||||
"\x16memos.api.v1/UserStats\x12\fusers/{user}*\tuserStats2\tuserStatsJ\x04\b\x02\x10\x03R\x17memo_display_timestamps\"D\n" +
|
||||
"\x13GetUserStatsRequest\x12-\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x19\xe0A\x02\xfaA\x13\n" +
|
||||
"\x11memos.api.v1/UserR\x04name\"\x19\n" +
|
||||
@@ -3475,9 +3475,9 @@ var file_api_v1_user_service_proto_depIdxs = []int32{
|
||||
4, // 7: memos.api.v1.CreateUserRequest.user:type_name -> memos.api.v1.User
|
||||
4, // 8: memos.api.v1.UpdateUserRequest.user:type_name -> memos.api.v1.User
|
||||
53, // 9: memos.api.v1.UpdateUserRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
52, // 10: memos.api.v1.UserStats.memo_display_timestamps:type_name -> google.protobuf.Timestamp
|
||||
45, // 11: memos.api.v1.UserStats.memo_type_stats:type_name -> memos.api.v1.UserStats.MemoTypeStats
|
||||
46, // 12: memos.api.v1.UserStats.tag_count:type_name -> memos.api.v1.UserStats.TagCountEntry
|
||||
45, // 10: memos.api.v1.UserStats.memo_type_stats:type_name -> memos.api.v1.UserStats.MemoTypeStats
|
||||
46, // 11: memos.api.v1.UserStats.tag_count:type_name -> memos.api.v1.UserStats.TagCountEntry
|
||||
52, // 12: memos.api.v1.UserStats.memo_created_timestamps:type_name -> google.protobuf.Timestamp
|
||||
13, // 13: memos.api.v1.ListAllUserStatsResponse.stats:type_name -> memos.api.v1.UserStats
|
||||
47, // 14: memos.api.v1.UserSetting.general_setting:type_name -> memos.api.v1.UserSetting.GeneralSetting
|
||||
48, // 15: memos.api.v1.UserSetting.webhooks_setting:type_name -> memos.api.v1.UserSetting.WebhooksSetting
|
||||
|
||||
+9
-16
@@ -579,10 +579,10 @@ paths:
|
||||
in: query
|
||||
description: |-
|
||||
Optional. The order to sort results by.
|
||||
Default to "display_time desc".
|
||||
Default to "create_time desc".
|
||||
Supports comma-separated list of fields following AIP-132.
|
||||
Example: "pinned desc, display_time desc" or "create_time asc"
|
||||
Supported fields: pinned, display_time, create_time, update_time, name
|
||||
Example: "pinned desc, create_time desc" or "update_time asc"
|
||||
Supported fields: pinned, create_time, update_time, name
|
||||
schema:
|
||||
type: string
|
||||
- name: filter
|
||||
@@ -2626,9 +2626,6 @@ components:
|
||||
InstanceSetting_MemoRelatedSetting:
|
||||
type: object
|
||||
properties:
|
||||
displayWithUpdateTime:
|
||||
type: boolean
|
||||
description: display_with_update_time orders and displays memo with update time.
|
||||
contentLengthLimit:
|
||||
type: integer
|
||||
description: content_length_limit is the limit of content length. Unit is byte.
|
||||
@@ -2959,10 +2956,6 @@ components:
|
||||
The last update timestamp.
|
||||
If not set on creation, the server will set it to the current time.
|
||||
format: date-time
|
||||
displayTime:
|
||||
type: string
|
||||
description: The display timestamp of the memo.
|
||||
format: date-time
|
||||
content:
|
||||
type: string
|
||||
description: Required. The content of the memo in Markdown format.
|
||||
@@ -3637,12 +3630,6 @@ components:
|
||||
description: |-
|
||||
The resource name of the user whose stats these are.
|
||||
Format: users/{user}
|
||||
memoDisplayTimestamps:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The timestamps when the memos were displayed.
|
||||
memoTypeStats:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/UserStats_MemoTypeStats'
|
||||
@@ -3653,6 +3640,12 @@ components:
|
||||
type: integer
|
||||
format: int32
|
||||
description: The count of tags.
|
||||
memoCreatedTimestamps:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The creation timestamps of the user's memos.
|
||||
pinnedMemos:
|
||||
type: array
|
||||
items:
|
||||
|
||||
@@ -751,8 +751,6 @@ func (x *StorageS3Config) GetUsePathStyle() bool {
|
||||
|
||||
type InstanceMemoRelatedSetting struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// display_with_update_time orders and displays memo with update time.
|
||||
DisplayWithUpdateTime bool `protobuf:"varint,2,opt,name=display_with_update_time,json=displayWithUpdateTime,proto3" json:"display_with_update_time,omitempty"`
|
||||
// content_length_limit is the limit of content length. Unit is byte.
|
||||
ContentLengthLimit int32 `protobuf:"varint,3,opt,name=content_length_limit,json=contentLengthLimit,proto3" json:"content_length_limit,omitempty"`
|
||||
// enable_double_click_edit enables editing on double click.
|
||||
@@ -793,13 +791,6 @@ func (*InstanceMemoRelatedSetting) Descriptor() ([]byte, []int) {
|
||||
return file_store_instance_setting_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *InstanceMemoRelatedSetting) GetDisplayWithUpdateTime() bool {
|
||||
if x != nil {
|
||||
return x.DisplayWithUpdateTime
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *InstanceMemoRelatedSetting) GetContentLengthLimit() int32 {
|
||||
if x != nil {
|
||||
return x.ContentLengthLimit
|
||||
@@ -1255,12 +1246,11 @@ const file_store_instance_setting_proto_rawDesc = "" +
|
||||
"\bendpoint\x18\x03 \x01(\tR\bendpoint\x12\x16\n" +
|
||||
"\x06region\x18\x04 \x01(\tR\x06region\x12\x16\n" +
|
||||
"\x06bucket\x18\x05 \x01(\tR\x06bucket\x12$\n" +
|
||||
"\x0euse_path_style\x18\x06 \x01(\bR\fusePathStyle\"\xde\x01\n" +
|
||||
"\x1aInstanceMemoRelatedSetting\x127\n" +
|
||||
"\x18display_with_update_time\x18\x02 \x01(\bR\x15displayWithUpdateTime\x120\n" +
|
||||
"\x0euse_path_style\x18\x06 \x01(\bR\fusePathStyle\"\xc5\x01\n" +
|
||||
"\x1aInstanceMemoRelatedSetting\x120\n" +
|
||||
"\x14content_length_limit\x18\x03 \x01(\x05R\x12contentLengthLimit\x127\n" +
|
||||
"\x18enable_double_click_edit\x18\x04 \x01(\bR\x15enableDoubleClickEdit\x12\x1c\n" +
|
||||
"\treactions\x18\a \x03(\tR\treactions\"w\n" +
|
||||
"\treactions\x18\a \x03(\tR\treactionsJ\x04\b\x02\x10\x03R\x18display_with_update_time\"w\n" +
|
||||
"\x13InstanceTagMetadata\x12=\n" +
|
||||
"\x10background_color\x18\x01 \x01(\v2\x12.google.type.ColorR\x0fbackgroundColor\x12!\n" +
|
||||
"\fblur_content\x18\x02 \x01(\bR\vblurContent\"\xb0\x01\n" +
|
||||
|
||||
@@ -103,8 +103,8 @@ message StorageS3Config {
|
||||
}
|
||||
|
||||
message InstanceMemoRelatedSetting {
|
||||
// display_with_update_time orders and displays memo with update time.
|
||||
bool display_with_update_time = 2;
|
||||
reserved 2;
|
||||
reserved "display_with_update_time";
|
||||
// content_length_limit is the limit of content length. Unit is byte.
|
||||
int32 content_length_limit = 3;
|
||||
// enable_double_click_edit enables editing on double click.
|
||||
|
||||
@@ -325,7 +325,6 @@ func convertInstanceMemoRelatedSettingFromStore(setting *storepb.InstanceMemoRel
|
||||
return nil
|
||||
}
|
||||
return &v1pb.InstanceSetting_MemoRelatedSetting{
|
||||
DisplayWithUpdateTime: setting.DisplayWithUpdateTime,
|
||||
ContentLengthLimit: setting.ContentLengthLimit,
|
||||
EnableDoubleClickEdit: setting.EnableDoubleClickEdit,
|
||||
Reactions: setting.Reactions,
|
||||
@@ -337,7 +336,6 @@ func convertInstanceMemoRelatedSettingToStore(setting *v1pb.InstanceSetting_Memo
|
||||
return nil
|
||||
}
|
||||
return &storepb.InstanceMemoRelatedSetting{
|
||||
DisplayWithUpdateTime: setting.DisplayWithUpdateTime,
|
||||
ContentLengthLimit: setting.ContentLengthLimit,
|
||||
EnableDoubleClickEdit: setting.EnableDoubleClickEdit,
|
||||
Reactions: setting.Reactions,
|
||||
|
||||
@@ -54,25 +54,7 @@ func (s *APIV1Service) CreateMemo(ctx context.Context, request *v1pb.CreateMemoR
|
||||
Visibility: convertVisibilityToStore(request.Memo.Visibility),
|
||||
}
|
||||
|
||||
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
|
||||
}
|
||||
|
||||
// Handle display_time first: if provided, use it to set the appropriate timestamp
|
||||
// based on the instance setting (similar to UpdateMemo logic)
|
||||
// Note: explicit create_time/update_time below will override this if provided
|
||||
if request.Memo.DisplayTime != nil && request.Memo.DisplayTime.IsValid() {
|
||||
displayTs := request.Memo.DisplayTime.AsTime().Unix()
|
||||
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
|
||||
create.UpdatedTs = displayTs
|
||||
} else {
|
||||
create.CreatedTs = displayTs
|
||||
}
|
||||
}
|
||||
|
||||
// Set custom timestamps if provided in the request
|
||||
// These take precedence over display_time
|
||||
// Set custom timestamps if provided in the request.
|
||||
if request.Memo.CreateTime != nil && request.Memo.CreateTime.IsValid() {
|
||||
createdTs := request.Memo.CreateTime.AsTime().Unix()
|
||||
create.CreatedTs = createdTs
|
||||
@@ -196,7 +178,7 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid order_by: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Default ordering by display_time desc
|
||||
// Default ordering by create_time desc.
|
||||
memoFind.OrderByTimeAsc = false
|
||||
}
|
||||
|
||||
@@ -218,14 +200,6 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
|
||||
}
|
||||
}
|
||||
|
||||
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
|
||||
}
|
||||
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
|
||||
memoFind.OrderByUpdatedTs = true
|
||||
}
|
||||
|
||||
var limit, offset int
|
||||
if request.PageToken != "" {
|
||||
var pageToken v1pb.PageToken
|
||||
@@ -312,15 +286,13 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to list memo creators: %v", err)
|
||||
}
|
||||
conversionOptions := memoConversionOptions{displayWithUpdateTime: instanceMemoRelatedSetting.DisplayWithUpdateTime}
|
||||
|
||||
for _, memo := range memos {
|
||||
memoName := fmt.Sprintf("%s%s", MemoNamePrefix, memo.UID)
|
||||
reactions := reactionMap[memoName]
|
||||
attachments := attachmentMap[memo.ID]
|
||||
relations := relationMap[memo.ID]
|
||||
|
||||
memoMessage, err := s.convertMemoFromStoreWithCreatorsAndOptions(ctx, memo, reactions, attachments, relations, creatorMap, conversionOptions)
|
||||
memoMessage, err := s.convertMemoFromStoreWithCreators(ctx, memo, reactions, attachments, relations, creatorMap)
|
||||
if err != nil {
|
||||
if stderrors.Is(err, errMemoCreatorNotFound) {
|
||||
slog.Warn("Skipping memo with missing creator",
|
||||
@@ -479,16 +451,7 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
|
||||
}
|
||||
update.UpdatedTs = &updatedTs
|
||||
} else if path == "display_time" {
|
||||
displayTs := request.Memo.DisplayTime.AsTime().Unix()
|
||||
memoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
|
||||
}
|
||||
if memoRelatedSetting.DisplayWithUpdateTime {
|
||||
update.UpdatedTs = &displayTs
|
||||
} else {
|
||||
update.CreatedTs = &displayTs
|
||||
}
|
||||
return nil, status.Errorf(codes.InvalidArgument, "display_time is not supported")
|
||||
} else if path == "location" {
|
||||
payload := memo.Payload
|
||||
payload.Location = convertLocationToStore(request.Memo.Location)
|
||||
@@ -817,12 +780,6 @@ func (s *APIV1Service) ListMemoComments(ctx context.Context, request *v1pb.ListM
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to list memo creators: %v", err)
|
||||
}
|
||||
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
|
||||
}
|
||||
conversionOptions := memoConversionOptions{displayWithUpdateTime: instanceMemoRelatedSetting.DisplayWithUpdateTime}
|
||||
|
||||
var memosResponse []*v1pb.Memo
|
||||
for _, m := range memos {
|
||||
memoName := memoIDToNameMap[m.ID]
|
||||
@@ -830,7 +787,7 @@ func (s *APIV1Service) ListMemoComments(ctx context.Context, request *v1pb.ListM
|
||||
attachments := attachmentMap[m.ID]
|
||||
relations := relationMap[m.ID]
|
||||
|
||||
memoMessage, err := s.convertMemoFromStoreWithCreatorsAndOptions(ctx, m, reactions, attachments, relations, creatorMap, conversionOptions)
|
||||
memoMessage, err := s.convertMemoFromStoreWithCreators(ctx, m, reactions, attachments, relations, creatorMap)
|
||||
if err != nil {
|
||||
if stderrors.Is(err, errMemoCreatorNotFound) {
|
||||
slog.Warn("Skipping memo comment with missing creator",
|
||||
@@ -939,7 +896,7 @@ func (s *APIV1Service) getMemoContentSnippet(content string) (string, error) {
|
||||
|
||||
// parseMemoOrderBy parses the order_by field and sets the appropriate ordering in memoFind.
|
||||
// Follows AIP-132: supports comma-separated list of fields with optional "desc" suffix.
|
||||
// Example: "pinned desc, display_time desc" or "create_time asc".
|
||||
// Example: "pinned desc, create_time desc" or "update_time asc".
|
||||
func (*APIV1Service) parseMemoOrderBy(orderBy string, memoFind *store.FindMemo) error {
|
||||
if strings.TrimSpace(orderBy) == "" {
|
||||
return errors.New("empty order_by")
|
||||
@@ -950,6 +907,7 @@ func (*APIV1Service) parseMemoOrderBy(orderBy string, memoFind *store.FindMemo)
|
||||
|
||||
// Track if we've seen pinned field.
|
||||
hasPinned := false
|
||||
hasExplicitTimeField := false
|
||||
|
||||
for _, field := range fields {
|
||||
parts := strings.Fields(strings.TrimSpace(field))
|
||||
@@ -971,16 +929,21 @@ func (*APIV1Service) parseMemoOrderBy(orderBy string, memoFind *store.FindMemo)
|
||||
hasPinned = true
|
||||
memoFind.OrderByPinned = true
|
||||
// Note: pinned is always DESC (true first) regardless of direction specified.
|
||||
case "display_time", "create_time", "name":
|
||||
case "create_time", "name":
|
||||
// Only set if this is the first time field we encounter.
|
||||
if !memoFind.OrderByUpdatedTs {
|
||||
if !hasExplicitTimeField {
|
||||
memoFind.OrderByTimeAsc = fieldDirection == "asc"
|
||||
}
|
||||
hasExplicitTimeField = true
|
||||
case "update_time":
|
||||
memoFind.OrderByUpdatedTs = true
|
||||
memoFind.OrderByTimeAsc = fieldDirection == "asc"
|
||||
// Only set if this is the first time field we encounter.
|
||||
if !hasExplicitTimeField {
|
||||
memoFind.OrderByUpdatedTs = true
|
||||
memoFind.OrderByTimeAsc = fieldDirection == "asc"
|
||||
}
|
||||
hasExplicitTimeField = true
|
||||
default:
|
||||
return errors.Errorf("unsupported order field: %s, supported fields are: pinned, display_time, create_time, update_time, name", fieldName)
|
||||
return errors.Errorf("unsupported order field: %s, supported fields are: pinned, create_time, update_time, name", fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,6 @@ var (
|
||||
errReactionCreatorNotFound = stderrors.New("reaction creator not found")
|
||||
)
|
||||
|
||||
type memoConversionOptions struct {
|
||||
displayWithUpdateTime bool
|
||||
}
|
||||
|
||||
func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Memo, reactions []*store.Reaction, attachments []*store.Attachment, relations []*v1pb.MemoRelation) (*v1pb.Memo, error) {
|
||||
creatorMap, err := s.listUsersByID(ctx, []int32{memo.CreatorID})
|
||||
if err != nil {
|
||||
@@ -33,42 +29,20 @@ func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Mem
|
||||
}
|
||||
|
||||
func (s *APIV1Service) convertMemoFromStoreWithCreators(ctx context.Context, memo *store.Memo, reactions []*store.Reaction, attachments []*store.Attachment, relations []*v1pb.MemoRelation, creatorMap map[int32]*store.User) (*v1pb.Memo, error) {
|
||||
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get instance memo related setting")
|
||||
}
|
||||
return s.convertMemoFromStoreWithCreatorsAndOptions(
|
||||
ctx,
|
||||
memo,
|
||||
reactions,
|
||||
attachments,
|
||||
relations,
|
||||
creatorMap,
|
||||
memoConversionOptions{displayWithUpdateTime: instanceMemoRelatedSetting.DisplayWithUpdateTime},
|
||||
)
|
||||
}
|
||||
|
||||
func (s *APIV1Service) convertMemoFromStoreWithCreatorsAndOptions(ctx context.Context, memo *store.Memo, reactions []*store.Reaction, attachments []*store.Attachment, relations []*v1pb.MemoRelation, creatorMap map[int32]*store.User, options memoConversionOptions) (*v1pb.Memo, error) {
|
||||
displayTs := memo.CreatedTs
|
||||
if options.displayWithUpdateTime {
|
||||
displayTs = memo.UpdatedTs
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%s%s", MemoNamePrefix, memo.UID)
|
||||
creator := creatorMap[memo.CreatorID]
|
||||
if creator == nil {
|
||||
return nil, errMemoCreatorNotFound
|
||||
}
|
||||
memoMessage := &v1pb.Memo{
|
||||
Name: name,
|
||||
State: convertStateFromStore(memo.RowStatus),
|
||||
Creator: BuildUserName(creator.Username),
|
||||
CreateTime: timestamppb.New(time.Unix(memo.CreatedTs, 0)),
|
||||
UpdateTime: timestamppb.New(time.Unix(memo.UpdatedTs, 0)),
|
||||
DisplayTime: timestamppb.New(time.Unix(displayTs, 0)),
|
||||
Content: memo.Content,
|
||||
Visibility: convertVisibilityFromStore(memo.Visibility),
|
||||
Pinned: memo.Pinned,
|
||||
Name: name,
|
||||
State: convertStateFromStore(memo.RowStatus),
|
||||
Creator: BuildUserName(creator.Username),
|
||||
CreateTime: timestamppb.New(time.Unix(memo.CreatedTs, 0)),
|
||||
UpdateTime: timestamppb.New(time.Unix(memo.UpdatedTs, 0)),
|
||||
Content: memo.Content,
|
||||
Visibility: convertVisibilityFromStore(memo.Visibility),
|
||||
Pinned: memo.Pinned,
|
||||
}
|
||||
if memo.Payload != nil {
|
||||
memoMessage.Tags = memo.Payload.Tags
|
||||
|
||||
@@ -254,6 +254,120 @@ func TestListMemos(t *testing.T) {
|
||||
require.Equal(t, "👍", userTwoReaction.ReactionType)
|
||||
}
|
||||
|
||||
func TestListMemosTimeOrderBy(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
user, err := ts.CreateHostUser(ctx, "time-order-user")
|
||||
require.NoError(t, err)
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
memoEarlyCreateLateUpdate, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "early create late update",
|
||||
Visibility: apiv1.Visibility_PRIVATE,
|
||||
CreateTime: timestamppb.New(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
UpdateTime: timestamppb.New(time.Date(2020, 1, 3, 0, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
memoMiddleCreateEarlyUpdate, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "middle create early update",
|
||||
Visibility: apiv1.Visibility_PRIVATE,
|
||||
CreateTime: timestamppb.New(time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)),
|
||||
UpdateTime: timestamppb.New(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
memoLateCreateMiddleUpdate, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "late create middle update",
|
||||
Visibility: apiv1.Visibility_PRIVATE,
|
||||
CreateTime: timestamppb.New(time.Date(2020, 1, 3, 0, 0, 0, 0, time.UTC)),
|
||||
UpdateTime: timestamppb.New(time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
orderBy string
|
||||
wantNames []string
|
||||
}{
|
||||
{
|
||||
name: "default create time",
|
||||
orderBy: "",
|
||||
wantNames: []string{
|
||||
memoLateCreateMiddleUpdate.Name,
|
||||
memoMiddleCreateEarlyUpdate.Name,
|
||||
memoEarlyCreateLateUpdate.Name,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "explicit create time",
|
||||
orderBy: "create_time desc",
|
||||
wantNames: []string{
|
||||
memoLateCreateMiddleUpdate.Name,
|
||||
memoMiddleCreateEarlyUpdate.Name,
|
||||
memoEarlyCreateLateUpdate.Name,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "explicit update time",
|
||||
orderBy: "update_time desc",
|
||||
wantNames: []string{
|
||||
memoEarlyCreateLateUpdate.Name,
|
||||
memoLateCreateMiddleUpdate.Name,
|
||||
memoMiddleCreateEarlyUpdate.Name,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pinned with explicit create time",
|
||||
orderBy: "pinned desc, create_time desc",
|
||||
wantNames: []string{
|
||||
memoLateCreateMiddleUpdate.Name,
|
||||
memoMiddleCreateEarlyUpdate.Name,
|
||||
memoEarlyCreateLateUpdate.Name,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "explicit create time ascending",
|
||||
orderBy: "create_time asc",
|
||||
wantNames: []string{
|
||||
memoEarlyCreateLateUpdate.Name,
|
||||
memoMiddleCreateEarlyUpdate.Name,
|
||||
memoLateCreateMiddleUpdate.Name,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
resp, err := ts.Service.ListMemos(userCtx, &apiv1.ListMemosRequest{
|
||||
PageSize: 10,
|
||||
OrderBy: test.orderBy,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resp.Memos, len(test.wantNames))
|
||||
|
||||
gotNames := make([]string, 0, len(resp.Memos))
|
||||
for _, memo := range resp.Memos {
|
||||
gotNames = append(gotNames, memo.Name)
|
||||
}
|
||||
require.Equal(t, test.wantNames, gotNames)
|
||||
})
|
||||
}
|
||||
|
||||
_, err = ts.Service.ListMemos(userCtx, &apiv1.ListMemosRequest{
|
||||
PageSize: 10,
|
||||
OrderBy: "display_time desc",
|
||||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestListMemosSkipsReactionsWithMissingCreators(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -431,7 +545,6 @@ func TestCreateMemoWithCustomTimestamps(t *testing.T) {
|
||||
// Define custom timestamps (January 1, 2020)
|
||||
customCreateTime := time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC)
|
||||
customUpdateTime := time.Date(2020, 1, 2, 12, 0, 0, 0, time.UTC)
|
||||
customDisplayTime := time.Date(2020, 1, 3, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
// Test 1: Create a memo with custom create_time
|
||||
memoWithCreateTime, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
@@ -457,41 +570,21 @@ func TestCreateMemoWithCustomTimestamps(t *testing.T) {
|
||||
require.NotNil(t, memoWithUpdateTime)
|
||||
require.Equal(t, customUpdateTime.Unix(), memoWithUpdateTime.UpdateTime.AsTime().Unix(), "update_time should match the custom timestamp")
|
||||
|
||||
// Test 3: Create a memo with custom display_time
|
||||
// Note: display_time is computed from either created_ts or updated_ts based on instance setting
|
||||
// Since DisplayWithUpdateTime defaults to false, display_time maps to created_ts
|
||||
memoWithDisplayTime, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "This memo has a custom display time",
|
||||
Visibility: apiv1.Visibility_PRIVATE,
|
||||
DisplayTime: timestamppb.New(customDisplayTime),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, memoWithDisplayTime)
|
||||
// Since DisplayWithUpdateTime is false by default, display_time sets created_ts
|
||||
require.Equal(t, customDisplayTime.Unix(), memoWithDisplayTime.DisplayTime.AsTime().Unix(), "display_time should match the custom timestamp")
|
||||
require.Equal(t, customDisplayTime.Unix(), memoWithDisplayTime.CreateTime.AsTime().Unix(), "create_time should also match since display_time maps to created_ts")
|
||||
|
||||
// Test 4: Create a memo with all custom timestamps
|
||||
// When both display_time and create_time are provided, create_time takes precedence
|
||||
// Test 3: Create a memo with all custom timestamps
|
||||
memoWithAllTimestamps, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "This memo has all custom timestamps",
|
||||
Visibility: apiv1.Visibility_PRIVATE,
|
||||
CreateTime: timestamppb.New(customCreateTime),
|
||||
UpdateTime: timestamppb.New(customUpdateTime),
|
||||
DisplayTime: timestamppb.New(customDisplayTime),
|
||||
Content: "This memo has all custom timestamps",
|
||||
Visibility: apiv1.Visibility_PRIVATE,
|
||||
CreateTime: timestamppb.New(customCreateTime),
|
||||
UpdateTime: timestamppb.New(customUpdateTime),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, memoWithAllTimestamps)
|
||||
require.Equal(t, customCreateTime.Unix(), memoWithAllTimestamps.CreateTime.AsTime().Unix(), "create_time should match the custom timestamp")
|
||||
require.Equal(t, customUpdateTime.Unix(), memoWithAllTimestamps.UpdateTime.AsTime().Unix(), "update_time should match the custom timestamp")
|
||||
// display_time is computed from created_ts when DisplayWithUpdateTime is false
|
||||
require.Equal(t, customCreateTime.Unix(), memoWithAllTimestamps.DisplayTime.AsTime().Unix(), "display_time should be derived from create_time")
|
||||
|
||||
// Test 5: Create a comment (memo relation) with custom timestamps
|
||||
// Test 4: Create a comment (memo relation) with custom timestamps
|
||||
parentMemo, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "This is the parent memo",
|
||||
@@ -514,7 +607,7 @@ func TestCreateMemoWithCustomTimestamps(t *testing.T) {
|
||||
require.NotNil(t, comment)
|
||||
require.Equal(t, customCommentCreateTime.Unix(), comment.CreateTime.AsTime().Unix(), "comment create_time should match the custom timestamp")
|
||||
|
||||
// Test 6: Verify that memos without custom timestamps still get auto-generated ones
|
||||
// Test 5: Verify that memos without custom timestamps still get auto-generated ones
|
||||
memoWithoutTimestamps, err := ts.Service.CreateMemo(userCtx, &apiv1.CreateMemoRequest{
|
||||
Memo: &apiv1.Memo{
|
||||
Content: "This memo has auto-generated timestamps",
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -55,11 +54,6 @@ func (s *APIV1Service) listUsernamesByID(ctx context.Context, userIDs []int32) (
|
||||
}
|
||||
|
||||
func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUserStatsRequest) (*v1pb.ListAllUserStatsResponse, error) {
|
||||
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get instance memo related setting")
|
||||
}
|
||||
|
||||
normalStatus := store.Normal
|
||||
memoFind := &store.FindMemo{
|
||||
// Exclude comments by default.
|
||||
@@ -105,7 +99,7 @@ func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUser
|
||||
userMemoStatMap[memo.CreatorID] = &v1pb.UserStats{
|
||||
Name: "",
|
||||
TagCount: make(map[string]int32),
|
||||
MemoDisplayTimestamps: []*timestamppb.Timestamp{},
|
||||
MemoCreatedTimestamps: []*timestamppb.Timestamp{},
|
||||
PinnedMemos: []string{},
|
||||
MemoTypeStats: &v1pb.UserStats_MemoTypeStats{
|
||||
LinkCount: 0,
|
||||
@@ -118,12 +112,7 @@ func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUser
|
||||
|
||||
stats := userMemoStatMap[memo.CreatorID]
|
||||
|
||||
// Add display timestamp
|
||||
displayTs := memo.CreatedTs
|
||||
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
|
||||
displayTs = memo.UpdatedTs
|
||||
}
|
||||
stats.MemoDisplayTimestamps = append(stats.MemoDisplayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))
|
||||
stats.MemoCreatedTimestamps = append(stats.MemoCreatedTimestamps, timestamppb.New(time.Unix(memo.CreatedTs, 0)))
|
||||
|
||||
// Count memo stats
|
||||
stats.TotalMemoCount++
|
||||
@@ -215,12 +204,7 @@ func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserSt
|
||||
memoFind.VisibilityList = []store.Visibility{store.Public, store.Protected}
|
||||
}
|
||||
|
||||
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get instance memo related setting")
|
||||
}
|
||||
|
||||
displayTimestamps := []*timestamppb.Timestamp{}
|
||||
createdTimestamps := []*timestamppb.Timestamp{}
|
||||
tagCount := make(map[string]int32)
|
||||
linkCount := int32(0)
|
||||
codeCount := int32(0)
|
||||
@@ -246,11 +230,7 @@ func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserSt
|
||||
totalMemoCount += int32(len(memos))
|
||||
|
||||
for _, memo := range memos {
|
||||
displayTs := memo.CreatedTs
|
||||
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
|
||||
displayTs = memo.UpdatedTs
|
||||
}
|
||||
displayTimestamps = append(displayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))
|
||||
createdTimestamps = append(createdTimestamps, timestamppb.New(time.Unix(memo.CreatedTs, 0)))
|
||||
// Count different memo types based on content.
|
||||
if memo.Payload != nil {
|
||||
for _, tag := range memo.Payload.Tags {
|
||||
@@ -281,7 +261,7 @@ func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserSt
|
||||
|
||||
userStats := &v1pb.UserStats{
|
||||
Name: fmt.Sprintf("%s/stats", BuildUserName(user.Username)),
|
||||
MemoDisplayTimestamps: displayTimestamps,
|
||||
MemoCreatedTimestamps: createdTimestamps,
|
||||
TagCount: tagCount,
|
||||
PinnedMemos: pinnedMemos,
|
||||
TotalMemoCount: totalMemoCount,
|
||||
|
||||
@@ -35,7 +35,7 @@ export const buildMemoShareImagePreviewModel = ({
|
||||
}: BuildMemoShareImagePreviewModelOptions): MemoShareImagePreviewModel => {
|
||||
const displayName = creator?.displayName || creator?.username || fallbackDisplayName;
|
||||
const avatarUrl = getMemoSharePreviewAvatarUrl(creator?.avatarUrl);
|
||||
const displayTime = memo.displayTime ? timestampDate(memo.displayTime) : memo.createTime ? timestampDate(memo.createTime) : undefined;
|
||||
const displayTime = memo.createTime ? timestampDate(memo.createTime) : undefined;
|
||||
const formattedDisplayTime = displayTime?.toLocaleString(locale, {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
|
||||
@@ -67,7 +67,7 @@ const MemoCommentSection = ({ memo, comments, parentPage }: Props) => {
|
||||
</div>
|
||||
)}
|
||||
{comments.map((comment) => (
|
||||
<div className="w-full" key={`${comment.name}-${comment.displayTime}`} id={extractMemoIdFromName(comment.name)}>
|
||||
<div className="w-full" key={`${comment.name}-${comment.updateTime}`} id={extractMemoIdFromName(comment.name)}>
|
||||
<MemoView memo={comment} parentPage={parentPage} showCreator compact />
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -11,8 +11,8 @@ interface Props {
|
||||
|
||||
function MemoDisplaySettingMenu({ className }: Props) {
|
||||
const t = useTranslate();
|
||||
const { orderByTimeAsc, toggleSortOrder } = useView();
|
||||
const isApplying = orderByTimeAsc !== false;
|
||||
const { orderByTimeAsc, timeBasis, setTimeBasis, toggleSortOrder } = useView();
|
||||
const isApplying = orderByTimeAsc !== false || timeBasis !== "create_time";
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
@@ -22,7 +22,19 @@ function MemoDisplaySettingMenu({ className }: Props) {
|
||||
<PopoverContent align="end" alignOffset={-12} sideOffset={14}>
|
||||
<div className="flex flex-col gap-2 p-1">
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<span className="text-sm shrink-0 mr-3 text-foreground">{t("memo.direction")}</span>
|
||||
<span className="text-sm shrink-0 mr-3 text-foreground">{t("memo.shown-time")}</span>
|
||||
<Select value={timeBasis} onValueChange={(value) => setTimeBasis(value === "update_time" ? "update_time" : "create_time")}>
|
||||
<SelectTrigger size="sm" className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="create_time">{t("common.created-at")}</SelectItem>
|
||||
<SelectItem value="update_time">{t("common.last-updated-at")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<span className="text-sm shrink-0 mr-3 text-foreground">{t("memo.order")}</span>
|
||||
<Select
|
||||
value={orderByTimeAsc.toString()}
|
||||
onValueChange={(value) => {
|
||||
@@ -31,12 +43,12 @@ function MemoDisplaySettingMenu({ className }: Props) {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger size="sm">
|
||||
<SelectTrigger size="sm" className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="false">{t("memo.direction-desc")}</SelectItem>
|
||||
<SelectItem value="true">{t("memo.direction-asc")}</SelectItem>
|
||||
<SelectItem value="false">{t("memo.newest-first")}</SelectItem>
|
||||
<SelectItem value="true">{t("memo.oldest-first")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
@@ -74,7 +74,7 @@ export const LinkMemoDialog = ({
|
||||
<div className="w-full flex flex-col gap-1">
|
||||
<div className="flex items-center gap-1.5 text-sm text-muted-foreground select-none">
|
||||
{alreadyLinked && <LinkIcon className="w-3 h-3 shrink-0" />}
|
||||
<span>{memo.displayTime && timestampDate(memo.displayTime).toLocaleString()}</span>
|
||||
<span>{memo.createTime && timestampDate(memo.createTime).toLocaleString()}</span>
|
||||
</div>
|
||||
<MemoPreview name={memo.name} content={memo.content} attachments={memo.attachments} showMemoId />
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
||||
import { createContext, useContext } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useView } from "@/contexts/ViewContext";
|
||||
import type { Memo } from "@/types/proto/api/v1/memo_service_pb";
|
||||
import { MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb";
|
||||
import type { User } from "@/types/proto/api/v1/user_service_pb";
|
||||
@@ -37,12 +38,14 @@ export const computeCommentAmount = (memo: Memo): number =>
|
||||
|
||||
export const useMemoViewDerived = () => {
|
||||
const { memo, isArchived, readonly } = useMemoViewContext();
|
||||
const { timeBasis } = useView();
|
||||
const location = useLocation();
|
||||
|
||||
const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`) || location.pathname.startsWith("/memos/shares/");
|
||||
const commentAmount = computeCommentAmount(memo);
|
||||
|
||||
const displayTime = memo.displayTime ? timestampDate(memo.displayTime) : undefined;
|
||||
const displayTimestamp = timeBasis === "update_time" ? memo.updateTime : memo.createTime;
|
||||
const displayTime = displayTimestamp ? timestampDate(displayTimestamp) : undefined;
|
||||
const relativeTimeFormat: "datetime" | "auto" =
|
||||
displayTime && Date.now() - displayTime.getTime() > RELATIVE_TIME_THRESHOLD_MS ? "datetime" : "auto";
|
||||
|
||||
@@ -51,6 +54,7 @@ export const useMemoViewDerived = () => {
|
||||
readonly,
|
||||
isInMemoDetailPage,
|
||||
commentAmount,
|
||||
displayTime,
|
||||
relativeTimeFormat,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
||||
import { BookmarkIcon } from "lucide-react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
@@ -23,7 +22,7 @@ const MemoHeader: React.FC<MemoHeaderProps> = ({ showCreator, showVisibility, sh
|
||||
const [reactionSelectorOpen, setReactionSelectorOpen] = useState(false);
|
||||
|
||||
const { memo, creator, currentUser, parentPage, isArchived, readonly, openEditor } = useMemoViewContext();
|
||||
const { relativeTimeFormat } = useMemoViewDerived();
|
||||
const { displayTime: memoDisplayTime, relativeTimeFormat } = useMemoViewDerived();
|
||||
|
||||
const navigateTo = useNavigateTo();
|
||||
const handleGotoMemoDetailPage = useCallback(() => {
|
||||
@@ -33,13 +32,9 @@ const MemoHeader: React.FC<MemoHeaderProps> = ({ showCreator, showVisibility, sh
|
||||
const { unpinMemo } = useMemoActions(memo);
|
||||
|
||||
const displayTime = isArchived ? (
|
||||
(memo.displayTime ? timestampDate(memo.displayTime) : undefined)?.toLocaleString(i18n.language)
|
||||
memoDisplayTime?.toLocaleString(i18n.language)
|
||||
) : (
|
||||
<relative-time
|
||||
datetime={(memo.displayTime ? timestampDate(memo.displayTime) : undefined)?.toISOString()}
|
||||
lang={i18n.language}
|
||||
format={relativeTimeFormat}
|
||||
></relative-time>
|
||||
<relative-time datetime={memoDisplayTime?.toISOString()} lang={i18n.language} format={relativeTimeFormat}></relative-time>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -88,7 +88,7 @@ const PagedMemoList = (props: Props) => {
|
||||
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteMemos(
|
||||
{
|
||||
state: props.state || State.NORMAL,
|
||||
orderBy: props.orderBy || "display_time desc",
|
||||
orderBy: props.orderBy || "create_time desc",
|
||||
filter: props.filter,
|
||||
pageSize: props.pageSize || DEFAULT_LIST_MEMOS_PAGE_SIZE,
|
||||
},
|
||||
|
||||
@@ -72,13 +72,6 @@ const MemoRelatedSettings = () => {
|
||||
return (
|
||||
<SettingSection title={t("setting.memo.label")}>
|
||||
<SettingGroup title={t("common.basic")}>
|
||||
<SettingRow label={t("setting.system.display-with-updated-time")}>
|
||||
<Switch
|
||||
checked={memoRelatedSetting.displayWithUpdateTime}
|
||||
onCheckedChange={(checked) => updatePartialSetting({ displayWithUpdateTime: checked })}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow label={t("setting.system.enable-double-click-to-edit")}>
|
||||
<Switch
|
||||
checked={memoRelatedSetting.enableDoubleClickEdit}
|
||||
|
||||
@@ -52,7 +52,7 @@ const UserMemoMap = ({ creator, className }: Props) => {
|
||||
const { data, isLoading } = useInfiniteMemos(
|
||||
{
|
||||
state: State.NORMAL,
|
||||
orderBy: "display_time desc",
|
||||
orderBy: "create_time desc",
|
||||
pageSize: 1000,
|
||||
filter: creatorFilter,
|
||||
},
|
||||
@@ -133,8 +133,8 @@ const UserMemoMap = ({ creator, className }: Props) => {
|
||||
Memo
|
||||
</span>
|
||||
<span className="block text-[11px] font-medium text-muted-foreground">
|
||||
{memo.displayTime &&
|
||||
timestampDate(memo.displayTime).toLocaleDateString(undefined, {
|
||||
{memo.createTime &&
|
||||
timestampDate(memo.createTime).toLocaleDateString(undefined, {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import { createContext, type ReactNode, useContext, useState } from "react";
|
||||
|
||||
export type MemoTimeBasis = "create_time" | "update_time";
|
||||
|
||||
interface ViewState {
|
||||
orderByTimeAsc: boolean;
|
||||
timeBasis?: MemoTimeBasis;
|
||||
sortTimeField?: MemoTimeBasis;
|
||||
}
|
||||
|
||||
interface ViewContextValue {
|
||||
orderByTimeAsc: boolean;
|
||||
timeBasis: MemoTimeBasis;
|
||||
toggleSortOrder: () => void;
|
||||
setTimeBasis: (field: MemoTimeBasis) => void;
|
||||
}
|
||||
|
||||
const ViewContext = createContext<ViewContextValue | null>(null);
|
||||
@@ -10,13 +20,16 @@ const ViewContext = createContext<ViewContextValue | null>(null);
|
||||
const LOCAL_STORAGE_KEY = "memos-view-setting";
|
||||
|
||||
export function ViewProvider({ children }: { children: ReactNode }) {
|
||||
const getInitialState = () => {
|
||||
const getInitialState = (): ViewState => {
|
||||
try {
|
||||
const cached = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (cached) {
|
||||
const data = JSON.parse(cached);
|
||||
const data = JSON.parse(cached) as Partial<ViewState>;
|
||||
const cachedTimeBasis = data.timeBasis ?? data.sortTimeField;
|
||||
const timeBasis = cachedTimeBasis === "create_time" || cachedTimeBasis === "update_time" ? cachedTimeBasis : undefined;
|
||||
return {
|
||||
orderByTimeAsc: Boolean(data.orderByTimeAsc ?? false),
|
||||
timeBasis,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -26,8 +39,9 @@ export function ViewProvider({ children }: { children: ReactNode }) {
|
||||
};
|
||||
|
||||
const [viewState, setViewState] = useState(getInitialState);
|
||||
const timeBasis = viewState.timeBasis ?? "create_time";
|
||||
|
||||
const persistToStorage = (newState: typeof viewState) => {
|
||||
const persistToStorage = (newState: ViewState) => {
|
||||
try {
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(newState));
|
||||
} catch (error) {
|
||||
@@ -43,11 +57,21 @@ export function ViewProvider({ children }: { children: ReactNode }) {
|
||||
});
|
||||
};
|
||||
|
||||
const setTimeBasis = (field: MemoTimeBasis) => {
|
||||
setViewState((prev) => {
|
||||
const newState = { ...prev, timeBasis: field };
|
||||
persistToStorage(newState);
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewContext.Provider
|
||||
value={{
|
||||
...viewState,
|
||||
orderByTimeAsc: viewState.orderByTimeAsc,
|
||||
timeBasis,
|
||||
toggleSortOrder,
|
||||
setTimeBasis,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -49,15 +49,15 @@ export const useFilteredMemoStats = (options: UseFilteredMemoStatsOptions = {}):
|
||||
}
|
||||
}
|
||||
const displayDates = (memosResponse?.memos ?? [])
|
||||
.map((memo) => (memo.displayTime ? timestampDate(memo.displayTime) : undefined))
|
||||
.map((memo) => (memo.createTime ? timestampDate(memo.createTime) : undefined))
|
||||
.filter((date): date is Date => date !== undefined)
|
||||
.map(toDateString);
|
||||
activityStats = countBy(displayDates);
|
||||
} else if (userName && userStats) {
|
||||
// home/profile: use backend per-user stats
|
||||
if (userStats.memoDisplayTimestamps && userStats.memoDisplayTimestamps.length > 0) {
|
||||
if (userStats.memoCreatedTimestamps && userStats.memoCreatedTimestamps.length > 0) {
|
||||
activityStats = countBy(
|
||||
userStats.memoDisplayTimestamps
|
||||
userStats.memoCreatedTimestamps
|
||||
.map((ts) => (ts ? timestampDate(ts) : undefined))
|
||||
.filter((date): date is Date => date !== undefined)
|
||||
.map(toDateString),
|
||||
@@ -69,7 +69,7 @@ export const useFilteredMemoStats = (options: UseFilteredMemoStatsOptions = {}):
|
||||
} else if (memosResponse?.memos) {
|
||||
// archived/fallback: compute from cached memos
|
||||
const displayDates = memosResponse.memos
|
||||
.map((memo) => (memo.displayTime ? timestampDate(memo.displayTime) : undefined))
|
||||
.map((memo) => (memo.createTime ? timestampDate(memo.createTime) : undefined))
|
||||
.filter((date): date is Date => date !== undefined)
|
||||
.map(toDateString);
|
||||
activityStats = countBy(displayDates);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMemo } from "react";
|
||||
import { useAuth } from "@/contexts/AuthContext";
|
||||
import { useInstance } from "@/contexts/InstanceContext";
|
||||
import { useMemoFilterContext } from "@/contexts/MemoFilterContext";
|
||||
import { buildMemoCreatorFilter } from "@/helpers/resource-names";
|
||||
import { Visibility } from "@/types/proto/api/v1/memo_service_pb";
|
||||
@@ -37,7 +36,6 @@ export const useMemoFilters = (options: UseMemoFiltersOptions = {}): string | un
|
||||
|
||||
const { shortcuts } = useAuth();
|
||||
const { filters, shortcut: currentShortcut } = useMemoFilterContext();
|
||||
const { memoRelatedSetting } = useInstance();
|
||||
|
||||
// Get selected shortcut if needed
|
||||
const selectedShortcut = useMemo(() => {
|
||||
@@ -79,14 +77,11 @@ export const useMemoFilters = (options: UseMemoFiltersOptions = {}): string | un
|
||||
} else if (filter.factor === "property.hasCode") {
|
||||
conditions.push(`has_code`);
|
||||
} else if (filter.factor === "displayTime") {
|
||||
const displayWithUpdateTime = memoRelatedSetting?.displayWithUpdateTime ?? false;
|
||||
const factor = displayWithUpdateTime ? "updated_ts" : "created_ts";
|
||||
|
||||
const filterDate = new Date(filter.value);
|
||||
const filterUtcTimestamp = filterDate.getTime() + filterDate.getTimezoneOffset() * 60 * 1000;
|
||||
const timestampAfter = filterUtcTimestamp / 1000;
|
||||
|
||||
conditions.push(`${factor} >= ${timestampAfter} && ${factor} < ${timestampAfter + 60 * 60 * 24}`);
|
||||
conditions.push(`created_ts >= ${timestampAfter} && created_ts < ${timestampAfter + 60 * 60 * 24}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,5 +92,5 @@ export const useMemoFilters = (options: UseMemoFiltersOptions = {}): string | un
|
||||
}
|
||||
|
||||
return conditions.length > 0 ? conditions.join(" && ") : undefined;
|
||||
}, [creatorName, includeShortcuts, includePinned, visibilities, selectedShortcut, filters, memoRelatedSetting]);
|
||||
}, [creatorName, includeShortcuts, includePinned, visibilities, selectedShortcut, filters]);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
||||
import dayjs from "dayjs";
|
||||
import { useMemo } from "react";
|
||||
import { useView } from "@/contexts/ViewContext";
|
||||
import { type MemoTimeBasis, useView } from "@/contexts/ViewContext";
|
||||
import { State } from "@/types/proto/api/v1/common_pb";
|
||||
import { Memo } from "@/types/proto/api/v1/memo_service_pb";
|
||||
import type { Memo } from "@/types/proto/api/v1/memo_service_pb";
|
||||
|
||||
export interface UseMemoSortingOptions {
|
||||
pinnedFirst?: boolean;
|
||||
@@ -15,15 +15,20 @@ export interface UseMemoSortingResult {
|
||||
orderBy: string;
|
||||
}
|
||||
|
||||
const getMemoSortTime = (memo: Memo, timeBasis: MemoTimeBasis): Date | undefined => {
|
||||
const timestamp = timeBasis === "update_time" ? memo.updateTime : memo.createTime;
|
||||
return timestamp ? timestampDate(timestamp) : undefined;
|
||||
};
|
||||
|
||||
export const useMemoSorting = (options: UseMemoSortingOptions = {}): UseMemoSortingResult => {
|
||||
const { pinnedFirst = false, state = State.NORMAL } = options;
|
||||
const { orderByTimeAsc } = useView();
|
||||
const { orderByTimeAsc, timeBasis } = useView();
|
||||
|
||||
// Generate orderBy string for API
|
||||
const orderBy = useMemo(() => {
|
||||
const timeOrder = orderByTimeAsc ? "display_time asc" : "display_time desc";
|
||||
const timeOrder = orderByTimeAsc ? `${timeBasis} asc` : `${timeBasis} desc`;
|
||||
return pinnedFirst ? `pinned desc, ${timeOrder}` : timeOrder;
|
||||
}, [pinnedFirst, orderByTimeAsc]);
|
||||
}, [pinnedFirst, orderByTimeAsc, timeBasis]);
|
||||
|
||||
// Generate listSort function for client-side sorting
|
||||
const listSort = useMemo(() => {
|
||||
@@ -36,13 +41,13 @@ export const useMemoSorting = (options: UseMemoSortingOptions = {}): UseMemoSort
|
||||
return b.pinned ? 1 : -1;
|
||||
}
|
||||
|
||||
// Then sort by display time
|
||||
const aTime = a.displayTime ? timestampDate(a.displayTime) : undefined;
|
||||
const bTime = b.displayTime ? timestampDate(b.displayTime) : undefined;
|
||||
// Then sort by the selected time field.
|
||||
const aTime = getMemoSortTime(a, timeBasis);
|
||||
const bTime = getMemoSortTime(b, timeBasis);
|
||||
return orderByTimeAsc ? dayjs(aTime).unix() - dayjs(bTime).unix() : dayjs(bTime).unix() - dayjs(aTime).unix();
|
||||
});
|
||||
};
|
||||
}, [pinnedFirst, state, orderByTimeAsc]);
|
||||
}, [pinnedFirst, state, orderByTimeAsc, timeBasis]);
|
||||
|
||||
return { listSort, orderBy };
|
||||
};
|
||||
|
||||
@@ -247,9 +247,13 @@
|
||||
"load-more": "Load more",
|
||||
"no-archived-memos": "No archived memos.",
|
||||
"no-memos": "No memos.",
|
||||
"newest-first": "Newest first",
|
||||
"oldest-first": "Oldest first",
|
||||
"order": "Order",
|
||||
"order-by": "Order By",
|
||||
"outline": "Outline",
|
||||
"search-placeholder": "Search memos...",
|
||||
"shown-time": "Shown time",
|
||||
"share": {
|
||||
"active-links": "Active share links",
|
||||
"copied": "Copied!",
|
||||
|
||||
@@ -209,8 +209,12 @@
|
||||
"load-more": "加载更多",
|
||||
"no-archived-memos": "没有已归档备忘录。",
|
||||
"no-memos": "无备忘录",
|
||||
"newest-first": "最新优先",
|
||||
"oldest-first": "最早优先",
|
||||
"order": "顺序",
|
||||
"order-by": "排序",
|
||||
"search-placeholder": "搜索备忘录",
|
||||
"shown-time": "显示时间",
|
||||
"show-less": "显示较少",
|
||||
"show-more": "查看更多",
|
||||
"to-do": "待办",
|
||||
|
||||
@@ -206,8 +206,12 @@
|
||||
"load-more": "載入更多",
|
||||
"no-archived-memos": "無已封存的備忘錄",
|
||||
"no-memos": "無備忘錄",
|
||||
"newest-first": "最新優先",
|
||||
"oldest-first": "最早優先",
|
||||
"order": "順序",
|
||||
"order-by": "排序",
|
||||
"search-placeholder": "搜尋備忘錄",
|
||||
"shown-time": "顯示時間",
|
||||
"show-less": "顯示較少",
|
||||
"show-more": "查看更多",
|
||||
"to-do": "待辦事項",
|
||||
|
||||
@@ -24,7 +24,7 @@ const Home = () => {
|
||||
return (
|
||||
<div className="w-full min-h-full bg-background text-foreground">
|
||||
<PagedMemoList
|
||||
renderer={(memo: Memo) => <MemoView key={`${memo.name}-${memo.displayTime}`} memo={memo} showVisibility showPinned compact />}
|
||||
renderer={(memo: Memo) => <MemoView key={`${memo.name}-${memo.updateTime}`} memo={memo} showVisibility showPinned compact />}
|
||||
listSort={listSort}
|
||||
orderBy={orderBy}
|
||||
filter={memoFilter}
|
||||
|
||||
@@ -100,7 +100,7 @@ const MemoDetail = () => {
|
||||
</div>
|
||||
)}
|
||||
<MemoView
|
||||
key={`${displayMemo.name}-${displayMemo.displayTime}`}
|
||||
key={`${displayMemo.name}-${displayMemo.updateTime}`}
|
||||
memo={displayMemo}
|
||||
compact={false}
|
||||
parentPage={locationState?.from}
|
||||
|
||||
@@ -130,7 +130,7 @@ const UserProfile = () => {
|
||||
{activeTab === "memos" ? (
|
||||
<PagedMemoList
|
||||
renderer={(memo: Memo) => (
|
||||
<MemoView key={`${memo.name}-${memo.displayTime}`} memo={memo} showVisibility showPinned compact />
|
||||
<MemoView key={`${memo.name}-${memo.updateTime}`} memo={memo} showVisibility showPinned compact />
|
||||
)}
|
||||
listSort={listSort}
|
||||
orderBy={orderBy}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file api/v1/ai_service.proto (package memos.api.v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -31,14 +31,14 @@ export type TranscribeRequest = Message<"memos.api.v1.TranscribeRequest"> & {
|
||||
*
|
||||
* @generated from field: memos.api.v1.TranscriptionConfig config = 2;
|
||||
*/
|
||||
config?: TranscriptionConfig;
|
||||
config?: TranscriptionConfig | undefined;
|
||||
|
||||
/**
|
||||
* Required. Audio input.
|
||||
*
|
||||
* @generated from field: memos.api.v1.TranscriptionAudio audio = 3;
|
||||
*/
|
||||
audio?: TranscriptionAudio;
|
||||
audio?: TranscriptionAudio | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file api/v1/attachment_service.proto (package memos.api.v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -72,7 +72,7 @@ export type Attachment = Message<"memos.api.v1.Attachment"> & {
|
||||
*
|
||||
* @generated from field: google.protobuf.Timestamp create_time = 2;
|
||||
*/
|
||||
createTime?: Timestamp;
|
||||
createTime?: Timestamp | undefined;
|
||||
|
||||
/**
|
||||
* The filename of the attachment.
|
||||
@@ -115,14 +115,14 @@ export type Attachment = Message<"memos.api.v1.Attachment"> & {
|
||||
*
|
||||
* @generated from field: optional string memo = 8;
|
||||
*/
|
||||
memo?: string;
|
||||
memo?: string | undefined;
|
||||
|
||||
/**
|
||||
* Optional. Motion media metadata.
|
||||
*
|
||||
* @generated from field: memos.api.v1.MotionMedia motion_media = 9;
|
||||
*/
|
||||
motionMedia?: MotionMedia;
|
||||
motionMedia?: MotionMedia | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -141,7 +141,7 @@ export type CreateAttachmentRequest = Message<"memos.api.v1.CreateAttachmentRequ
|
||||
*
|
||||
* @generated from field: memos.api.v1.Attachment attachment = 1;
|
||||
*/
|
||||
attachment?: Attachment;
|
||||
attachment?: Attachment | undefined;
|
||||
|
||||
/**
|
||||
* Optional. The attachment ID to use for this attachment.
|
||||
@@ -270,14 +270,14 @@ export type UpdateAttachmentRequest = Message<"memos.api.v1.UpdateAttachmentRequ
|
||||
*
|
||||
* @generated from field: memos.api.v1.Attachment attachment = 1;
|
||||
*/
|
||||
attachment?: Attachment;
|
||||
attachment?: Attachment | undefined;
|
||||
|
||||
/**
|
||||
* Required. The list of fields to update.
|
||||
*
|
||||
* @generated from field: google.protobuf.FieldMask update_mask = 2;
|
||||
*/
|
||||
updateMask?: FieldMask;
|
||||
updateMask?: FieldMask | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file api/v1/auth_service.proto (package memos.api.v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -40,7 +40,7 @@ export type GetCurrentUserResponse = Message<"memos.api.v1.GetCurrentUserRespons
|
||||
*
|
||||
* @generated from field: memos.api.v1.User user = 1;
|
||||
*/
|
||||
user?: User;
|
||||
user?: User | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -166,7 +166,7 @@ export type SignInResponse = Message<"memos.api.v1.SignInResponse"> & {
|
||||
*
|
||||
* @generated from field: memos.api.v1.User user = 1;
|
||||
*/
|
||||
user?: User;
|
||||
user?: User | undefined;
|
||||
|
||||
/**
|
||||
* The short-lived access token for API requests.
|
||||
@@ -182,7 +182,7 @@ export type SignInResponse = Message<"memos.api.v1.SignInResponse"> & {
|
||||
*
|
||||
* @generated from field: google.protobuf.Timestamp access_token_expires_at = 3;
|
||||
*/
|
||||
accessTokenExpiresAt?: Timestamp;
|
||||
accessTokenExpiresAt?: Timestamp | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -234,7 +234,7 @@ export type RefreshTokenResponse = Message<"memos.api.v1.RefreshTokenResponse">
|
||||
*
|
||||
* @generated from field: google.protobuf.Timestamp expires_at = 2;
|
||||
*/
|
||||
expiresAt?: Timestamp;
|
||||
expiresAt?: Timestamp | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file api/v1/common.proto (package memos.api.v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file api/v1/idp_service.proto (package memos.api.v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -56,7 +56,7 @@ export type IdentityProvider = Message<"memos.api.v1.IdentityProvider"> & {
|
||||
*
|
||||
* @generated from field: memos.api.v1.IdentityProviderConfig config = 5;
|
||||
*/
|
||||
config?: IdentityProviderConfig;
|
||||
config?: IdentityProviderConfig | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,7 +181,7 @@ export type OAuth2Config = Message<"memos.api.v1.OAuth2Config"> & {
|
||||
/**
|
||||
* @generated from field: memos.api.v1.FieldMapping field_mapping = 7;
|
||||
*/
|
||||
fieldMapping?: FieldMapping;
|
||||
fieldMapping?: FieldMapping | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -252,7 +252,7 @@ export type CreateIdentityProviderRequest = Message<"memos.api.v1.CreateIdentity
|
||||
*
|
||||
* @generated from field: memos.api.v1.IdentityProvider identity_provider = 1;
|
||||
*/
|
||||
identityProvider?: IdentityProvider;
|
||||
identityProvider?: IdentityProvider | undefined;
|
||||
|
||||
/**
|
||||
* Optional. The ID to use for the identity provider, which will become the final component of the resource name.
|
||||
@@ -279,7 +279,7 @@ export type UpdateIdentityProviderRequest = Message<"memos.api.v1.UpdateIdentity
|
||||
*
|
||||
* @generated from field: memos.api.v1.IdentityProvider identity_provider = 1;
|
||||
*/
|
||||
identityProvider?: IdentityProvider;
|
||||
identityProvider?: IdentityProvider | undefined;
|
||||
|
||||
/**
|
||||
* Required. The update mask applies to the resource. Only the top level fields of
|
||||
@@ -287,7 +287,7 @@ export type UpdateIdentityProviderRequest = Message<"memos.api.v1.UpdateIdentity
|
||||
*
|
||||
* @generated from field: google.protobuf.FieldMask update_mask = 2;
|
||||
*/
|
||||
updateMask?: FieldMask;
|
||||
updateMask?: FieldMask | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file api/v1/shortcut_service.proto (package memos.api.v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -128,7 +128,7 @@ export type CreateShortcutRequest = Message<"memos.api.v1.CreateShortcutRequest"
|
||||
*
|
||||
* @generated from field: memos.api.v1.Shortcut shortcut = 2;
|
||||
*/
|
||||
shortcut?: Shortcut;
|
||||
shortcut?: Shortcut | undefined;
|
||||
|
||||
/**
|
||||
* Optional. If set, validate the request, but do not actually create the shortcut.
|
||||
@@ -154,14 +154,14 @@ export type UpdateShortcutRequest = Message<"memos.api.v1.UpdateShortcutRequest"
|
||||
*
|
||||
* @generated from field: memos.api.v1.Shortcut shortcut = 1;
|
||||
*/
|
||||
shortcut?: Shortcut;
|
||||
shortcut?: Shortcut | undefined;
|
||||
|
||||
/**
|
||||
* Optional. The list of fields to update.
|
||||
*
|
||||
* @generated from field: google.protobuf.FieldMask update_mask = 2;
|
||||
*/
|
||||
updateMask?: FieldMask;
|
||||
updateMask?: FieldMask | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/api/annotations.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/api/client.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -57,7 +57,7 @@ export type CommonLanguageSettings = Message<"google.api.CommonLanguageSettings"
|
||||
*
|
||||
* @generated from field: google.api.SelectiveGapicGeneration selective_gapic_generation = 3;
|
||||
*/
|
||||
selectiveGapicGeneration?: SelectiveGapicGeneration;
|
||||
selectiveGapicGeneration?: SelectiveGapicGeneration | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,56 +102,56 @@ export type ClientLibrarySettings = Message<"google.api.ClientLibrarySettings">
|
||||
*
|
||||
* @generated from field: google.api.JavaSettings java_settings = 21;
|
||||
*/
|
||||
javaSettings?: JavaSettings;
|
||||
javaSettings?: JavaSettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for C++ client libraries.
|
||||
*
|
||||
* @generated from field: google.api.CppSettings cpp_settings = 22;
|
||||
*/
|
||||
cppSettings?: CppSettings;
|
||||
cppSettings?: CppSettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for PHP client libraries.
|
||||
*
|
||||
* @generated from field: google.api.PhpSettings php_settings = 23;
|
||||
*/
|
||||
phpSettings?: PhpSettings;
|
||||
phpSettings?: PhpSettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for Python client libraries.
|
||||
*
|
||||
* @generated from field: google.api.PythonSettings python_settings = 24;
|
||||
*/
|
||||
pythonSettings?: PythonSettings;
|
||||
pythonSettings?: PythonSettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for Node client libraries.
|
||||
*
|
||||
* @generated from field: google.api.NodeSettings node_settings = 25;
|
||||
*/
|
||||
nodeSettings?: NodeSettings;
|
||||
nodeSettings?: NodeSettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for .NET client libraries.
|
||||
*
|
||||
* @generated from field: google.api.DotnetSettings dotnet_settings = 26;
|
||||
*/
|
||||
dotnetSettings?: DotnetSettings;
|
||||
dotnetSettings?: DotnetSettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for Ruby client libraries.
|
||||
*
|
||||
* @generated from field: google.api.RubySettings ruby_settings = 27;
|
||||
*/
|
||||
rubySettings?: RubySettings;
|
||||
rubySettings?: RubySettings | undefined;
|
||||
|
||||
/**
|
||||
* Settings for Go client libraries.
|
||||
*
|
||||
* @generated from field: google.api.GoSettings go_settings = 28;
|
||||
*/
|
||||
goSettings?: GoSettings;
|
||||
goSettings?: GoSettings | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -313,7 +313,7 @@ export type JavaSettings = Message<"google.api.JavaSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 3;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -334,7 +334,7 @@ export type CppSettings = Message<"google.api.CppSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -355,7 +355,7 @@ export type PhpSettings = Message<"google.api.PhpSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -376,14 +376,14 @@ export type PythonSettings = Message<"google.api.PythonSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
|
||||
/**
|
||||
* Experimental features to be included during client library generation.
|
||||
*
|
||||
* @generated from field: google.api.PythonSettings.ExperimentalFeatures experimental_features = 2;
|
||||
*/
|
||||
experimentalFeatures?: PythonSettings_ExperimentalFeatures;
|
||||
experimentalFeatures?: PythonSettings_ExperimentalFeatures | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -450,7 +450,7 @@ export type NodeSettings = Message<"google.api.NodeSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -471,7 +471,7 @@ export type DotnetSettings = Message<"google.api.DotnetSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
|
||||
/**
|
||||
* Map from original service names to renamed versions.
|
||||
@@ -542,7 +542,7 @@ export type RubySettings = Message<"google.api.RubySettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -563,7 +563,7 @@ export type GoSettings = Message<"google.api.GoSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.CommonLanguageSettings common = 1;
|
||||
*/
|
||||
common?: CommonLanguageSettings;
|
||||
common?: CommonLanguageSettings | undefined;
|
||||
|
||||
/**
|
||||
* Map of service names to renamed services. Keys are the package relative
|
||||
@@ -626,7 +626,7 @@ export type MethodSettings = Message<"google.api.MethodSettings"> & {
|
||||
*
|
||||
* @generated from field: google.api.MethodSettings.LongRunning long_running = 2;
|
||||
*/
|
||||
longRunning?: MethodSettings_LongRunning;
|
||||
longRunning?: MethodSettings_LongRunning | undefined;
|
||||
|
||||
/**
|
||||
* List of top-level fields of the request message, that should be
|
||||
@@ -669,7 +669,7 @@ export type MethodSettings_LongRunning = Message<"google.api.MethodSettings.Long
|
||||
*
|
||||
* @generated from field: google.protobuf.Duration initial_poll_delay = 1;
|
||||
*/
|
||||
initialPollDelay?: Duration;
|
||||
initialPollDelay?: Duration | undefined;
|
||||
|
||||
/**
|
||||
* Multiplier to gradually increase delay between subsequent polls until it
|
||||
@@ -686,7 +686,7 @@ export type MethodSettings_LongRunning = Message<"google.api.MethodSettings.Long
|
||||
*
|
||||
* @generated from field: google.protobuf.Duration max_poll_delay = 3;
|
||||
*/
|
||||
maxPollDelay?: Duration;
|
||||
maxPollDelay?: Duration | undefined;
|
||||
|
||||
/**
|
||||
* Total polling timeout.
|
||||
@@ -694,7 +694,7 @@ export type MethodSettings_LongRunning = Message<"google.api.MethodSettings.Long
|
||||
*
|
||||
* @generated from field: google.protobuf.Duration total_poll_timeout = 4;
|
||||
*/
|
||||
totalPollTimeout?: Duration;
|
||||
totalPollTimeout?: Duration | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/api/field_behavior.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/api/http.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/api/launch_stage.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/api/resource.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.12.0 with parameter "target=ts"
|
||||
// @generated from file google/type/color.proto (package google.type, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
@@ -192,7 +192,7 @@ export type Color = Message<"google.type.Color"> & {
|
||||
*
|
||||
* @generated from field: google.protobuf.FloatValue alpha = 4;
|
||||
*/
|
||||
alpha?: number;
|
||||
alpha?: number | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user