Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
9361613f
Commit
9361613f
authored
Dec 21, 2023
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: update timeline page
parent
b1433422
Changes
21
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
2878 additions
and
303 deletions
+2878
-303
memo_service.go
api/v2/memo_service.go
+113
-0
memo_relation_service.proto
proto/api/v2/memo_relation_service.proto
+17
-0
memo_service.proto
proto/api/v2/memo_service.proto
+46
-0
README.md
proto/gen/api/v2/README.md
+142
-0
memo_relation_service.pb.go
proto/gen/api/v2/memo_relation_service.pb.go
+232
-0
memo_service.pb.go
proto/gen/api/v2/memo_service.pb.go
+671
-248
memo_service.pb.gw.go
proto/gen/api/v2/memo_service.pb.gw.go
+341
-0
memo_service_grpc.pb.go
proto/gen/api/v2/memo_service_grpc.pb.go
+111
-0
TagSelector.tsx
web/src/components/MemoEditorV1/ActionButton/TagSelector.tsx
+52
-0
TagSuggestions.tsx
web/src/components/MemoEditorV1/Editor/TagSuggestions.tsx
+136
-0
index.tsx
web/src/components/MemoEditorV1/Editor/index.tsx
+162
-0
MemoEditorDialog.tsx
web/src/components/MemoEditorV1/MemoEditorDialog.tsx
+59
-0
RelationListView.tsx
web/src/components/MemoEditorV1/RelationListView.tsx
+56
-0
ResourceListView.tsx
web/src/components/MemoEditorV1/ResourceListView.tsx
+42
-0
index.tsx
web/src/components/MemoEditorV1/index.tsx
+454
-0
MemoRelationListViewV1.tsx
web/src/components/MemoRelationListViewV1.tsx
+83
-0
TimelineMemo.tsx
web/src/components/TimelineMemo.tsx
+45
-0
VisibilityIconV1.tsx
web/src/components/VisibilityIconV1.tsx
+27
-0
Timeline.tsx
web/src/pages/Timeline.tsx
+33
-54
memo.ts
web/src/store/v1/memo.ts
+29
-1
memo.ts
web/src/utils/memo.ts
+27
-0
No files found.
api/v2/memo_service.go
View file @
9361613f
...
...
@@ -233,6 +233,44 @@ func (s *APIV2Service) DeleteMemo(ctx context.Context, request *apiv2pb.DeleteMe
return
&
apiv2pb
.
DeleteMemoResponse
{},
nil
}
func
(
s
*
APIV2Service
)
SetMemoResources
(
ctx
context
.
Context
,
request
*
apiv2pb
.
SetMemoResourcesRequest
)
(
*
apiv2pb
.
SetMemoResourcesResponse
,
error
)
{
resources
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
request
.
Id
})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list resources"
)
}
// Delete resources that are not in the request.
for
_
,
resource
:=
range
resources
{
found
:=
false
for
_
,
requestResource
:=
range
request
.
Resources
{
if
resource
.
ID
==
int32
(
requestResource
.
Id
)
{
found
=
true
break
}
}
if
!
found
{
if
err
=
s
.
Store
.
DeleteResource
(
ctx
,
&
store
.
DeleteResource
{
ID
:
int32
(
resource
.
ID
),
MemoID
:
&
request
.
Id
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to delete resource"
)
}
}
}
// Update resources' memo_id in the request.
for
_
,
resource
:=
range
request
.
Resources
{
if
_
,
err
:=
s
.
Store
.
UpdateResource
(
ctx
,
&
store
.
UpdateResource
{
ID
:
resource
.
Id
,
MemoID
:
&
request
.
Id
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to update resource"
)
}
}
return
&
apiv2pb
.
SetMemoResourcesResponse
{},
nil
}
func
(
s
*
APIV2Service
)
ListMemoResources
(
ctx
context
.
Context
,
request
*
apiv2pb
.
ListMemoResourcesRequest
)
(
*
apiv2pb
.
ListMemoResourcesResponse
,
error
)
{
resources
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
request
.
Id
,
...
...
@@ -250,6 +288,51 @@ func (s *APIV2Service) ListMemoResources(ctx context.Context, request *apiv2pb.L
return
response
,
nil
}
func
(
s
*
APIV2Service
)
SetMemoRelations
(
ctx
context
.
Context
,
request
*
apiv2pb
.
SetMemoRelationsRequest
)
(
*
apiv2pb
.
SetMemoRelationsResponse
,
error
)
{
if
err
:=
s
.
Store
.
DeleteMemoRelation
(
ctx
,
&
store
.
DeleteMemoRelation
{
MemoID
:
&
request
.
Id
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to delete memo relation"
)
}
for
_
,
relation
:=
range
request
.
Relations
{
if
_
,
err
:=
s
.
Store
.
UpsertMemoRelation
(
ctx
,
&
store
.
MemoRelation
{
MemoID
:
request
.
Id
,
RelatedMemoID
:
relation
.
RelatedMemoId
,
Type
:
convertMemoRelationTypeToStore
(
relation
.
Type
),
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to upsert memo relation"
)
}
}
return
&
apiv2pb
.
SetMemoRelationsResponse
{},
nil
}
func
(
s
*
APIV2Service
)
ListMemoRelations
(
ctx
context
.
Context
,
request
*
apiv2pb
.
ListMemoRelationsRequest
)
(
*
apiv2pb
.
ListMemoRelationsResponse
,
error
)
{
relationList
:=
[]
*
apiv2pb
.
MemoRelation
{}
tempList
,
err
:=
s
.
Store
.
ListMemoRelations
(
ctx
,
&
store
.
FindMemoRelation
{
MemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
relation
:=
range
tempList
{
relationList
=
append
(
relationList
,
convertMemoRelationFromStore
(
relation
))
}
tempList
,
err
=
s
.
Store
.
ListMemoRelations
(
ctx
,
&
store
.
FindMemoRelation
{
RelatedMemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
relation
:=
range
tempList
{
relationList
=
append
(
relationList
,
convertMemoRelationFromStore
(
relation
))
}
response
:=
&
apiv2pb
.
ListMemoRelationsResponse
{
Relations
:
relationList
,
}
return
response
,
nil
}
func
(
s
*
APIV2Service
)
CreateMemoComment
(
ctx
context
.
Context
,
request
*
apiv2pb
.
CreateMemoCommentRequest
)
(
*
apiv2pb
.
CreateMemoCommentResponse
,
error
)
{
// Create the comment memo first.
createMemoResponse
,
err
:=
s
.
CreateMemo
(
ctx
,
request
.
Create
)
...
...
@@ -348,6 +431,36 @@ func (s *APIV2Service) getMemoDisplayWithUpdatedTsSettingValue(ctx context.Conte
return
memoDisplayWithUpdatedTs
,
nil
}
func
convertMemoRelationFromStore
(
memoRelation
*
store
.
MemoRelation
)
*
apiv2pb
.
MemoRelation
{
return
&
apiv2pb
.
MemoRelation
{
MemoId
:
memoRelation
.
MemoID
,
RelatedMemoId
:
memoRelation
.
RelatedMemoID
,
Type
:
convertMemoRelationTypeFromStore
(
memoRelation
.
Type
),
}
}
func
convertMemoRelationTypeFromStore
(
relationType
store
.
MemoRelationType
)
apiv2pb
.
MemoRelation_Type
{
switch
relationType
{
case
store
.
MemoRelationReference
:
return
apiv2pb
.
MemoRelation_REFERENCE
case
store
.
MemoRelationComment
:
return
apiv2pb
.
MemoRelation_COMMENT
default
:
return
apiv2pb
.
MemoRelation_TYPE_UNSPECIFIED
}
}
func
convertMemoRelationTypeToStore
(
relationType
apiv2pb
.
MemoRelation_Type
)
store
.
MemoRelationType
{
switch
relationType
{
case
apiv2pb
.
MemoRelation_REFERENCE
:
return
store
.
MemoRelationReference
case
apiv2pb
.
MemoRelation_COMMENT
:
return
store
.
MemoRelationComment
default
:
return
store
.
MemoRelationReference
}
}
func
convertVisibilityFromStore
(
visibility
store
.
Visibility
)
apiv2pb
.
Visibility
{
switch
visibility
{
case
store
.
Private
:
...
...
proto/api/v2/memo_relation_service.proto
0 → 100644
View file @
9361613f
syntax
=
"proto3"
;
package
memos
.
api.v2
;
option
go_package
=
"gen/api/v2"
;
message
MemoRelation
{
int32
memo_id
=
1
;
int32
related_memo_id
=
2
;
enum
Type
{
TYPE_UNSPECIFIED
=
0
;
REFERENCE
=
1
;
COMMENT
=
2
;
}
Type
type
=
3
;
}
proto/api/v2/memo_service.proto
View file @
9361613f
...
...
@@ -4,6 +4,7 @@ package memos.api.v2;
import
"api/v2/common.proto"
;
import
"api/v2/markdown_service.proto"
;
import
"api/v2/memo_relation_service.proto"
;
import
"api/v2/resource_service.proto"
;
import
"google/api/annotations.proto"
;
import
"google/api/client.proto"
;
...
...
@@ -42,11 +43,32 @@ service MemoService {
option
(
google.api.method_signature
)
=
"id"
;
}
rpc
SetMemoResources
(
SetMemoResourcesRequest
)
returns
(
SetMemoResourcesResponse
)
{
option
(
google.api.http
)
=
{
post
:
"/api/v2/memos/{id}/resources"
body
:
"*"
};
option
(
google.api.method_signature
)
=
"id"
;
}
rpc
ListMemoResources
(
ListMemoResourcesRequest
)
returns
(
ListMemoResourcesResponse
)
{
option
(
google.api.http
)
=
{
get
:
"/api/v2/memos/{id}/resources"
};
option
(
google.api.method_signature
)
=
"id"
;
}
rpc
SetMemoRelations
(
SetMemoRelationsRequest
)
returns
(
SetMemoRelationsResponse
)
{
option
(
google.api.http
)
=
{
post
:
"/api/v2/memos/{id}/relations"
body
:
"*"
};
option
(
google.api.method_signature
)
=
"id"
;
}
rpc
ListMemoRelations
(
ListMemoRelationsRequest
)
returns
(
ListMemoRelationsResponse
)
{
option
(
google.api.http
)
=
{
get
:
"/api/v2/memos/{id}/relations"
};
option
(
google.api.method_signature
)
=
"id"
;
}
rpc
CreateMemoComment
(
CreateMemoCommentRequest
)
returns
(
CreateMemoCommentResponse
)
{
option
(
google.api.http
)
=
{
post
:
"/api/v2/memos/{id}/comments"
};
option
(
google.api.method_signature
)
=
"id"
;
...
...
@@ -139,6 +161,14 @@ message DeleteMemoRequest {
message
DeleteMemoResponse
{}
message
SetMemoResourcesRequest
{
int32
id
=
1
;
repeated
Resource
resources
=
2
;
}
message
SetMemoResourcesResponse
{}
message
ListMemoResourcesRequest
{
int32
id
=
1
;
}
...
...
@@ -147,6 +177,22 @@ message ListMemoResourcesResponse {
repeated
Resource
resources
=
1
;
}
message
SetMemoRelationsRequest
{
int32
id
=
1
;
repeated
MemoRelation
relations
=
2
;
}
message
SetMemoRelationsResponse
{}
message
ListMemoRelationsRequest
{
int32
id
=
1
;
}
message
ListMemoRelationsResponse
{
repeated
MemoRelation
relations
=
1
;
}
message
CreateMemoCommentRequest
{
// id is the memo id to create comment for.
int32
id
=
1
;
...
...
proto/gen/api/v2/README.md
View file @
9361613f
...
...
@@ -91,6 +91,11 @@
-
[
MarkdownService
](
#memos-api-v2-MarkdownService
)
-
[
api/v2/memo_relation_service.proto
](
#api_v2_memo_relation_service-proto
)
-
[
MemoRelation
](
#memos-api-v2-MemoRelation
)
-
[
MemoRelation.Type
](
#memos-api-v2-MemoRelation-Type
)
-
[
api/v2/resource_service.proto
](
#api_v2_resource_service-proto
)
-
[
CreateResourceRequest
](
#memos-api-v2-CreateResourceRequest
)
-
[
CreateResourceResponse
](
#memos-api-v2-CreateResourceResponse
)
...
...
@@ -115,11 +120,17 @@
-
[
GetMemoResponse
](
#memos-api-v2-GetMemoResponse
)
-
[
ListMemoCommentsRequest
](
#memos-api-v2-ListMemoCommentsRequest
)
-
[
ListMemoCommentsResponse
](
#memos-api-v2-ListMemoCommentsResponse
)
-
[
ListMemoRelationsRequest
](
#memos-api-v2-ListMemoRelationsRequest
)
-
[
ListMemoRelationsResponse
](
#memos-api-v2-ListMemoRelationsResponse
)
-
[
ListMemoResourcesRequest
](
#memos-api-v2-ListMemoResourcesRequest
)
-
[
ListMemoResourcesResponse
](
#memos-api-v2-ListMemoResourcesResponse
)
-
[
ListMemosRequest
](
#memos-api-v2-ListMemosRequest
)
-
[
ListMemosResponse
](
#memos-api-v2-ListMemosResponse
)
-
[
Memo
](
#memos-api-v2-Memo
)
-
[
SetMemoRelationsRequest
](
#memos-api-v2-SetMemoRelationsRequest
)
-
[
SetMemoRelationsResponse
](
#memos-api-v2-SetMemoRelationsResponse
)
-
[
SetMemoResourcesRequest
](
#memos-api-v2-SetMemoResourcesRequest
)
-
[
SetMemoResourcesResponse
](
#memos-api-v2-SetMemoResourcesResponse
)
-
[
UpdateMemoRequest
](
#memos-api-v2-UpdateMemoRequest
)
-
[
UpdateMemoResponse
](
#memos-api-v2-UpdateMemoResponse
)
...
...
@@ -1317,6 +1328,52 @@
<a
name=
"api_v2_memo_relation_service-proto"
></a>
<p
align=
"right"
><a
href=
"#top"
>
Top
</a></p>
## api/v2/memo_relation_service.proto
<a
name=
"memos-api-v2-MemoRelation"
></a>
### MemoRelation
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| memo_id |
[
int32
](
#int32
)
| | |
| related_memo_id |
[
int32
](
#int32
)
| | |
| type |
[
MemoRelation.Type
](
#memos-api-v2-MemoRelation-Type
)
| | |
<a
name=
"memos-api-v2-MemoRelation-Type"
></a>
### MemoRelation.Type
| Name | Number | Description |
| ---- | ------ | ----------- |
| TYPE_UNSPECIFIED | 0 | |
| REFERENCE | 1 | |
| COMMENT | 2 | |
<a
name=
"api_v2_resource_service-proto"
></a>
<p
align=
"right"
><a
href=
"#top"
>
Top
</a></p>
...
...
@@ -1635,6 +1692,36 @@
<a
name=
"memos-api-v2-ListMemoRelationsRequest"
></a>
### ListMemoRelationsRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id |
[
int32
](
#int32
)
| | |
<a
name=
"memos-api-v2-ListMemoRelationsResponse"
></a>
### ListMemoRelationsResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| relations |
[
MemoRelation
](
#memos-api-v2-MemoRelation
)
| repeated | |
<a
name=
"memos-api-v2-ListMemoResourcesRequest"
></a>
### ListMemoResourcesRequest
...
...
@@ -1721,6 +1808,58 @@
<a
name=
"memos-api-v2-SetMemoRelationsRequest"
></a>
### SetMemoRelationsRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id |
[
int32
](
#int32
)
| | |
| relations |
[
MemoRelation
](
#memos-api-v2-MemoRelation
)
| repeated | |
<a
name=
"memos-api-v2-SetMemoRelationsResponse"
></a>
### SetMemoRelationsResponse
<a
name=
"memos-api-v2-SetMemoResourcesRequest"
></a>
### SetMemoResourcesRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id |
[
int32
](
#int32
)
| | |
| resources |
[
Resource
](
#memos-api-v2-Resource
)
| repeated | |
<a
name=
"memos-api-v2-SetMemoResourcesResponse"
></a>
### SetMemoResourcesResponse
<a
name=
"memos-api-v2-UpdateMemoRequest"
></a>
### UpdateMemoRequest
...
...
@@ -1785,7 +1924,10 @@
| GetMemo |
[
GetMemoRequest
](
#memos-api-v2-GetMemoRequest
)
|
[
GetMemoResponse
](
#memos-api-v2-GetMemoResponse
)
| |
| UpdateMemo |
[
UpdateMemoRequest
](
#memos-api-v2-UpdateMemoRequest
)
|
[
UpdateMemoResponse
](
#memos-api-v2-UpdateMemoResponse
)
| |
| DeleteMemo |
[
DeleteMemoRequest
](
#memos-api-v2-DeleteMemoRequest
)
|
[
DeleteMemoResponse
](
#memos-api-v2-DeleteMemoResponse
)
| |
| SetMemoResources |
[
SetMemoResourcesRequest
](
#memos-api-v2-SetMemoResourcesRequest
)
|
[
SetMemoResourcesResponse
](
#memos-api-v2-SetMemoResourcesResponse
)
| |
| ListMemoResources |
[
ListMemoResourcesRequest
](
#memos-api-v2-ListMemoResourcesRequest
)
|
[
ListMemoResourcesResponse
](
#memos-api-v2-ListMemoResourcesResponse
)
| |
| SetMemoRelations |
[
SetMemoRelationsRequest
](
#memos-api-v2-SetMemoRelationsRequest
)
|
[
SetMemoRelationsResponse
](
#memos-api-v2-SetMemoRelationsResponse
)
| |
| ListMemoRelations |
[
ListMemoRelationsRequest
](
#memos-api-v2-ListMemoRelationsRequest
)
|
[
ListMemoRelationsResponse
](
#memos-api-v2-ListMemoRelationsResponse
)
| |
| CreateMemoComment |
[
CreateMemoCommentRequest
](
#memos-api-v2-CreateMemoCommentRequest
)
|
[
CreateMemoCommentResponse
](
#memos-api-v2-CreateMemoCommentResponse
)
| |
| ListMemoComments |
[
ListMemoCommentsRequest
](
#memos-api-v2-ListMemoCommentsRequest
)
|
[
ListMemoCommentsResponse
](
#memos-api-v2-ListMemoCommentsResponse
)
| |
...
...
proto/gen/api/v2/memo_relation_service.pb.go
0 → 100644
View file @
9361613f
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc (unknown)
// source: api/v2/memo_relation_service.proto
package
apiv2
import
(
protoreflect
"google.golang.org/protobuf/reflect/protoreflect"
protoimpl
"google.golang.org/protobuf/runtime/protoimpl"
reflect
"reflect"
sync
"sync"
)
const
(
// Verify that this generated code is sufficiently up-to-date.
_
=
protoimpl
.
EnforceVersion
(
20
-
protoimpl
.
MinVersion
)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_
=
protoimpl
.
EnforceVersion
(
protoimpl
.
MaxVersion
-
20
)
)
type
MemoRelation_Type
int32
const
(
MemoRelation_TYPE_UNSPECIFIED
MemoRelation_Type
=
0
MemoRelation_REFERENCE
MemoRelation_Type
=
1
MemoRelation_COMMENT
MemoRelation_Type
=
2
)
// Enum value maps for MemoRelation_Type.
var
(
MemoRelation_Type_name
=
map
[
int32
]
string
{
0
:
"TYPE_UNSPECIFIED"
,
1
:
"REFERENCE"
,
2
:
"COMMENT"
,
}
MemoRelation_Type_value
=
map
[
string
]
int32
{
"TYPE_UNSPECIFIED"
:
0
,
"REFERENCE"
:
1
,
"COMMENT"
:
2
,
}
)
func
(
x
MemoRelation_Type
)
Enum
()
*
MemoRelation_Type
{
p
:=
new
(
MemoRelation_Type
)
*
p
=
x
return
p
}
func
(
x
MemoRelation_Type
)
String
()
string
{
return
protoimpl
.
X
.
EnumStringOf
(
x
.
Descriptor
(),
protoreflect
.
EnumNumber
(
x
))
}
func
(
MemoRelation_Type
)
Descriptor
()
protoreflect
.
EnumDescriptor
{
return
file_api_v2_memo_relation_service_proto_enumTypes
[
0
]
.
Descriptor
()
}
func
(
MemoRelation_Type
)
Type
()
protoreflect
.
EnumType
{
return
&
file_api_v2_memo_relation_service_proto_enumTypes
[
0
]
}
func
(
x
MemoRelation_Type
)
Number
()
protoreflect
.
EnumNumber
{
return
protoreflect
.
EnumNumber
(
x
)
}
// Deprecated: Use MemoRelation_Type.Descriptor instead.
func
(
MemoRelation_Type
)
EnumDescriptor
()
([]
byte
,
[]
int
)
{
return
file_api_v2_memo_relation_service_proto_rawDescGZIP
(),
[]
int
{
0
,
0
}
}
type
MemoRelation
struct
{
state
protoimpl
.
MessageState
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"`
}
func
(
x
*
MemoRelation
)
Reset
()
{
*
x
=
MemoRelation
{}
if
protoimpl
.
UnsafeEnabled
{
mi
:=
&
file_api_v2_memo_relation_service_proto_msgTypes
[
0
]
ms
:=
protoimpl
.
X
.
MessageStateOf
(
protoimpl
.
Pointer
(
x
))
ms
.
StoreMessageInfo
(
mi
)
}
}
func
(
x
*
MemoRelation
)
String
()
string
{
return
protoimpl
.
X
.
MessageStringOf
(
x
)
}
func
(
*
MemoRelation
)
ProtoMessage
()
{}
func
(
x
*
MemoRelation
)
ProtoReflect
()
protoreflect
.
Message
{
mi
:=
&
file_api_v2_memo_relation_service_proto_msgTypes
[
0
]
if
protoimpl
.
UnsafeEnabled
&&
x
!=
nil
{
ms
:=
protoimpl
.
X
.
MessageStateOf
(
protoimpl
.
Pointer
(
x
))
if
ms
.
LoadMessageInfo
()
==
nil
{
ms
.
StoreMessageInfo
(
mi
)
}
return
ms
}
return
mi
.
MessageOf
(
x
)
}
// Deprecated: Use MemoRelation.ProtoReflect.Descriptor instead.
func
(
*
MemoRelation
)
Descriptor
()
([]
byte
,
[]
int
)
{
return
file_api_v2_memo_relation_service_proto_rawDescGZIP
(),
[]
int
{
0
}
}
func
(
x
*
MemoRelation
)
GetMemoId
()
int32
{
if
x
!=
nil
{
return
x
.
MemoId
}
return
0
}
func
(
x
*
MemoRelation
)
GetRelatedMemoId
()
int32
{
if
x
!=
nil
{
return
x
.
RelatedMemoId
}
return
0
}
func
(
x
*
MemoRelation
)
GetType
()
MemoRelation_Type
{
if
x
!=
nil
{
return
x
.
Type
}
return
MemoRelation_TYPE_UNSPECIFIED
}
var
File_api_v2_memo_relation_service_proto
protoreflect
.
FileDescriptor
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
,
}
var
(
file_api_v2_memo_relation_service_proto_rawDescOnce
sync
.
Once
file_api_v2_memo_relation_service_proto_rawDescData
=
file_api_v2_memo_relation_service_proto_rawDesc
)
func
file_api_v2_memo_relation_service_proto_rawDescGZIP
()
[]
byte
{
file_api_v2_memo_relation_service_proto_rawDescOnce
.
Do
(
func
()
{
file_api_v2_memo_relation_service_proto_rawDescData
=
protoimpl
.
X
.
CompressGZIP
(
file_api_v2_memo_relation_service_proto_rawDescData
)
})
return
file_api_v2_memo_relation_service_proto_rawDescData
}
var
file_api_v2_memo_relation_service_proto_enumTypes
=
make
([]
protoimpl
.
EnumInfo
,
1
)
var
file_api_v2_memo_relation_service_proto_msgTypes
=
make
([]
protoimpl
.
MessageInfo
,
1
)
var
file_api_v2_memo_relation_service_proto_goTypes
=
[]
interface
{}{
(
MemoRelation_Type
)(
0
),
// 0: memos.api.v2.MemoRelation.Type
(
*
MemoRelation
)(
nil
),
// 1: memos.api.v2.MemoRelation
}
var
file_api_v2_memo_relation_service_proto_depIdxs
=
[]
int32
{
0
,
// 0: memos.api.v2.MemoRelation.type:type_name -> memos.api.v2.MemoRelation.Type
1
,
// [1:1] is the sub-list for method output_type
1
,
// [1:1] is the sub-list for method input_type
1
,
// [1:1] is the sub-list for extension type_name
1
,
// [1:1] is the sub-list for extension extendee
0
,
// [0:1] is the sub-list for field type_name
}
func
init
()
{
file_api_v2_memo_relation_service_proto_init
()
}
func
file_api_v2_memo_relation_service_proto_init
()
{
if
File_api_v2_memo_relation_service_proto
!=
nil
{
return
}
if
!
protoimpl
.
UnsafeEnabled
{
file_api_v2_memo_relation_service_proto_msgTypes
[
0
]
.
Exporter
=
func
(
v
interface
{},
i
int
)
interface
{}
{
switch
v
:=
v
.
(
*
MemoRelation
);
i
{
case
0
:
return
&
v
.
state
case
1
:
return
&
v
.
sizeCache
case
2
:
return
&
v
.
unknownFields
default
:
return
nil
}
}
}
type
x
struct
{}
out
:=
protoimpl
.
TypeBuilder
{
File
:
protoimpl
.
DescBuilder
{
GoPackagePath
:
reflect
.
TypeOf
(
x
{})
.
PkgPath
(),
RawDescriptor
:
file_api_v2_memo_relation_service_proto_rawDesc
,
NumEnums
:
1
,
NumMessages
:
1
,
NumExtensions
:
0
,
NumServices
:
0
,
},
GoTypes
:
file_api_v2_memo_relation_service_proto_goTypes
,
DependencyIndexes
:
file_api_v2_memo_relation_service_proto_depIdxs
,
EnumInfos
:
file_api_v2_memo_relation_service_proto_enumTypes
,
MessageInfos
:
file_api_v2_memo_relation_service_proto_msgTypes
,
}
.
Build
()
File_api_v2_memo_relation_service_proto
=
out
.
File
file_api_v2_memo_relation_service_proto_rawDesc
=
nil
file_api_v2_memo_relation_service_proto_goTypes
=
nil
file_api_v2_memo_relation_service_proto_depIdxs
=
nil
}
proto/gen/api/v2/memo_service.pb.go
View file @
9361613f
This diff is collapsed.
Click to expand it.
proto/gen/api/v2/memo_service.pb.gw.go
View file @
9361613f
This diff is collapsed.
Click to expand it.
proto/gen/api/v2/memo_service_grpc.pb.go
View file @
9361613f
...
...
@@ -24,7 +24,10 @@ const (
MemoService_GetMemo_FullMethodName
=
"/memos.api.v2.MemoService/GetMemo"
MemoService_UpdateMemo_FullMethodName
=
"/memos.api.v2.MemoService/UpdateMemo"
MemoService_DeleteMemo_FullMethodName
=
"/memos.api.v2.MemoService/DeleteMemo"
MemoService_SetMemoResources_FullMethodName
=
"/memos.api.v2.MemoService/SetMemoResources"
MemoService_ListMemoResources_FullMethodName
=
"/memos.api.v2.MemoService/ListMemoResources"
MemoService_SetMemoRelations_FullMethodName
=
"/memos.api.v2.MemoService/SetMemoRelations"
MemoService_ListMemoRelations_FullMethodName
=
"/memos.api.v2.MemoService/ListMemoRelations"
MemoService_CreateMemoComment_FullMethodName
=
"/memos.api.v2.MemoService/CreateMemoComment"
MemoService_ListMemoComments_FullMethodName
=
"/memos.api.v2.MemoService/ListMemoComments"
)
...
...
@@ -38,7 +41,10 @@ type MemoServiceClient interface {
GetMemo
(
ctx
context
.
Context
,
in
*
GetMemoRequest
,
opts
...
grpc
.
CallOption
)
(
*
GetMemoResponse
,
error
)
UpdateMemo
(
ctx
context
.
Context
,
in
*
UpdateMemoRequest
,
opts
...
grpc
.
CallOption
)
(
*
UpdateMemoResponse
,
error
)
DeleteMemo
(
ctx
context
.
Context
,
in
*
DeleteMemoRequest
,
opts
...
grpc
.
CallOption
)
(
*
DeleteMemoResponse
,
error
)
SetMemoResources
(
ctx
context
.
Context
,
in
*
SetMemoResourcesRequest
,
opts
...
grpc
.
CallOption
)
(
*
SetMemoResourcesResponse
,
error
)
ListMemoResources
(
ctx
context
.
Context
,
in
*
ListMemoResourcesRequest
,
opts
...
grpc
.
CallOption
)
(
*
ListMemoResourcesResponse
,
error
)
SetMemoRelations
(
ctx
context
.
Context
,
in
*
SetMemoRelationsRequest
,
opts
...
grpc
.
CallOption
)
(
*
SetMemoRelationsResponse
,
error
)
ListMemoRelations
(
ctx
context
.
Context
,
in
*
ListMemoRelationsRequest
,
opts
...
grpc
.
CallOption
)
(
*
ListMemoRelationsResponse
,
error
)
CreateMemoComment
(
ctx
context
.
Context
,
in
*
CreateMemoCommentRequest
,
opts
...
grpc
.
CallOption
)
(
*
CreateMemoCommentResponse
,
error
)
ListMemoComments
(
ctx
context
.
Context
,
in
*
ListMemoCommentsRequest
,
opts
...
grpc
.
CallOption
)
(
*
ListMemoCommentsResponse
,
error
)
}
...
...
@@ -96,6 +102,15 @@ func (c *memoServiceClient) DeleteMemo(ctx context.Context, in *DeleteMemoReques
return
out
,
nil
}
func
(
c
*
memoServiceClient
)
SetMemoResources
(
ctx
context
.
Context
,
in
*
SetMemoResourcesRequest
,
opts
...
grpc
.
CallOption
)
(
*
SetMemoResourcesResponse
,
error
)
{
out
:=
new
(
SetMemoResourcesResponse
)
err
:=
c
.
cc
.
Invoke
(
ctx
,
MemoService_SetMemoResources_FullMethodName
,
in
,
out
,
opts
...
)
if
err
!=
nil
{
return
nil
,
err
}
return
out
,
nil
}
func
(
c
*
memoServiceClient
)
ListMemoResources
(
ctx
context
.
Context
,
in
*
ListMemoResourcesRequest
,
opts
...
grpc
.
CallOption
)
(
*
ListMemoResourcesResponse
,
error
)
{
out
:=
new
(
ListMemoResourcesResponse
)
err
:=
c
.
cc
.
Invoke
(
ctx
,
MemoService_ListMemoResources_FullMethodName
,
in
,
out
,
opts
...
)
...
...
@@ -105,6 +120,24 @@ func (c *memoServiceClient) ListMemoResources(ctx context.Context, in *ListMemoR
return
out
,
nil
}
func
(
c
*
memoServiceClient
)
SetMemoRelations
(
ctx
context
.
Context
,
in
*
SetMemoRelationsRequest
,
opts
...
grpc
.
CallOption
)
(
*
SetMemoRelationsResponse
,
error
)
{
out
:=
new
(
SetMemoRelationsResponse
)
err
:=
c
.
cc
.
Invoke
(
ctx
,
MemoService_SetMemoRelations_FullMethodName
,
in
,
out
,
opts
...
)
if
err
!=
nil
{
return
nil
,
err
}
return
out
,
nil
}
func
(
c
*
memoServiceClient
)
ListMemoRelations
(
ctx
context
.
Context
,
in
*
ListMemoRelationsRequest
,
opts
...
grpc
.
CallOption
)
(
*
ListMemoRelationsResponse
,
error
)
{
out
:=
new
(
ListMemoRelationsResponse
)
err
:=
c
.
cc
.
Invoke
(
ctx
,
MemoService_ListMemoRelations_FullMethodName
,
in
,
out
,
opts
...
)
if
err
!=
nil
{
return
nil
,
err
}
return
out
,
nil
}
func
(
c
*
memoServiceClient
)
CreateMemoComment
(
ctx
context
.
Context
,
in
*
CreateMemoCommentRequest
,
opts
...
grpc
.
CallOption
)
(
*
CreateMemoCommentResponse
,
error
)
{
out
:=
new
(
CreateMemoCommentResponse
)
err
:=
c
.
cc
.
Invoke
(
ctx
,
MemoService_CreateMemoComment_FullMethodName
,
in
,
out
,
opts
...
)
...
...
@@ -132,7 +165,10 @@ type MemoServiceServer interface {
GetMemo
(
context
.
Context
,
*
GetMemoRequest
)
(
*
GetMemoResponse
,
error
)
UpdateMemo
(
context
.
Context
,
*
UpdateMemoRequest
)
(
*
UpdateMemoResponse
,
error
)
DeleteMemo
(
context
.
Context
,
*
DeleteMemoRequest
)
(
*
DeleteMemoResponse
,
error
)
SetMemoResources
(
context
.
Context
,
*
SetMemoResourcesRequest
)
(
*
SetMemoResourcesResponse
,
error
)
ListMemoResources
(
context
.
Context
,
*
ListMemoResourcesRequest
)
(
*
ListMemoResourcesResponse
,
error
)
SetMemoRelations
(
context
.
Context
,
*
SetMemoRelationsRequest
)
(
*
SetMemoRelationsResponse
,
error
)
ListMemoRelations
(
context
.
Context
,
*
ListMemoRelationsRequest
)
(
*
ListMemoRelationsResponse
,
error
)
CreateMemoComment
(
context
.
Context
,
*
CreateMemoCommentRequest
)
(
*
CreateMemoCommentResponse
,
error
)
ListMemoComments
(
context
.
Context
,
*
ListMemoCommentsRequest
)
(
*
ListMemoCommentsResponse
,
error
)
mustEmbedUnimplementedMemoServiceServer
()
...
...
@@ -157,9 +193,18 @@ func (UnimplementedMemoServiceServer) UpdateMemo(context.Context, *UpdateMemoReq
func
(
UnimplementedMemoServiceServer
)
DeleteMemo
(
context
.
Context
,
*
DeleteMemoRequest
)
(
*
DeleteMemoResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method DeleteMemo not implemented"
)
}
func
(
UnimplementedMemoServiceServer
)
SetMemoResources
(
context
.
Context
,
*
SetMemoResourcesRequest
)
(
*
SetMemoResourcesResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method SetMemoResources not implemented"
)
}
func
(
UnimplementedMemoServiceServer
)
ListMemoResources
(
context
.
Context
,
*
ListMemoResourcesRequest
)
(
*
ListMemoResourcesResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method ListMemoResources not implemented"
)
}
func
(
UnimplementedMemoServiceServer
)
SetMemoRelations
(
context
.
Context
,
*
SetMemoRelationsRequest
)
(
*
SetMemoRelationsResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method SetMemoRelations not implemented"
)
}
func
(
UnimplementedMemoServiceServer
)
ListMemoRelations
(
context
.
Context
,
*
ListMemoRelationsRequest
)
(
*
ListMemoRelationsResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method ListMemoRelations not implemented"
)
}
func
(
UnimplementedMemoServiceServer
)
CreateMemoComment
(
context
.
Context
,
*
CreateMemoCommentRequest
)
(
*
CreateMemoCommentResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method CreateMemoComment not implemented"
)
}
...
...
@@ -269,6 +314,24 @@ func _MemoService_DeleteMemo_Handler(srv interface{}, ctx context.Context, dec f
return
interceptor
(
ctx
,
in
,
info
,
handler
)
}
func
_MemoService_SetMemoResources_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
in
:=
new
(
SetMemoResourcesRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
return
nil
,
err
}
if
interceptor
==
nil
{
return
srv
.
(
MemoServiceServer
)
.
SetMemoResources
(
ctx
,
in
)
}
info
:=
&
grpc
.
UnaryServerInfo
{
Server
:
srv
,
FullMethod
:
MemoService_SetMemoResources_FullMethodName
,
}
handler
:=
func
(
ctx
context
.
Context
,
req
interface
{})
(
interface
{},
error
)
{
return
srv
.
(
MemoServiceServer
)
.
SetMemoResources
(
ctx
,
req
.
(
*
SetMemoResourcesRequest
))
}
return
interceptor
(
ctx
,
in
,
info
,
handler
)
}
func
_MemoService_ListMemoResources_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
in
:=
new
(
ListMemoResourcesRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
...
...
@@ -287,6 +350,42 @@ func _MemoService_ListMemoResources_Handler(srv interface{}, ctx context.Context
return
interceptor
(
ctx
,
in
,
info
,
handler
)
}
func
_MemoService_SetMemoRelations_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
in
:=
new
(
SetMemoRelationsRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
return
nil
,
err
}
if
interceptor
==
nil
{
return
srv
.
(
MemoServiceServer
)
.
SetMemoRelations
(
ctx
,
in
)
}
info
:=
&
grpc
.
UnaryServerInfo
{
Server
:
srv
,
FullMethod
:
MemoService_SetMemoRelations_FullMethodName
,
}
handler
:=
func
(
ctx
context
.
Context
,
req
interface
{})
(
interface
{},
error
)
{
return
srv
.
(
MemoServiceServer
)
.
SetMemoRelations
(
ctx
,
req
.
(
*
SetMemoRelationsRequest
))
}
return
interceptor
(
ctx
,
in
,
info
,
handler
)
}
func
_MemoService_ListMemoRelations_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
in
:=
new
(
ListMemoRelationsRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
return
nil
,
err
}
if
interceptor
==
nil
{
return
srv
.
(
MemoServiceServer
)
.
ListMemoRelations
(
ctx
,
in
)
}
info
:=
&
grpc
.
UnaryServerInfo
{
Server
:
srv
,
FullMethod
:
MemoService_ListMemoRelations_FullMethodName
,
}
handler
:=
func
(
ctx
context
.
Context
,
req
interface
{})
(
interface
{},
error
)
{
return
srv
.
(
MemoServiceServer
)
.
ListMemoRelations
(
ctx
,
req
.
(
*
ListMemoRelationsRequest
))
}
return
interceptor
(
ctx
,
in
,
info
,
handler
)
}
func
_MemoService_CreateMemoComment_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
in
:=
new
(
CreateMemoCommentRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
...
...
@@ -350,10 +449,22 @@ var MemoService_ServiceDesc = grpc.ServiceDesc{
MethodName
:
"DeleteMemo"
,
Handler
:
_MemoService_DeleteMemo_Handler
,
},
{
MethodName
:
"SetMemoResources"
,
Handler
:
_MemoService_SetMemoResources_Handler
,
},
{
MethodName
:
"ListMemoResources"
,
Handler
:
_MemoService_ListMemoResources_Handler
,
},
{
MethodName
:
"SetMemoRelations"
,
Handler
:
_MemoService_SetMemoRelations_Handler
,
},
{
MethodName
:
"ListMemoRelations"
,
Handler
:
_MemoService_ListMemoRelations_Handler
,
},
{
MethodName
:
"CreateMemoComment"
,
Handler
:
_MemoService_CreateMemoComment_Handler
,
...
...
web/src/components/MemoEditorV1/ActionButton/TagSelector.tsx
0 → 100644
View file @
9361613f
import
{
IconButton
}
from
"@mui/joy"
;
import
{
useEffect
}
from
"react"
;
import
Icon
from
"@/components/Icon"
;
import
OverflowTip
from
"@/components/kit/OverflowTip"
;
import
{
useTagStore
}
from
"@/store/module"
;
interface
Props
{
onTagSelectorClick
:
(
tag
:
string
)
=>
void
;
}
const
TagSelector
=
(
props
:
Props
)
=>
{
const
{
onTagSelectorClick
}
=
props
;
const
tagStore
=
useTagStore
();
const
tags
=
tagStore
.
state
.
tags
;
useEffect
(()
=>
{
(
async
()
=>
{
try
{
await
tagStore
.
fetchTags
();
}
catch
(
error
)
{
// do nothing.
}
})();
},
[]);
return
(
<
IconButton
className=
"relative group flex flex-row justify-center items-center p-1 w-auto h-auto mr-1 select-none rounded cursor-pointer text-gray-600 dark:text-gray-400 hover:bg-gray-300 dark:hover:bg-zinc-800 hover:shadow"
>
<
Icon
.
Hash
className=
"w-5 h-5 mx-auto"
/>
<
div
className=
"hidden flex-row justify-start items-start flex-wrap absolute top-8 left-0 mt-1 p-1 z-1 rounded w-52 h-auto max-h-48 overflow-y-auto font-mono shadow bg-zinc-200 dark:bg-zinc-600 group-hover:flex"
>
{
tags
.
length
>
0
?
(
tags
.
map
((
tag
)
=>
{
return
(
<
div
className=
"w-auto max-w-full text-black dark:text-gray-300 cursor-pointer rounded text-sm leading-6 px-2 hover:bg-zinc-300 dark:hover:bg-zinc-700 shrink-0"
onClick=
{
()
=>
onTagSelectorClick
(
tag
)
}
key=
{
tag
}
>
<
OverflowTip
>
#
{
tag
}
</
OverflowTip
>
</
div
>
);
})
)
:
(
<
p
className=
"italic text-sm ml-2"
onClick=
{
(
e
)
=>
e
.
stopPropagation
()
}
>
No tags found
</
p
>
)
}
</
div
>
</
IconButton
>
);
};
export
default
TagSelector
;
web/src/components/MemoEditorV1/Editor/TagSuggestions.tsx
0 → 100644
View file @
9361613f
import
classNames
from
"classnames"
;
import
{
useEffect
,
useRef
,
useState
}
from
"react"
;
import
getCaretCoordinates
from
"textarea-caret"
;
import
OverflowTip
from
"@/components/kit/OverflowTip"
;
import
{
useTagStore
}
from
"@/store/module"
;
import
{
EditorRefActions
}
from
"."
;
type
Props
=
{
editorRef
:
React
.
RefObject
<
HTMLTextAreaElement
>
;
editorActions
:
React
.
ForwardedRef
<
EditorRefActions
>
;
};
type
Position
=
{
left
:
number
;
top
:
number
;
height
:
number
};
const
TagSuggestions
=
({
editorRef
,
editorActions
}:
Props
)
=>
{
const
[
position
,
setPosition
]
=
useState
<
Position
|
null
>
(
null
);
const
hide
=
()
=>
setPosition
(
null
);
const
{
state
}
=
useTagStore
();
const
tagsRef
=
useRef
(
state
.
tags
);
tagsRef
.
current
=
state
.
tags
;
const
[
selected
,
select
]
=
useState
(
0
);
const
selectedRef
=
useRef
(
selected
);
selectedRef
.
current
=
selected
;
const
getCurrentWord
=
():
[
word
:
string
,
startIndex
:
number
]
=>
{
const
editor
=
editorRef
.
current
;
if
(
!
editor
)
return
[
""
,
0
];
const
cursorPos
=
editor
.
selectionEnd
;
const
before
=
editor
.
value
.
slice
(
0
,
cursorPos
).
match
(
/
\S
*$/
)
||
{
0
:
""
,
index
:
cursorPos
};
const
after
=
editor
.
value
.
slice
(
cursorPos
).
match
(
/^
\S
*/
)
||
{
0
:
""
};
return
[
before
[
0
]
+
after
[
0
],
before
.
index
??
cursorPos
];
};
const
suggestionsRef
=
useRef
<
string
[]
>
([]);
suggestionsRef
.
current
=
(()
=>
{
const
input
=
getCurrentWord
()[
0
].
slice
(
1
).
toLowerCase
();
const
customMatches
=
(
tag
:
string
,
input
:
string
)
=>
{
const
tagLowerCase
=
tag
.
toLowerCase
();
const
inputLowerCase
=
input
.
toLowerCase
();
let
inputIndex
=
0
;
for
(
let
i
=
0
;
i
<
tagLowerCase
.
length
;
i
++
)
{
if
(
tagLowerCase
[
i
]
===
inputLowerCase
[
inputIndex
])
{
inputIndex
++
;
if
(
inputIndex
===
inputLowerCase
.
length
)
{
return
true
;
}
}
}
return
false
;
};
const
matchedTags
=
tagsRef
.
current
.
filter
((
tag
)
=>
customMatches
(
tag
,
input
));
return
matchedTags
.
slice
(
0
,
5
);
})();
const
isVisibleRef
=
useRef
(
false
);
isVisibleRef
.
current
=
!!
(
position
&&
suggestionsRef
.
current
.
length
>
0
);
const
autocomplete
=
(
tag
:
string
)
=>
{
if
(
!
editorActions
||
!
(
"current"
in
editorActions
)
||
!
editorActions
.
current
)
return
;
const
[
word
,
index
]
=
getCurrentWord
();
editorActions
.
current
.
removeText
(
index
,
word
.
length
);
editorActions
.
current
.
insertText
(
`#
${
tag
}
`
);
hide
();
};
const
handleKeyDown
=
(
e
:
KeyboardEvent
)
=>
{
if
(
!
isVisibleRef
.
current
)
return
;
const
suggestions
=
suggestionsRef
.
current
;
const
selected
=
selectedRef
.
current
;
if
([
"Escape"
,
"ArrowLeft"
,
"ArrowRight"
].
includes
(
e
.
code
))
hide
();
if
(
"ArrowDown"
===
e
.
code
)
{
select
((
selected
+
1
)
%
suggestions
.
length
);
e
.
preventDefault
();
e
.
stopPropagation
();
}
if
(
"ArrowUp"
===
e
.
code
)
{
select
((
selected
-
1
+
suggestions
.
length
)
%
suggestions
.
length
);
e
.
preventDefault
();
e
.
stopPropagation
();
}
if
([
"Enter"
,
"Tab"
].
includes
(
e
.
code
))
{
autocomplete
(
suggestions
[
selected
]);
e
.
preventDefault
();
e
.
stopPropagation
();
}
};
const
handleInput
=
()
=>
{
if
(
!
editorRef
.
current
)
return
;
select
(
0
);
const
[
word
,
index
]
=
getCurrentWord
();
const
isActive
=
word
.
startsWith
(
"#"
)
&&
!
word
.
slice
(
1
).
includes
(
"#"
);
isActive
?
setPosition
(
getCaretCoordinates
(
editorRef
.
current
,
index
))
:
hide
();
};
const
listenersAreRegisteredRef
=
useRef
(
false
);
const
registerListeners
=
()
=>
{
const
editor
=
editorRef
.
current
;
if
(
!
editor
||
listenersAreRegisteredRef
.
current
)
return
;
editor
.
addEventListener
(
"click"
,
hide
);
editor
.
addEventListener
(
"blur"
,
hide
);
editor
.
addEventListener
(
"keydown"
,
handleKeyDown
);
editor
.
addEventListener
(
"input"
,
handleInput
);
listenersAreRegisteredRef
.
current
=
true
;
};
useEffect
(
registerListeners
,
[
!!
editorRef
.
current
]);
if
(
!
isVisibleRef
.
current
||
!
position
)
return
null
;
return
(
<
div
className=
"z-20 p-1 mt-1 -ml-2 absolute max-w-[12rem] gap-px rounded font-mono flex flex-col justify-start items-start overflow-auto shadow bg-zinc-200 dark:bg-zinc-600"
style=
{
{
left
:
position
.
left
,
top
:
position
.
top
+
position
.
height
}
}
>
{
suggestionsRef
.
current
.
map
((
tag
,
i
)
=>
(
<
div
key=
{
tag
}
onMouseDown=
{
()
=>
autocomplete
(
tag
)
}
className=
{
classNames
(
"rounded p-1 px-2 w-full truncate text-sm dark:text-gray-300 cursor-pointer hover:bg-zinc-300 dark:hover:bg-zinc-700"
,
i
===
selected
?
"bg-zinc-300 dark:bg-zinc-700"
:
""
)
}
>
<
OverflowTip
>
#
{
tag
}
</
OverflowTip
>
</
div
>
))
}
</
div
>
);
};
export
default
TagSuggestions
;
web/src/components/MemoEditorV1/Editor/index.tsx
0 → 100644
View file @
9361613f
import
classNames
from
"classnames"
;
import
{
forwardRef
,
ReactNode
,
useCallback
,
useEffect
,
useImperativeHandle
,
useRef
}
from
"react"
;
import
TagSuggestions
from
"./TagSuggestions"
;
export
interface
EditorRefActions
{
focus
:
FunctionType
;
scrollToCursor
:
FunctionType
;
insertText
:
(
text
:
string
,
prefix
?:
string
,
suffix
?:
string
)
=>
void
;
removeText
:
(
start
:
number
,
length
:
number
)
=>
void
;
setContent
:
(
text
:
string
)
=>
void
;
getContent
:
()
=>
string
;
getSelectedContent
:
()
=>
string
;
getCursorPosition
:
()
=>
number
;
setCursorPosition
:
(
startPos
:
number
,
endPos
?:
number
)
=>
void
;
getCursorLineNumber
:
()
=>
number
;
getLine
:
(
lineNumber
:
number
)
=>
string
;
setLine
:
(
lineNumber
:
number
,
text
:
string
)
=>
void
;
}
interface
Props
{
className
:
string
;
initialContent
:
string
;
placeholder
:
string
;
tools
?:
ReactNode
;
onContentChange
:
(
content
:
string
)
=>
void
;
onPaste
:
(
event
:
React
.
ClipboardEvent
)
=>
void
;
}
const
Editor
=
forwardRef
(
function
Editor
(
props
:
Props
,
ref
:
React
.
ForwardedRef
<
EditorRefActions
>
)
{
const
{
className
,
initialContent
,
placeholder
,
onPaste
,
onContentChange
:
handleContentChangeCallback
}
=
props
;
const
editorRef
=
useRef
<
HTMLTextAreaElement
>
(
null
);
useEffect
(()
=>
{
if
(
editorRef
.
current
&&
initialContent
)
{
editorRef
.
current
.
value
=
initialContent
;
handleContentChangeCallback
(
initialContent
);
}
},
[]);
useEffect
(()
=>
{
if
(
editorRef
.
current
)
{
updateEditorHeight
();
}
},
[
editorRef
.
current
?.
value
]);
const
updateEditorHeight
=
()
=>
{
if
(
editorRef
.
current
)
{
editorRef
.
current
.
style
.
height
=
"auto"
;
editorRef
.
current
.
style
.
height
=
(
editorRef
.
current
.
scrollHeight
??
0
)
+
"px"
;
}
};
useImperativeHandle
(
ref
,
()
=>
({
focus
:
()
=>
{
editorRef
.
current
?.
focus
();
},
scrollToCursor
:
()
=>
{
if
(
editorRef
.
current
)
{
editorRef
.
current
.
scrollTop
=
editorRef
.
current
.
scrollHeight
;
}
},
insertText
:
(
content
=
""
,
prefix
=
""
,
suffix
=
""
)
=>
{
if
(
!
editorRef
.
current
)
{
return
;
}
const
cursorPosition
=
editorRef
.
current
.
selectionStart
;
const
endPosition
=
editorRef
.
current
.
selectionEnd
;
const
prevValue
=
editorRef
.
current
.
value
;
const
value
=
prevValue
.
slice
(
0
,
cursorPosition
)
+
prefix
+
(
content
||
prevValue
.
slice
(
cursorPosition
,
endPosition
))
+
suffix
+
prevValue
.
slice
(
endPosition
);
editorRef
.
current
.
value
=
value
;
editorRef
.
current
.
focus
();
editorRef
.
current
.
selectionEnd
=
endPosition
+
prefix
.
length
+
content
.
length
;
handleContentChangeCallback
(
editorRef
.
current
.
value
);
updateEditorHeight
();
},
removeText
:
(
start
:
number
,
length
:
number
)
=>
{
if
(
!
editorRef
.
current
)
{
return
;
}
const
prevValue
=
editorRef
.
current
.
value
;
const
value
=
prevValue
.
slice
(
0
,
start
)
+
prevValue
.
slice
(
start
+
length
);
editorRef
.
current
.
value
=
value
;
editorRef
.
current
.
focus
();
editorRef
.
current
.
selectionEnd
=
start
;
handleContentChangeCallback
(
editorRef
.
current
.
value
);
updateEditorHeight
();
},
setContent
:
(
text
:
string
)
=>
{
if
(
editorRef
.
current
)
{
editorRef
.
current
.
value
=
text
;
handleContentChangeCallback
(
editorRef
.
current
.
value
);
updateEditorHeight
();
}
},
getContent
:
():
string
=>
{
return
editorRef
.
current
?.
value
??
""
;
},
getCursorPosition
:
():
number
=>
{
return
editorRef
.
current
?.
selectionStart
??
0
;
},
getSelectedContent
:
()
=>
{
const
start
=
editorRef
.
current
?.
selectionStart
;
const
end
=
editorRef
.
current
?.
selectionEnd
;
return
editorRef
.
current
?.
value
.
slice
(
start
,
end
)
??
""
;
},
setCursorPosition
:
(
startPos
:
number
,
endPos
?:
number
)
=>
{
const
_endPos
=
isNaN
(
endPos
as
number
)
?
startPos
:
(
endPos
as
number
);
editorRef
.
current
?.
setSelectionRange
(
startPos
,
_endPos
);
},
getCursorLineNumber
:
()
=>
{
const
cursorPosition
=
editorRef
.
current
?.
selectionStart
??
0
;
const
lines
=
editorRef
.
current
?.
value
.
slice
(
0
,
cursorPosition
).
split
(
"
\n
"
)
??
[];
return
lines
.
length
-
1
;
},
getLine
:
(
lineNumber
:
number
)
=>
{
return
editorRef
.
current
?.
value
.
split
(
"
\n
"
)[
lineNumber
]
??
""
;
},
setLine
:
(
lineNumber
:
number
,
text
:
string
)
=>
{
const
lines
=
editorRef
.
current
?.
value
.
split
(
"
\n
"
)
??
[];
lines
[
lineNumber
]
=
text
;
if
(
editorRef
.
current
)
{
editorRef
.
current
.
value
=
lines
.
join
(
"
\n
"
);
editorRef
.
current
.
focus
();
handleContentChangeCallback
(
editorRef
.
current
.
value
);
updateEditorHeight
();
}
},
}),
[]
);
const
handleEditorInput
=
useCallback
(()
=>
{
handleContentChangeCallback
(
editorRef
.
current
?.
value
??
""
);
updateEditorHeight
();
},
[]);
return
(
<
div
className=
{
classNames
(
"flex flex-col justify-start items-start relative w-full h-auto bg-inherit dark:text-gray-200"
,
className
)
}
>
<
textarea
className=
"w-full h-full max-h-[300px] my-1 text-base resize-none overflow-x-hidden overflow-y-auto bg-transparent outline-none whitespace-pre-wrap word-break"
rows=
{
1
}
placeholder=
{
placeholder
}
ref=
{
editorRef
}
onPaste=
{
onPaste
}
onInput=
{
handleEditorInput
}
></
textarea
>
<
TagSuggestions
editorRef=
{
editorRef
}
editorActions=
{
ref
}
/>
</
div
>
);
});
export
default
Editor
;
web/src/components/MemoEditorV1/MemoEditorDialog.tsx
0 → 100644
View file @
9361613f
import
{
useEffect
}
from
"react"
;
import
{
useGlobalStore
,
useTagStore
}
from
"@/store/module"
;
import
MemoEditor
from
"."
;
import
{
generateDialog
}
from
"../Dialog"
;
import
Icon
from
"../Icon"
;
interface
Props
extends
DialogProps
{
memoId
?:
MemoId
;
relationList
?:
MemoRelation
[];
}
const
MemoEditorDialog
:
React
.
FC
<
Props
>
=
({
memoId
,
relationList
,
destroy
}:
Props
)
=>
{
const
globalStore
=
useGlobalStore
();
const
tagStore
=
useTagStore
();
const
{
systemStatus
}
=
globalStore
.
state
;
useEffect
(()
=>
{
tagStore
.
fetchTags
();
},
[]);
const
handleCloseBtnClick
=
()
=>
{
destroy
();
};
return
(
<>
<
div
className=
"dialog-header-container"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
img
className=
"w-5 h-auto rounded-full shadow"
src=
{
systemStatus
.
customizedProfile
.
logoUrl
}
alt=
""
/>
<
p
className=
"ml-1 text-black opacity-80 dark:text-gray-200"
>
{
systemStatus
.
customizedProfile
.
name
}
</
p
>
</
div
>
<
button
className=
"btn close-btn"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
/>
</
button
>
</
div
>
<
div
className=
"flex flex-col justify-start items-start max-w-full w-[36rem]"
>
<
MemoEditor
className=
"border-none !p-0 -mb-2"
cacheKey=
{
`memo-editor-${memoId}`
}
memoId=
{
memoId
}
relationList=
{
relationList
}
onConfirm=
{
handleCloseBtnClick
}
/>
</
div
>
</>
);
};
export
default
function
showMemoEditorDialog
(
props
:
Pick
<
Props
,
"memoId"
|
"relationList"
>
=
{}):
void
{
generateDialog
(
{
className
:
"memo-editor-dialog"
,
dialogName
:
"memo-editor-dialog"
,
containerClassName
:
"dark:!bg-zinc-700"
,
},
MemoEditorDialog
,
props
);
}
web/src/components/MemoEditorV1/RelationListView.tsx
0 → 100644
View file @
9361613f
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useMemoCacheStore
}
from
"@/store/v1"
;
import
{
MemoRelation
,
MemoRelation_Type
}
from
"@/types/proto/api/v2/memo_relation_service"
;
import
Icon
from
"../Icon"
;
interface
Props
{
relationList
:
MemoRelation
[];
setRelationList
:
(
relationList
:
MemoRelation
[])
=>
void
;
}
const
RelationListView
=
(
props
:
Props
)
=>
{
const
{
relationList
,
setRelationList
}
=
props
;
const
memoCacheStore
=
useMemoCacheStore
();
const
[
referencingMemoList
,
setReferencingMemoList
]
=
useState
<
Memo
[]
>
([]);
useEffect
(()
=>
{
(
async
()
=>
{
const
requests
=
relationList
.
filter
((
relation
)
=>
relation
.
type
===
MemoRelation_Type
.
REFERENCE
)
.
map
(
async
(
relation
)
=>
{
return
await
memoCacheStore
.
getOrFetchMemoById
(
relation
.
relatedMemoId
);
});
const
list
=
await
Promise
.
all
(
requests
);
setReferencingMemoList
(
list
);
})();
},
[
relationList
]);
const
handleDeleteRelation
=
async
(
memo
:
Memo
)
=>
{
setRelationList
(
relationList
.
filter
((
relation
)
=>
relation
.
relatedMemoId
!==
memo
.
id
));
};
return
(
<>
{
referencingMemoList
.
length
>
0
&&
(
<
div
className=
"w-full flex flex-row gap-2 mt-2 flex-wrap"
>
{
referencingMemoList
.
map
((
memo
)
=>
{
return
(
<
div
key=
{
memo
.
id
}
className=
"w-auto max-w-xs overflow-hidden flex flex-row justify-start items-center bg-gray-100 dark:bg-zinc-800 hover:opacity-80 rounded-md text-sm p-1 px-2 text-gray-500 cursor-pointer hover:line-through"
onClick=
{
()
=>
handleDeleteRelation
(
memo
)
}
>
<
Icon
.
Link
className=
"w-4 h-auto shrink-0 opacity-80"
/>
<
span
className=
"px-1 shrink-0 opacity-80"
>
#
{
memo
.
id
}
</
span
>
<
span
className=
"max-w-full text-ellipsis whitespace-nowrap overflow-hidden"
>
{
memo
.
content
}
</
span
>
<
Icon
.
X
className=
"w-4 h-auto hover:opacity-80 shrink-0 ml-1"
/>
</
div
>
);
})
}
</
div
>
)
}
</>
);
};
export
default
RelationListView
;
web/src/components/MemoEditorV1/ResourceListView.tsx
0 → 100644
View file @
9361613f
import
{
Resource
}
from
"@/types/proto/api/v2/resource_service"
;
import
Icon
from
"../Icon"
;
import
ResourceIcon
from
"../ResourceIcon"
;
interface
Props
{
resourceList
:
Resource
[];
setResourceList
:
(
resourceList
:
Resource
[])
=>
void
;
}
const
ResourceListView
=
(
props
:
Props
)
=>
{
const
{
resourceList
,
setResourceList
}
=
props
;
const
handleDeleteResource
=
async
(
resourceId
:
ResourceId
)
=>
{
setResourceList
(
resourceList
.
filter
((
resource
)
=>
resource
.
id
!==
resourceId
));
};
return
(
<>
{
resourceList
.
length
>
0
&&
(
<
div
className=
"w-full flex flex-row justify-start flex-wrap gap-2 mt-2"
>
{
resourceList
.
map
((
resource
)
=>
{
return
(
<
div
key=
{
resource
.
id
}
className=
"max-w-full flex flex-row justify-start items-center flex-nowrap gap-x-1 bg-gray-100 dark:bg-zinc-800 px-2 py-1 rounded text-gray-500"
>
<
ResourceIcon
resource=
{
resource
}
className=
"!w-4 !h-4 !opacity-100"
/>
<
span
className=
"text-sm max-w-[8rem] truncate"
>
{
resource
.
filename
}
</
span
>
<
Icon
.
X
className=
"w-4 h-auto cursor-pointer opacity-60 hover:opacity-100"
onClick=
{
()
=>
handleDeleteResource
(
resource
.
id
)
}
/>
</
div
>
);
})
}
</
div
>
)
}
</>
);
};
export
default
ResourceListView
;
web/src/components/MemoEditorV1/index.tsx
0 → 100644
View file @
9361613f
This diff is collapsed.
Click to expand it.
web/src/components/MemoRelationListViewV1.tsx
0 → 100644
View file @
9361613f
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
useMemoV1Store
}
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"
;
interface
Props
{
memo
:
Memo
;
relationList
:
MemoRelation
[];
}
const
MemoRelationListViewV1
=
(
props
:
Props
)
=>
{
const
{
memo
,
relationList
}
=
props
;
const
memoStore
=
useMemoV1Store
();
const
[
referencingMemoList
,
setReferencingMemoList
]
=
useState
<
Memo
[]
>
([]);
const
[
referencedMemoList
,
setReferencedMemoList
]
=
useState
<
Memo
[]
>
([]);
useEffect
(()
=>
{
(
async
()
=>
{
const
referencingMemoList
=
await
Promise
.
all
(
relationList
.
filter
((
relation
)
=>
relation
.
memoId
===
memo
.
id
&&
relation
.
relatedMemoId
!==
memo
.
id
)
.
map
((
relation
)
=>
memoStore
.
getOrFetchMemoById
(
relation
.
relatedMemoId
))
);
setReferencingMemoList
(
referencingMemoList
);
const
referencedMemoList
=
await
Promise
.
all
(
relationList
.
filter
((
relation
)
=>
relation
.
memoId
!==
memo
.
id
&&
relation
.
relatedMemoId
===
memo
.
id
)
.
map
((
relation
)
=>
memoStore
.
getOrFetchMemoById
(
relation
.
memoId
))
);
setReferencedMemoList
(
referencedMemoList
);
})();
},
[
memo
,
relationList
]);
return
(
<>
{
referencingMemoList
.
length
>
0
&&
(
<
div
className=
"w-full mt-2 flex flex-row justify-start items-center flex-wrap gap-2"
>
{
referencingMemoList
.
map
((
memo
)
=>
{
return
(
<
div
key=
{
memo
.
id
}
className=
"block w-auto max-w-[50%]"
>
<
Link
className=
"px-2 border rounded-md w-auto text-sm leading-6 flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-300 dark:border-gray-600 hover:shadow hover:opacity-80"
to=
{
`/m/${memo.id}`
}
>
<
Tooltip
title=
"Reference"
placement=
"top"
>
<
Icon
.
Link
className=
"w-4 h-auto shrink-0 opacity-70"
/>
</
Tooltip
>
<
span
className=
"opacity-70 mx-1"
>
#
{
memo
.
id
}
</
span
>
<
span
className=
"truncate"
>
{
memo
.
content
}
</
span
>
</
Link
>
</
div
>
);
})
}
</
div
>
)
}
{
referencedMemoList
.
length
>
0
&&
(
<
div
className=
"w-full mt-2 flex flex-row justify-start items-center flex-wrap gap-2"
>
{
referencedMemoList
.
map
((
memo
)
=>
{
return
(
<
div
key=
{
memo
.
id
}
className=
"block w-auto max-w-[50%]"
>
<
Link
className=
"px-2 border rounded-md w-auto text-sm leading-6 flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-300 dark:border-gray-600 hover:shadow hover:opacity-80"
to=
{
`/m/${memo.id}`
}
>
<
Tooltip
title=
"Backlink"
placement=
"top"
>
<
Icon
.
Milestone
className=
"w-4 h-auto shrink-0 opacity-70"
/>
</
Tooltip
>
<
span
className=
"opacity-70 mx-1"
>
#
{
memo
.
id
}
</
span
>
<
span
className=
"truncate"
>
{
memo
.
content
}
</
span
>
</
Link
>
</
div
>
);
})
}
</
div
>
)
}
</>
);
};
export
default
MemoRelationListViewV1
;
web/src/components/TimelineMemo.tsx
0 → 100644
View file @
9361613f
import
{
useEffect
,
useState
}
from
"react"
;
import
Icon
from
"@/components/Icon"
;
import
MemoContentV1
from
"@/components/MemoContentV1"
;
import
MemoResourceListView
from
"@/components/MemoResourceListView"
;
import
{
getTimeString
}
from
"@/helpers/datetime"
;
import
{
useMemoV1Store
}
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
{
Resource
}
from
"@/types/proto/api/v2/resource_service"
;
import
MemoRelationListViewV1
from
"./MemoRelationListViewV1"
;
interface
Props
{
memo
:
Memo
;
}
const
TimelineMemo
=
(
props
:
Props
)
=>
{
const
{
memo
}
=
props
;
const
memoStore
=
useMemoV1Store
();
const
[
resources
,
setResources
]
=
useState
<
Resource
[]
>
([]);
const
[
relations
,
setRelations
]
=
useState
<
MemoRelation
[]
>
([]);
useEffect
(()
=>
{
memoStore
.
fetchMemoResources
(
memo
.
id
).
then
((
resources
:
Resource
[])
=>
{
setResources
(
resources
);
});
memoStore
.
fetchMemoRelations
(
memo
.
id
).
then
((
relations
:
MemoRelation
[])
=>
{
setRelations
(
relations
.
filter
((
relation
)
=>
relation
.
type
===
MemoRelation_Type
.
REFERENCE
));
});
},
[
memo
.
id
]);
return
(
<
div
className=
"relative w-full flex flex-col justify-start items-start"
>
<
div
className=
"w-full flex flex-row justify-start items-center mt-0.5 mb-1 text-sm font-mono text-gray-500 dark:text-gray-400"
>
<
span
className=
"opacity-80"
>
{
getTimeString
(
memo
.
displayTime
)
}
</
span
>
<
Icon
.
Dot
className=
"w-5 h-auto opacity-60"
/>
<
span
className=
"opacity-60"
>
#
{
memo
.
id
}
</
span
>
</
div
>
<
MemoContentV1
content=
{
memo
.
content
}
nodes=
{
memo
.
nodes
}
/>
<
MemoResourceListView
resourceList=
{
resources
}
/>
<
MemoRelationListViewV1
memo=
{
memo
}
relationList=
{
relations
}
/>
</
div
>
);
};
export
default
TimelineMemo
;
web/src/components/VisibilityIconV1.tsx
0 → 100644
View file @
9361613f
import
classNames
from
"classnames"
;
import
{
Visibility
}
from
"@/types/proto/api/v2/memo_service"
;
import
Icon
from
"./Icon"
;
interface
Props
{
visibility
:
Visibility
;
}
const
VisibilityIcon
=
(
props
:
Props
)
=>
{
const
{
visibility
}
=
props
;
let
VIcon
=
null
;
if
(
visibility
===
Visibility
.
PRIVATE
)
{
VIcon
=
Icon
.
Lock
;
}
else
if
(
visibility
===
Visibility
.
PROTECTED
)
{
VIcon
=
Icon
.
Users
;
}
else
if
(
visibility
===
Visibility
.
PUBLIC
)
{
VIcon
=
Icon
.
Globe2
;
}
if
(
!
VIcon
)
{
return
null
;
}
return
<
VIcon
className=
{
classNames
(
"w-4 h-auto text-gray-400"
)
}
/>;
};
export
default
VisibilityIcon
;
web/src/pages/Timeline.tsx
View file @
9361613f
import
{
Button
}
from
"@mui/joy"
;
import
{
last
}
from
"lodash-es"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
useToggle
from
"react-use/lib/useToggle"
;
import
Empty
from
"@/components/Empty"
;
import
Icon
from
"@/components/Icon"
;
import
MemoContentV1
from
"@/components/MemoContentV1"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoRelationListView
from
"@/components/MemoRelationListView"
;
import
MemoResourceListView
from
"@/components/MemoResourceListView"
;
import
MemoEditorV1
from
"@/components/MemoEditorV1"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
TimelineMemo
from
"@/components/TimelineMemo"
;
import
DatePicker
from
"@/components/kit/DatePicker"
;
import
{
DAILY_TIMESTAMP
,
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
getDateStampByDate
,
getNormalizedDateString
,
getTimeStampByDate
,
getTimeString
}
from
"@/helpers/datetime"
;
import
{
DAILY_TIMESTAMP
}
from
"@/helpers/consts"
;
import
{
getDateStampByDate
,
getNormalizedDateString
,
getTimeStampByDate
}
from
"@/helpers/datetime"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemo
Store
}
from
"@/store/module
"
;
import
{
extractUsernameFromName
}
from
"@/store/v1
"
;
import
{
useMemo
V1Store
}
from
"@/store/v1
"
;
import
{
Memo
}
from
"@/types/proto/api/v2/memo_service
"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
const
Timeline
=
()
=>
{
const
t
=
useTranslate
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemo
V1
Store
();
const
currentUser
=
useCurrentUser
();
const
currentDateStamp
=
getDateStampByDate
(
getNormalizedDateString
())
as
number
;
const
[
selectedDateStamp
,
setSelectedDateStamp
]
=
useState
<
number
>
(
currentDateStamp
as
number
);
const
[
memos
,
setMemos
]
=
useState
<
Memo
[]
>
([]);
const
[
showDatePicker
,
toggleShowDatePicker
]
=
useToggle
(
false
);
const
dailyMemos
=
memoStore
.
state
.
memos
.
filter
((
m
)
=>
{
const
displayTimestamp
=
getTimeStampByDate
(
m
.
displayTs
);
const
selectedDateStampWithOffset
=
selectedDateStamp
;
return
(
m
.
rowStatus
===
"NORMAL"
&&
m
.
creatorUsername
===
extractUsernameFromName
(
currentUser
.
name
)
&&
displayTimestamp
>=
selectedDateStampWithOffset
&&
displayTimestamp
<
selectedDateStampWithOffset
+
DAILY_TIMESTAMP
);
})
.
sort
((
a
,
b
)
=>
getTimeStampByDate
(
a
.
displayTs
)
-
getTimeStampByDate
(
b
.
displayTs
));
const
sortedMemos
=
memos
.
sort
((
a
,
b
)
=>
getTimeStampByDate
(
a
.
createTime
)
-
getTimeStampByDate
(
b
.
createTime
));
useEffect
(()
=>
{
let
offset
=
0
;
const
fetchMoreMemos
=
async
()
=>
{
try
{
const
fetchedMemos
=
await
memoStore
.
fetchMemos
(
""
,
DEFAULT_MEMO_LIMIT
,
offset
);
offset
+=
fetchedMemos
.
length
;
if
(
fetchedMemos
.
length
===
DEFAULT_MEMO_LIMIT
)
{
const
lastMemo
=
last
(
fetchedMemos
);
if
(
lastMemo
&&
lastMemo
.
displayTs
>
selectedDateStamp
)
{
await
fetchMoreMemos
();
}
}
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
}
};
fetchMoreMemos
();
const
filters
=
[
`creator == "
${
currentUser
.
name
}
"`
,
`created_ts_after ==
${
selectedDateStamp
/
1000
}
`
,
`created_ts_before ==
${(
selectedDateStamp
+
DAILY_TIMESTAMP
)
/
1000
}
`
,
];
memoStore
.
fetchMemos
({
filter
:
filters
.
join
(
" && "
),
})
.
then
((
memos
:
Memo
[])
=>
{
setMemos
(
memos
);
});
},
[
selectedDateStamp
]);
const
handleDataPickerChange
=
(
datestamp
:
number
):
void
=>
{
...
...
@@ -63,6 +44,12 @@ const Timeline = () => {
toggleShowDatePicker
(
false
);
};
const
handleMemoCreate
=
async
(
id
:
number
)
=>
{
await
memoStore
.
getOrFetchMemoById
(
id
).
then
((
memo
:
Memo
)
=>
{
setMemos
([
memo
,
...
memos
]);
});
};
return
(
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
<
MobileHeader
/>
...
...
@@ -96,28 +83,21 @@ const Timeline = () => {
/>
</
div
>
<
div
className=
"w-full h-auto flex flex-col justify-start items-start px-2 pb-4 bg-white dark:bg-zinc-700"
>
{
daily
Memos
.
length
===
0
&&
(
{
sorted
Memos
.
length
===
0
&&
(
<
div
className=
"w-full mt-4 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-4 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
}
<
div
className=
"flex flex-col justify-start items-start w-full mt-2"
>
{
daily
Memos
.
map
((
memo
,
index
)
=>
(
{
sorted
Memos
.
map
((
memo
,
index
)
=>
(
<
div
key=
{
`${memo.id}-${memo.
displayTs
}`
}
key=
{
`${memo.id}-${memo.
createTime
}`
}
className=
"relative w-full flex flex-col justify-start items-start pl-8 sm:pl-12 pt-2 pb-4"
>
<
div
className=
"w-full flex flex-row justify-start items-center mt-0.5 mb-1 text-sm font-mono text-gray-500 dark:text-gray-400"
>
<
span
className=
"opacity-80"
>
{
getTimeString
(
memo
.
displayTs
)
}
</
span
>
<
Icon
.
Dot
className=
"w-5 h-auto opacity-60"
/>
<
span
className=
"opacity-60"
>
#
{
memo
.
id
}
</
span
>
</
div
>
<
MemoContentV1
content=
{
memo
.
content
}
/>
<
MemoResourceListView
resourceList=
{
memo
.
resourceList
}
/>
<
MemoRelationListView
memo=
{
memo
}
relationList=
{
memo
.
relationList
.
filter
((
relation
)
=>
relation
.
type
===
"REFERENCE"
)
}
/>
<
TimelineMemo
memo=
{
memo
}
/>
<
div
className=
"absolute left-1 sm:left-2 top-3 h-full"
>
{
index
!==
daily
Memos
.
length
-
1
&&
(
{
index
!==
sorted
Memos
.
length
-
1
&&
(
<
div
className=
"absolute top-2 left-[7px] h-full w-0.5 bg-gray-400 dark:bg-gray-500 block"
></
div
>
)
}
<
div
className=
"border-4 rounded-full border-white relative dark:border-zinc-700"
>
...
...
@@ -126,10 +106,9 @@ const Timeline = () => {
</
div
>
</
div
>
))
}
{
selectedDateStamp
===
currentDateStamp
&&
(
<
div
className=
"w-full pl-0 sm:pl-12 sm:mt-4"
>
<
MemoEditor
cacheKey=
"timeline-editor"
/>
<
MemoEditor
V1
cacheKey=
"timeline-editor"
onConfirm=
{
handleMemoCreate
}
/>
</
div
>
)
}
</
div
>
...
...
web/src/store/v1/memo.ts
View file @
9361613f
import
{
create
}
from
"zustand"
;
import
{
combine
}
from
"zustand/middleware"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
Memo
}
from
"@/types/proto/api/v2/memo_service"
;
import
{
CreateMemoRequest
,
ListMemosRequest
,
Memo
}
from
"@/types/proto/api/v2/memo_service"
;
export
const
useMemoV1Store
=
create
(
combine
({
memoById
:
new
Map
<
number
,
Memo
>
()
},
(
set
,
get
)
=>
({
getState
:
()
=>
get
(),
fetchMemos
:
async
(
request
:
Partial
<
ListMemosRequest
>
)
=>
{
const
{
memos
}
=
await
memoServiceClient
.
listMemos
(
request
);
return
memos
;
},
getOrFetchMemoById
:
async
(
id
:
MemoId
)
=>
{
const
memo
=
get
().
memoById
.
get
(
id
);
if
(
memo
)
{
...
...
@@ -29,6 +33,18 @@ export const useMemoV1Store = create(
getMemoById
:
(
id
:
number
)
=>
{
return
get
().
memoById
.
get
(
id
);
},
createMemo
:
async
(
request
:
CreateMemoRequest
)
=>
{
const
{
memo
}
=
await
memoServiceClient
.
createMemo
(
request
);
if
(
!
memo
)
{
throw
new
Error
(
"Memo not found"
);
}
set
((
state
)
=>
{
state
.
memoById
.
set
(
memo
.
id
,
memo
);
return
state
;
});
return
memo
;
},
updateMemo
:
async
(
update
:
Partial
<
Memo
>
,
updateMask
:
string
[])
=>
{
const
{
memo
}
=
await
memoServiceClient
.
updateMemo
({
id
:
update
.
id
!
,
...
...
@@ -55,5 +71,17 @@ export const useMemoV1Store = create(
return
state
;
});
},
fetchMemoResources
:
async
(
id
:
number
)
=>
{
const
{
resources
}
=
await
memoServiceClient
.
listMemoResources
({
id
,
});
return
resources
;
},
fetchMemoRelations
:
async
(
id
:
number
)
=>
{
const
{
relations
}
=
await
memoServiceClient
.
listMemoRelations
({
id
,
});
return
relations
;
},
}))
);
web/src/utils/memo.ts
0 → 100644
View file @
9361613f
import
{
Visibility
}
from
"@/types/proto/api/v2/memo_service"
;
export
const
convertVisibilityFromString
=
(
visibility
:
string
)
=>
{
switch
(
visibility
)
{
case
"PUBLIC"
:
return
Visibility
.
PUBLIC
;
case
"PROTECTED"
:
return
Visibility
.
PROTECTED
;
case
"PRIVATE"
:
return
Visibility
.
PRIVATE
;
default
:
return
Visibility
.
PUBLIC
;
}
};
export
const
convertVisibilityToString
=
(
visibility
:
Visibility
)
=>
{
switch
(
visibility
)
{
case
Visibility
.
PUBLIC
:
return
"PUBLIC"
;
case
Visibility
.
PROTECTED
:
return
"PROTECTED"
;
case
Visibility
.
PRIVATE
:
return
"PRIVATE"
;
default
:
return
"PRIVATE"
;
}
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment