From ed89cb83104903fa7460f8e0e35537870353ddaa Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 19 Mar 2024 21:53:44 +0800 Subject: [PATCH] chore: update memo relation definition --- proto/api/v2/memo_relation_service.proto | 9 +- proto/gen/api/v2/README.md | 4 +- proto/gen/api/v2/memo_relation_service.pb.go | 70 +-- server/route/api/v2/apidocs.swagger.md | 554 +++++++++--------- server/route/api/v2/apidocs.swagger.yaml | 16 +- server/route/api/v2/memo_relation_service.go | 15 +- server/route/api/v2/memo_service.go | 11 - .../ActionButton/AddMemoRelationButton.tsx | 8 +- .../MemoEditor/RelationListView.tsx | 6 +- web/src/components/MemoEditor/index.tsx | 5 +- web/src/components/MemoRelationListView.tsx | 16 +- web/src/components/MemoView.tsx | 2 +- web/src/pages/MemoDetail.tsx | 10 +- 13 files changed, 369 insertions(+), 357 deletions(-) diff --git a/proto/api/v2/memo_relation_service.proto b/proto/api/v2/memo_relation_service.proto index 8bd917574..c8387e3b3 100644 --- a/proto/api/v2/memo_relation_service.proto +++ b/proto/api/v2/memo_relation_service.proto @@ -5,8 +5,13 @@ package memos.api.v2; option go_package = "gen/api/v2"; message MemoRelation { - int32 memo_id = 1; - int32 related_memo_id = 2; + // The name of memo. + // Format: "memos/{uid}" + string memo = 1; + + // The name of related memo. + // Format: "memos/{uid}" + string related_memo = 2; enum Type { TYPE_UNSPECIFIED = 0; diff --git a/proto/gen/api/v2/README.md b/proto/gen/api/v2/README.md index d04fb0d9f..ac7a76c5f 100644 --- a/proto/gen/api/v2/README.md +++ b/proto/gen/api/v2/README.md @@ -1226,8 +1226,8 @@ Used internally for obfuscating the page token. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| memo_id | [int32](#int32) | | | -| related_memo_id | [int32](#int32) | | | +| memo | [string](#string) | | The name of memo. Format: "memos/{uid}" | +| related_memo | [string](#string) | | The name of related memo. Format: "memos/{uid}" | | type | [MemoRelation.Type](#memos-api-v2-MemoRelation-Type) | | | diff --git a/proto/gen/api/v2/memo_relation_service.pb.go b/proto/gen/api/v2/memo_relation_service.pb.go index 28d0644dd..62345e78b 100644 --- a/proto/gen/api/v2/memo_relation_service.pb.go +++ b/proto/gen/api/v2/memo_relation_service.pb.go @@ -74,9 +74,13 @@ type MemoRelation struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - MemoId int32 `protobuf:"varint,1,opt,name=memo_id,json=memoId,proto3" json:"memo_id,omitempty"` - RelatedMemoId int32 `protobuf:"varint,2,opt,name=related_memo_id,json=relatedMemoId,proto3" json:"related_memo_id,omitempty"` - Type MemoRelation_Type `protobuf:"varint,3,opt,name=type,proto3,enum=memos.api.v2.MemoRelation_Type" json:"type,omitempty"` + // The name of memo. + // Format: "memos/{uid}" + Memo string `protobuf:"bytes,1,opt,name=memo,proto3" json:"memo,omitempty"` + // The name of related memo. + // Format: "memos/{uid}" + RelatedMemo string `protobuf:"bytes,2,opt,name=related_memo,json=relatedMemo,proto3" json:"related_memo,omitempty"` + Type MemoRelation_Type `protobuf:"varint,3,opt,name=type,proto3,enum=memos.api.v2.MemoRelation_Type" json:"type,omitempty"` } func (x *MemoRelation) Reset() { @@ -111,18 +115,18 @@ func (*MemoRelation) Descriptor() ([]byte, []int) { return file_api_v2_memo_relation_service_proto_rawDescGZIP(), []int{0} } -func (x *MemoRelation) GetMemoId() int32 { +func (x *MemoRelation) GetMemo() string { if x != nil { - return x.MemoId + return x.Memo } - return 0 + return "" } -func (x *MemoRelation) GetRelatedMemoId() int32 { +func (x *MemoRelation) GetRelatedMemo() string { if x != nil { - return x.RelatedMemoId + return x.RelatedMemo } - return 0 + return "" } func (x *MemoRelation) GetType() MemoRelation_Type { @@ -138,30 +142,30 @@ var file_api_v2_memo_relation_service_proto_rawDesc = []byte{ 0x0a, 0x22, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x32, 0x22, 0xbe, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, - 0x6d, 0x6f, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x32, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x38, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x52, 0x45, 0x46, 0x45, 0x52, - 0x45, 0x4e, 0x43, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, - 0x54, 0x10, 0x02, 0x42, 0xb0, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, - 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, - 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, - 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, - 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, - 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, - 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x32, 0x22, 0xb4, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x12, 0x33, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x38, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, + 0x09, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, 0x4e, 0x43, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, + 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x42, 0xb0, 0x01, 0x0a, 0x10, 0x63, 0x6f, + 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x18, + 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, + 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, + 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, + 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, + 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, + 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/server/route/api/v2/apidocs.swagger.md b/server/route/api/v2/apidocs.swagger.md index 780834987..a486ebe3b 100644 --- a/server/route/api/v2/apidocs.swagger.md +++ b/server/route/api/v2/apidocs.swagger.md @@ -143,6 +143,24 @@ UpdateInbox updates an inbox. ### /api/v2/{name_1} +#### GET +##### Summary + +GetMemo gets a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name_1 | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2GetMemoResponse](#v2getmemoresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + #### DELETE ##### Summary @@ -223,26 +241,6 @@ CreateMemo creates a memo. | 200 | A successful response. | [v2CreateMemoResponse](#v2creatememoresponse) | | default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | -### /api/v2/memos/name/{name} - -#### GET -##### Summary - -GetMemoByName gets a memo by name. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| name | path | | Yes | string | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2GetMemoByNameResponse](#v2getmemobynameresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - ### /api/v2/memos/stats #### GET @@ -254,7 +252,7 @@ GetUserMemosStats gets stats of memos for a user. | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| name | query | name is the name of the user to get stats for. Format: users/{username} | No | string | +| name | query | name is the name of the user to get stats for. Format: users/{uid} | No | string | | timezone | query | timezone location Format: uses tz identifier https://en.wikipedia.org/wiki/List_of_tz_database_time_zones | No | string | | filter | query | Same as ListMemosRequest.filter | No | string | @@ -265,246 +263,6 @@ GetUserMemosStats gets stats of memos for a user. | 200 | A successful response. | [v2GetUserMemosStatsResponse](#v2getusermemosstatsresponse) | | default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | -### /api/v2/memos/{id} - -#### GET -##### Summary - -GetMemo gets a memo by id. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2GetMemoResponse](#v2getmemoresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -#### DELETE -##### Summary - -DeleteMemo deletes a memo by id. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2DeleteMemoResponse](#v2deletememoresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -### /api/v2/memos/{id}/comments - -#### GET -##### Summary - -ListMemoComments lists comments for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2ListMemoCommentsResponse](#v2listmemocommentsresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -#### POST -##### Summary - -CreateMemoComment creates a comment for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | id is the memo id to create comment for. | Yes | integer | -| create.content | query | | No | string | -| create.visibility | query | | No | string | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2CreateMemoCommentResponse](#v2creatememocommentresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -### /api/v2/memos/{id}/reactions - -#### GET -##### Summary - -ListMemoReactions lists reactions for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2ListMemoReactionsResponse](#v2listmemoreactionsresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -#### POST -##### Summary - -UpsertMemoReaction upserts a reaction for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | -| reaction.id | query | | No | integer | -| reaction.creator | query | The name of the creator. Format: users/{uid} | No | string | -| reaction.contentId | query | | No | string | -| reaction.reactionType | query | | No | string | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2UpsertMemoReactionResponse](#v2upsertmemoreactionresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -### /api/v2/memos/{id}/reactions/{reactionId} - -#### DELETE -##### Summary - -DeleteMemoReaction deletes a reaction for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | -| reactionId | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2DeleteMemoReactionResponse](#v2deletememoreactionresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -### /api/v2/memos/{id}/relations - -#### GET -##### Summary - -ListMemoRelations lists relations for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2ListMemoRelationsResponse](#v2listmemorelationsresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -#### POST -##### Summary - -SetMemoRelations sets relations for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | -| body | body | | Yes | [MemoServiceSetMemoRelationsBody](#memoservicesetmemorelationsbody) | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2SetMemoRelationsResponse](#v2setmemorelationsresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -### /api/v2/memos/{id}/resources - -#### GET -##### Summary - -ListMemoResources lists resources for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2ListMemoResourcesResponse](#v2listmemoresourcesresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -#### POST -##### Summary - -SetMemoResources sets resources for a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| id | path | | Yes | integer | -| body | body | | Yes | [MemoServiceSetMemoResourcesBody](#memoservicesetmemoresourcesbody) | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2SetMemoResourcesResponse](#v2setmemoresourcesresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - -### /api/v2/memos/{memo.id} - -#### PATCH -##### Summary - -UpdateMemo updates a memo. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| memo.id | path | id is the system generated unique identifier. | Yes | integer | -| memo | body | | Yes | { **"name"**: string, **"rowStatus"**: [apiv2RowStatus](#apiv2rowstatus), **"creator"**: string, **"createTime"**: dateTime, **"updateTime"**: dateTime, **"displayTime"**: dateTime, **"content"**: string, **"visibility"**: [v2Visibility](#v2visibility), **"pinned"**: boolean, **"parentId"**: integer, **"resources"**: [ [v2Resource](#v2resource) ], **"relations"**: [ [v2MemoRelation](#v2memorelation) ], **"reactions"**: [ [apiv2Reaction](#apiv2reaction) ] } | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [v2UpdateMemoResponse](#v2updatememoresponse) | -| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | - ### /api/v2/memos:export #### POST @@ -545,6 +303,266 @@ SearchMemosRequest searches memos. | 200 | A successful response. | [v2SearchMemosResponse](#v2searchmemosresponse) | | default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | +### /api/v2/{memo.name} + +#### PATCH +##### Summary + +UpdateMemo updates a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| memo.name | path | The name of the memo. Format: memos/{uid} | Yes | string | +| memo | body | | Yes | { **"resourceId"**: string, **"rowStatus"**: [apiv2RowStatus](#apiv2rowstatus), **"creator"**: string, **"createTime"**: dateTime, **"updateTime"**: dateTime, **"displayTime"**: dateTime, **"content"**: string, **"visibility"**: [v2Visibility](#v2visibility), **"pinned"**: boolean, **"parentId"**: integer, **"resources"**: [ [v2Resource](#v2resource) ], **"relations"**: [ [v2MemoRelation](#v2memorelation) ], **"reactions"**: [ [apiv2Reaction](#apiv2reaction) ] } | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2UpdateMemoResponse](#v2updatememoresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name_1} + +#### GET +##### Summary + +GetMemo gets a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name_1 | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2GetMemoResponse](#v2getmemoresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +#### DELETE +##### Summary + +DeleteInbox deletes an inbox. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name_1 | path | The name of the inbox to delete. Format: inboxes/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2DeleteInboxResponse](#v2deleteinboxresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name_2} + +#### DELETE +##### Summary + +DeleteMemo deletes a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name_2 | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2DeleteMemoResponse](#v2deletememoresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name}/comments + +#### GET +##### Summary + +ListMemoComments lists comments for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2ListMemoCommentsResponse](#v2listmemocommentsresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +#### POST +##### Summary + +CreateMemoComment creates a comment for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | +| comment.content | query | | No | string | +| comment.visibility | query | | No | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2CreateMemoCommentResponse](#v2creatememocommentresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name}/reactions + +#### GET +##### Summary + +ListMemoReactions lists reactions for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2ListMemoReactionsResponse](#v2listmemoreactionsresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +#### POST +##### Summary + +UpsertMemoReaction upserts a reaction for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | +| reaction.id | query | | No | integer | +| reaction.creator | query | The name of the creator. Format: users/{uid} | No | string | +| reaction.contentId | query | | No | string | +| reaction.reactionType | query | | No | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2UpsertMemoReactionResponse](#v2upsertmemoreactionresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name}/reactions/{reactionId} + +#### DELETE +##### Summary + +DeleteMemoReaction deletes a reaction for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | +| reactionId | path | | Yes | integer | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2DeleteMemoReactionResponse](#v2deletememoreactionresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name}/relations + +#### GET +##### Summary + +ListMemoRelations lists relations for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2ListMemoRelationsResponse](#v2listmemorelationsresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +#### POST +##### Summary + +SetMemoRelations sets relations for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | +| body | body | | Yes | [MemoServiceSetMemoRelationsBody](#memoservicesetmemorelationsbody) | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2SetMemoRelationsResponse](#v2setmemorelationsresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +### /api/v2/{name}/resources + +#### GET +##### Summary + +ListMemoResources lists resources for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2ListMemoResourcesResponse](#v2listmemoresourcesresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + +#### POST +##### Summary + +SetMemoResources sets resources for a memo. + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| name | path | The name of the memo. Format: memos/{uid} | Yes | string | +| body | body | | Yes | [MemoServiceSetMemoResourcesBody](#memoservicesetmemoresourcesbody) | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | A successful response. | [v2SetMemoResourcesResponse](#v2setmemoresourcesresponse) | +| default | An unexpected error response. | [googlerpcStatus](#googlerpcstatus) | + --- ## ResourceService @@ -1439,12 +1457,6 @@ GetActivity returns the activity with the given id. | ---- | ---- | ----------- | -------- | | linkMetadata | [v2LinkMetadata](#v2linkmetadata) | | No | -#### v2GetMemoByNameResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| memo | [v2Memo](#v2memo) | | No | - #### v2GetMemoResponse | Name | Type | Description | Required | @@ -1608,8 +1620,8 @@ GetActivity returns the activity with the given id. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| id | integer | id is the system generated unique identifier. | No | -| name | string | name is the user provided name. | No | +| name | string | | No | +| resourceId | string | | No | | rowStatus | [apiv2RowStatus](#apiv2rowstatus) | | No | | creator | string | | No | | createTime | dateTime | | No | @@ -1627,8 +1639,8 @@ GetActivity returns the activity with the given id. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| memoId | integer | | No | -| relatedMemoId | integer | | No | +| memo | string | | No | +| relatedMemo | string | | No | | type | [v2MemoRelationType](#v2memorelationtype) | | No | #### v2MemoRelationType diff --git a/server/route/api/v2/apidocs.swagger.yaml b/server/route/api/v2/apidocs.swagger.yaml index 53df0b1b2..afab175bc 100644 --- a/server/route/api/v2/apidocs.swagger.yaml +++ b/server/route/api/v2/apidocs.swagger.yaml @@ -2130,12 +2130,16 @@ definitions: v2MemoRelation: type: object properties: - memoId: - type: integer - format: int32 - relatedMemoId: - type: integer - format: int32 + memo: + type: string + title: |- + The name of memo. + Format: "memos/{uid}" + relatedMemo: + type: string + title: |- + The name of related memo. + Format: "memos/{uid}" type: $ref: '#/definitions/v2MemoRelationType' v2MemoRelationType: diff --git a/server/route/api/v2/memo_relation_service.go b/server/route/api/v2/memo_relation_service.go index 5aab45c78..9e4967be6 100644 --- a/server/route/api/v2/memo_relation_service.go +++ b/server/route/api/v2/memo_relation_service.go @@ -2,6 +2,7 @@ package v2 import ( "context" + "fmt" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -26,7 +27,7 @@ func (s *APIV2Service) SetMemoRelations(ctx context.Context, request *apiv2pb.Se for _, relation := range request.Relations { // Ignore reflexive relations. - if id == relation.RelatedMemoId { + if request.Name == relation.RelatedMemo { continue } // Ignore comment relations as there's no need to update a comment's relation. @@ -34,9 +35,13 @@ func (s *APIV2Service) SetMemoRelations(ctx context.Context, request *apiv2pb.Se if relation.Type == apiv2pb.MemoRelation_COMMENT { continue } + relatedMemoID, err := ExtractMemoIDFromName(relation.RelatedMemo) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid related memo name: %v", err) + } if _, err := s.Store.UpsertMemoRelation(ctx, &store.MemoRelation{ MemoID: id, - RelatedMemoID: relation.RelatedMemoId, + RelatedMemoID: relatedMemoID, Type: convertMemoRelationTypeToStore(relation.Type), }); err != nil { return nil, status.Errorf(codes.Internal, "failed to upsert memo relation") @@ -79,9 +84,9 @@ func (s *APIV2Service) ListMemoRelations(ctx context.Context, request *apiv2pb.L func convertMemoRelationFromStore(memoRelation *store.MemoRelation) *apiv2pb.MemoRelation { return &apiv2pb.MemoRelation{ - MemoId: memoRelation.MemoID, - RelatedMemoId: memoRelation.RelatedMemoID, - Type: convertMemoRelationTypeFromStore(memoRelation.Type), + Memo: fmt.Sprintf("%s%d", MemoNamePrefix, memoRelation.MemoID), + RelatedMemo: fmt.Sprintf("%s%d", MemoNamePrefix, memoRelation.RelatedMemoID), + Type: convertMemoRelationTypeFromStore(memoRelation.Type), } } diff --git a/server/route/api/v2/memo_service.go b/server/route/api/v2/memo_service.go index f15ce9fae..18ab5ccb9 100644 --- a/server/route/api/v2/memo_service.go +++ b/server/route/api/v2/memo_service.go @@ -883,17 +883,6 @@ func convertMemoToWebhookPayload(memo *apiv2pb.Memo) (*webhook.WebhookPayload, e } return resources }(), - RelationList: func() []*webhook.MemoRelation { - relations := []*webhook.MemoRelation{} - for _, relation := range memo.Relations { - relations = append(relations, &webhook.MemoRelation{ - MemoID: relation.MemoId, - RelatedMemoID: relation.RelatedMemoId, - Type: relation.Type.String(), - }) - } - return relations - }(), }, }, nil } diff --git a/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx b/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx index 5ccc242c7..155e49cac 100644 --- a/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx +++ b/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx @@ -5,7 +5,7 @@ import toast from "react-hot-toast"; import showCreateMemoRelationDialog from "@/components/CreateMemoRelationDialog"; import Icon from "@/components/Icon"; import { UNKNOWN_ID } from "@/helpers/consts"; -import { extractMemoIdFromName } from "@/store/v1"; +import { MemoNamePrefix } from "@/store/v1"; import { MemoRelation_Type } from "@/types/proto/api/v2/memo_relation_service"; import { EditorRefActions } from "../Editor"; import { MemoEditorContext } from "../types"; @@ -47,12 +47,12 @@ const AddMemoRelationButton = (props: Props) => { uniqBy( [ ...memos.map((memo) => ({ - memoId: context.memoId || UNKNOWN_ID, - relatedMemoId: extractMemoIdFromName(memo.name), + memo: `${MemoNamePrefix}${context.memoId || UNKNOWN_ID}`, + relatedMemo: memo.name, type: MemoRelation_Type.REFERENCE, })), ...context.relationList, - ].filter((relation) => relation.relatedMemoId !== (context.memoId || UNKNOWN_ID)), + ].filter((relation) => relation.relatedMemo !== `${MemoNamePrefix}${context.memoId || UNKNOWN_ID}`), "relatedMemoId", ), ); diff --git a/web/src/components/MemoEditor/RelationListView.tsx b/web/src/components/MemoEditor/RelationListView.tsx index 8c144bcdc..7805dbfd2 100644 --- a/web/src/components/MemoEditor/RelationListView.tsx +++ b/web/src/components/MemoEditor/RelationListView.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { MemoNamePrefix, extractMemoIdFromName, useMemoStore } from "@/store/v1"; +import { useMemoStore } from "@/store/v1"; import { MemoRelation, MemoRelation_Type } from "@/types/proto/api/v2/memo_relation_service"; import { Memo } from "@/types/proto/api/v2/memo_service"; import Icon from "../Icon"; @@ -19,7 +19,7 @@ const RelationListView = (props: Props) => { const requests = relationList .filter((relation) => relation.type === MemoRelation_Type.REFERENCE) .map(async (relation) => { - return await memoStore.getOrFetchMemoByName(`${MemoNamePrefix}${relation.relatedMemoId}`, { skipStore: true }); + return await memoStore.getOrFetchMemoByName(relation.relatedMemo, { skipStore: true }); }); const list = await Promise.all(requests); setReferencingMemoList(list); @@ -27,7 +27,7 @@ const RelationListView = (props: Props) => { }, [relationList]); const handleDeleteRelation = async (memo: Memo) => { - setRelationList(relationList.filter((relation) => relation.relatedMemoId !== extractMemoIdFromName(memo.name))); + setRelationList(relationList.filter((relation) => relation.relatedMemo !== memo.name)); }; return ( diff --git a/web/src/components/MemoEditor/index.tsx b/web/src/components/MemoEditor/index.tsx index 10831fa2e..b6c6455bc 100644 --- a/web/src/components/MemoEditor/index.tsx +++ b/web/src/components/MemoEditor/index.tsx @@ -75,7 +75,10 @@ const MemoEditor = (props: Props) => { const [contentCache, setContentCache] = useLocalStorage(contentCacheKey, ""); const referenceRelations = memoId ? state.relationList.filter( - (relation) => relation.memoId === memoId && relation.relatedMemoId !== memoId && relation.type === MemoRelation_Type.REFERENCE, + (relation) => + extractMemoIdFromName(relation.memo) === memoId && + extractMemoIdFromName(relation.relatedMemo) !== memoId && + relation.type === MemoRelation_Type.REFERENCE, ) : state.relationList.filter((relation) => relation.type === MemoRelation_Type.REFERENCE); diff --git a/web/src/components/MemoRelationListView.tsx b/web/src/components/MemoRelationListView.tsx index bcbedb2e2..140ac529d 100644 --- a/web/src/components/MemoRelationListView.tsx +++ b/web/src/components/MemoRelationListView.tsx @@ -1,7 +1,7 @@ import { Tooltip } from "@mui/joy"; import { memo, useEffect, useState } from "react"; import { Link } from "react-router-dom"; -import { MemoNamePrefix, extractMemoIdFromName, useMemoStore } from "@/store/v1"; +import { useMemoStore } from "@/store/v1"; import { MemoRelation } from "@/types/proto/api/v2/memo_relation_service"; import { Memo } from "@/types/proto/api/v2/memo_service"; import Icon from "./Icon"; @@ -21,20 +21,14 @@ const MemoRelationListView = (props: Props) => { (async () => { const referencingMemoList = await Promise.all( relationList - .filter( - (relation) => - relation.memoId === extractMemoIdFromName(memo.name) && relation.relatedMemoId !== extractMemoIdFromName(memo.name), - ) - .map((relation) => memoStore.getOrFetchMemoByName(`${MemoNamePrefix}${relation.relatedMemoId}`, { skipStore: true })), + .filter((relation) => relation.memo === memo.name && relation.relatedMemo !== memo.name) + .map((relation) => memoStore.getOrFetchMemoByName(relation.relatedMemo, { skipStore: true })), ); setReferencingMemoList(referencingMemoList); const referencedMemoList = await Promise.all( relationList - .filter( - (relation) => - relation.memoId !== extractMemoIdFromName(memo.name) && relation.relatedMemoId === extractMemoIdFromName(memo.name), - ) - .map((relation) => memoStore.getOrFetchMemoByName(`${MemoNamePrefix}${relation.memoId}`, { skipStore: true })), + .filter((relation) => relation.memo !== memo.name && relation.relatedMemo === memo.name) + .map((relation) => memoStore.getOrFetchMemoByName(relation.memo, { skipStore: true })), ); setReferencedMemoList(referencedMemoList); })(); diff --git a/web/src/components/MemoView.tsx b/web/src/components/MemoView.tsx index a089907b6..31a0ea3a3 100644 --- a/web/src/components/MemoView.tsx +++ b/web/src/components/MemoView.tsx @@ -41,7 +41,7 @@ const MemoView: React.FC = (props: Props) => { const memoContainerRef = useRef(null); const referencedMemos = memo.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE); const commentAmount = memo.relations.filter( - (relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemoId === extractMemoIdFromName(memo.name), + (relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo === memo.name, ).length; const readonly = memo.creator !== user?.name; const isInMemoDetailPage = location.pathname.startsWith(`/m/${memo.name}`); diff --git a/web/src/pages/MemoDetail.tsx b/web/src/pages/MemoDetail.tsx index fb9991ef2..c31b5c6eb 100644 --- a/web/src/pages/MemoDetail.tsx +++ b/web/src/pages/MemoDetail.tsx @@ -23,12 +23,8 @@ const MemoDetail = () => { const memo = memoStore.getMemoByResourceId(resourceId || ""); const [parentMemo, setParentMemo] = useState(undefined); const commentRelations = - memo?.relations.filter( - (relation) => relation.relatedMemoId === extractMemoIdFromName(memo.name) && relation.type === MemoRelation_Type.COMMENT, - ) || []; - const comments = commentRelations - .map((relation) => memoStore.getMemoByName(`${MemoNamePrefix}${relation.memoId}`)) - .filter((memo) => memo) as any as Memo[]; + memo?.relations.filter((relation) => relation.relatedMemo === memo.name && relation.type === MemoRelation_Type.COMMENT) || []; + const comments = commentRelations.map((relation) => memoStore.getMemoByName(relation.memo)).filter((memo) => memo) as any as Memo[]; // Prepare memo. useEffect(() => { @@ -56,7 +52,7 @@ const MemoDetail = () => { } else { setParentMemo(undefined); } - await Promise.all(commentRelations.map((relation) => memoStore.getOrFetchMemoByName(`${MemoNamePrefix}${relation.memoId}`))); + await Promise.all(commentRelations.map((relation) => memoStore.getOrFetchMemoByName(relation.memo))); })(); }, [memo]);