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
2a861ea4
Commit
2a861ea4
authored
Jan 10, 2025
by
johnnyjoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: tweak resource state in api
parent
1caaef1c
Changes
26
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
785 additions
and
792 deletions
+785
-792
common.proto
proto/api/v1/common.proto
+3
-3
memo_service.proto
proto/api/v1/memo_service.proto
+1
-1
user_service.proto
proto/api/v1/user_service.proto
+1
-1
webhook_service.proto
proto/api/v1/webhook_service.proto
+1
-1
common.pb.go
proto/gen/api/v1/common.pb.go
+37
-37
memo_service.pb.go
proto/gen/api/v1/memo_service.pb.go
+348
-348
user_service.pb.go
proto/gen/api/v1/user_service.pb.go
+219
-220
webhook_service.pb.go
proto/gen/api/v1/webhook_service.pb.go
+98
-98
apidocs.swagger.yaml
proto/gen/apidocs.swagger.yaml
+19
-19
common.go
server/router/api/v1/common.go
+8
-8
memo_service.go
server/router/api/v1/memo_service.go
+2
-2
memo_service_converter.go
server/router/api/v1/memo_service_converter.go
+1
-1
memo_service_filter.go
server/router/api/v1/memo_service_filter.go
+5
-4
user_service.go
server/router/api/v1/user_service.go
+3
-3
webhook_service.go
server/router/api/v1/webhook_service.go
+1
-4
MemoActionMenu.tsx
web/src/components/MemoActionMenu.tsx
+9
-13
AddMemoRelationPopover.tsx
...onents/MemoEditor/ActionButton/AddMemoRelationPopover.tsx
+1
-1
MemoReactionListView.tsx
web/src/components/MemoReactionListView.tsx
+2
-2
MemoView.tsx
web/src/components/MemoView.tsx
+2
-2
ReactionView.tsx
web/src/components/ReactionView.tsx
+2
-2
MemberSection.tsx
web/src/components/Settings/MemberSection.tsx
+9
-9
Archived.tsx
web/src/pages/Archived.tsx
+3
-3
Explore.tsx
web/src/pages/Explore.tsx
+3
-3
Home.tsx
web/src/pages/Home.tsx
+3
-3
UserProfile.tsx
web/src/pages/UserProfile.tsx
+3
-3
memoMetadata.ts
web/src/store/v1/memoMetadata.ts
+1
-1
No files found.
proto/api/v1/common.proto
View file @
2a861ea4
...
...
@@ -4,9 +4,9 @@ package memos.api.v1;
option
go_package
=
"gen/api/v1"
;
enum
RowStatus
{
ROW_STATUS
_UNSPECIFIED
=
0
;
ACTIVE
=
1
;
enum
State
{
STATE
_UNSPECIFIED
=
0
;
NORMAL
=
1
;
ARCHIVED
=
2
;
}
...
...
proto/api/v1/memo_service.proto
View file @
2a861ea4
...
...
@@ -137,7 +137,7 @@ message Memo {
// The user defined id of the memo.
string
uid
=
2
;
RowStatus
row_status
=
3
;
State
state
=
3
;
// The name of the creator.
// Format: users/{id}
...
...
proto/api/v1/user_service.proto
View file @
2a861ea4
...
...
@@ -114,7 +114,7 @@ message User {
string
password
=
9
[(
google.api.field_behavior
)
=
INPUT_ONLY
];
RowStatus
row_status
=
10
;
State
state
=
10
;
google.protobuf.Timestamp
create_time
=
11
;
...
...
proto/api/v1/webhook_service.proto
View file @
2a861ea4
...
...
@@ -53,7 +53,7 @@ message Webhook {
google.protobuf.Timestamp
update_time
=
4
;
RowStatus
row_status
=
5
;
State
state
=
5
;
string
name
=
6
;
...
...
proto/gen/api/v1/common.pb.go
View file @
2a861ea4
...
...
@@ -20,52 +20,52 @@ const (
_
=
protoimpl
.
EnforceVersion
(
protoimpl
.
MaxVersion
-
20
)
)
type
RowStatus
int32
type
State
int32
const
(
RowStatus_ROW_STATUS_UNSPECIFIED
RowStatus
=
0
RowStatus_ACTIVE
RowStatus
=
1
RowStatus_ARCHIVED
RowStatus
=
2
State_STATE_UNSPECIFIED
State
=
0
State_NORMAL
State
=
1
State_ARCHIVED
State
=
2
)
// Enum value maps for
RowStatus
.
// Enum value maps for
State
.
var
(
RowStatus
_name
=
map
[
int32
]
string
{
0
:
"
ROW_STATUS
_UNSPECIFIED"
,
1
:
"
ACTIVE
"
,
State
_name
=
map
[
int32
]
string
{
0
:
"
STATE
_UNSPECIFIED"
,
1
:
"
NORMAL
"
,
2
:
"ARCHIVED"
,
}
RowStatus
_value
=
map
[
string
]
int32
{
"
ROW_STATUS
_UNSPECIFIED"
:
0
,
"
ACTIVE"
:
1
,
State
_value
=
map
[
string
]
int32
{
"
STATE
_UNSPECIFIED"
:
0
,
"
NORMAL"
:
1
,
"ARCHIVED"
:
2
,
}
)
func
(
x
RowStatus
)
Enum
()
*
RowStatus
{
p
:=
new
(
RowStatus
)
func
(
x
State
)
Enum
()
*
State
{
p
:=
new
(
State
)
*
p
=
x
return
p
}
func
(
x
RowStatus
)
String
()
string
{
func
(
x
State
)
String
()
string
{
return
protoimpl
.
X
.
EnumStringOf
(
x
.
Descriptor
(),
protoreflect
.
EnumNumber
(
x
))
}
func
(
RowStatus
)
Descriptor
()
protoreflect
.
EnumDescriptor
{
func
(
State
)
Descriptor
()
protoreflect
.
EnumDescriptor
{
return
file_api_v1_common_proto_enumTypes
[
0
]
.
Descriptor
()
}
func
(
RowStatus
)
Type
()
protoreflect
.
EnumType
{
func
(
State
)
Type
()
protoreflect
.
EnumType
{
return
&
file_api_v1_common_proto_enumTypes
[
0
]
}
func
(
x
RowStatus
)
Number
()
protoreflect
.
EnumNumber
{
func
(
x
State
)
Number
()
protoreflect
.
EnumNumber
{
return
protoreflect
.
EnumNumber
(
x
)
}
// Deprecated: Use
RowStatus
.Descriptor instead.
func
(
RowStatus
)
EnumDescriptor
()
([]
byte
,
[]
int
)
{
// Deprecated: Use
State
.Descriptor instead.
func
(
State
)
EnumDescriptor
()
([]
byte
,
[]
int
)
{
return
file_api_v1_common_proto_rawDescGZIP
(),
[]
int
{
0
}
}
...
...
@@ -130,22 +130,22 @@ var file_api_v1_common_proto_rawDesc = []byte{
0x2e
,
0x76
,
0x31
,
0x22
,
0x39
,
0x0a
,
0x09
,
0x50
,
0x61
,
0x67
,
0x65
,
0x54
,
0x6f
,
0x6b
,
0x65
,
0x6e
,
0x12
,
0x14
,
0x0a
,
0x05
,
0x6c
,
0x69
,
0x6d
,
0x69
,
0x74
,
0x18
,
0x01
,
0x20
,
0x01
,
0x28
,
0x05
,
0x52
,
0x05
,
0x6c
,
0x69
,
0x6d
,
0x69
,
0x74
,
0x12
,
0x16
,
0x0a
,
0x06
,
0x6f
,
0x66
,
0x66
,
0x73
,
0x65
,
0x74
,
0x18
,
0x02
,
0x20
,
0x01
,
0x28
,
0x05
,
0x52
,
0x06
,
0x6f
,
0x66
,
0x66
,
0x73
,
0x65
,
0x74
,
0x2a
,
0x
41
,
0x0a
,
0x0
9
,
0x52
,
0x6f
,
0x77
,
0x53
,
0x74
,
0x61
,
0x74
,
0x75
,
0x73
,
0x12
,
0x1a
,
0x0a
,
0x16
,
0x52
,
0x
4f
,
0x57
,
0x5f
,
0x53
,
0x54
,
0x41
,
0x54
,
0x55
,
0x53
,
0x5f
,
0x55
,
0x4e
,
0x53
,
0x50
,
0x45
,
0x43
,
0x
49
,
0x46
,
0x49
,
0x45
,
0x44
,
0x10
,
0x00
,
0x12
,
0x0a
,
0x0a
,
0x06
,
0x41
,
0x43
,
0x54
,
0x49
,
0x56
,
0x4
5
,
0x10
,
0x01
,
0x12
,
0x0c
,
0x0a
,
0x08
,
0x41
,
0x52
,
0x43
,
0x48
,
0x49
,
0x56
,
0x45
,
0x44
,
0x10
,
0x
02
,
0x42
,
0xa3
,
0x01
,
0x0a
,
0x10
,
0x63
,
0x6f
,
0x6d
,
0x2e
,
0x6d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x2e
,
0x6
1
,
0x70
,
0x69
,
0x2e
,
0x76
,
0x31
,
0x42
,
0x0b
,
0x43
,
0x6f
,
0x6d
,
0x6d
,
0x6f
,
0x6e
,
0x50
,
0x72
,
0x
6f
,
0x74
,
0x6f
,
0x50
,
0x01
,
0x5a
,
0x30
,
0x67
,
0x69
,
0x74
,
0x68
,
0x75
,
0x62
,
0x2e
,
0x63
,
0x6f
,
0x
6d
,
0x2f
,
0x75
,
0x73
,
0x65
,
0x6d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x2f
,
0x6d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x
2f
,
0x70
,
0x72
,
0x6f
,
0x74
,
0x6f
,
0x2f
,
0x67
,
0x65
,
0x6e
,
0x2f
,
0x61
,
0x70
,
0x69
,
0x2f
,
0x76
,
0x
31
,
0x3b
,
0x61
,
0x70
,
0x69
,
0x76
,
0x31
,
0xa2
,
0x02
,
0x03
,
0x4d
,
0x41
,
0x58
,
0xaa
,
0x02
,
0x0c
,
0x
4d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x2e
,
0x41
,
0x70
,
0x69
,
0x2e
,
0x56
,
0x31
,
0xca
,
0x02
,
0x0c
,
0x4d
,
0x
65
,
0x6d
,
0x6f
,
0x73
,
0x5c
,
0x41
,
0x70
,
0x69
,
0x5c
,
0x56
,
0x31
,
0xe2
,
0x02
,
0x18
,
0x4d
,
0x65
,
0x
6d
,
0x6f
,
0x73
,
0x5c
,
0x41
,
0x70
,
0x69
,
0x5c
,
0x56
,
0x31
,
0x5c
,
0x47
,
0x50
,
0x42
,
0x4d
,
0x65
,
0x
74
,
0x61
,
0x64
,
0x61
,
0x74
,
0x61
,
0xea
,
0x02
,
0x0e
,
0x4d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x3a
,
0x3a
,
0x
41
,
0x70
,
0x69
,
0x3a
,
0x3a
,
0x56
,
0x31
,
0x62
,
0x06
,
0x
70
,
0x72
,
0x6f
,
0x74
,
0x6f
,
0x33
,
0x18
,
0x02
,
0x20
,
0x01
,
0x28
,
0x05
,
0x52
,
0x06
,
0x6f
,
0x66
,
0x66
,
0x73
,
0x65
,
0x74
,
0x2a
,
0x
38
,
0x0a
,
0x0
5
,
0x53
,
0x74
,
0x61
,
0x74
,
0x65
,
0x12
,
0x15
,
0x0a
,
0x11
,
0x53
,
0x54
,
0x41
,
0x54
,
0x45
,
0x
5f
,
0x55
,
0x4e
,
0x53
,
0x50
,
0x45
,
0x43
,
0x49
,
0x46
,
0x49
,
0x45
,
0x44
,
0x10
,
0x00
,
0x12
,
0x0a
,
0x
0a
,
0x06
,
0x4e
,
0x4f
,
0x52
,
0x4d
,
0x41
,
0x4c
,
0x10
,
0x01
,
0x12
,
0x0c
,
0x0a
,
0x08
,
0x41
,
0x52
,
0x4
3
,
0x48
,
0x49
,
0x56
,
0x45
,
0x44
,
0x10
,
0x02
,
0x42
,
0xa3
,
0x01
,
0x0a
,
0x10
,
0x63
,
0x6f
,
0x6d
,
0x
2e
,
0x6d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x2e
,
0x61
,
0x70
,
0x69
,
0x2e
,
0x76
,
0x31
,
0x42
,
0x0b
,
0x43
,
0x6
f
,
0x6d
,
0x6d
,
0x6f
,
0x6e
,
0x50
,
0x72
,
0x6f
,
0x74
,
0x6f
,
0x50
,
0x01
,
0x5a
,
0x30
,
0x67
,
0x69
,
0x
74
,
0x68
,
0x75
,
0x62
,
0x2e
,
0x63
,
0x6f
,
0x6d
,
0x2f
,
0x75
,
0x73
,
0x65
,
0x6d
,
0x65
,
0x6d
,
0x6f
,
0x
73
,
0x2f
,
0x6d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x2f
,
0x70
,
0x72
,
0x6f
,
0x74
,
0x6f
,
0x2f
,
0x67
,
0x65
,
0x
6e
,
0x2f
,
0x61
,
0x70
,
0x69
,
0x2f
,
0x76
,
0x31
,
0x3b
,
0x61
,
0x70
,
0x69
,
0x76
,
0x31
,
0xa2
,
0x02
,
0x
03
,
0x4d
,
0x41
,
0x58
,
0xaa
,
0x02
,
0x0c
,
0x4d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x2e
,
0x41
,
0x70
,
0x69
,
0x
2e
,
0x56
,
0x31
,
0xca
,
0x02
,
0x0c
,
0x4d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x5c
,
0x41
,
0x70
,
0x69
,
0x5c
,
0x
56
,
0x31
,
0xe2
,
0x02
,
0x18
,
0x4d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x5c
,
0x41
,
0x70
,
0x69
,
0x5c
,
0x56
,
0x
31
,
0x5c
,
0x47
,
0x50
,
0x42
,
0x4d
,
0x65
,
0x74
,
0x61
,
0x64
,
0x61
,
0x74
,
0x61
,
0xea
,
0x02
,
0x0e
,
0x
4d
,
0x65
,
0x6d
,
0x6f
,
0x73
,
0x3a
,
0x3a
,
0x41
,
0x70
,
0x69
,
0x3a
,
0x3a
,
0x56
,
0x31
,
0x62
,
0x06
,
0x70
,
0x72
,
0x6f
,
0x74
,
0x6f
,
0x33
,
}
var
(
...
...
@@ -163,7 +163,7 @@ func file_api_v1_common_proto_rawDescGZIP() []byte {
var
file_api_v1_common_proto_enumTypes
=
make
([]
protoimpl
.
EnumInfo
,
1
)
var
file_api_v1_common_proto_msgTypes
=
make
([]
protoimpl
.
MessageInfo
,
1
)
var
file_api_v1_common_proto_goTypes
=
[]
any
{
(
RowStatus
)(
0
),
// 0: memos.api.v1.RowStatus
(
State
)(
0
),
// 0: memos.api.v1.State
(
*
PageToken
)(
nil
),
// 1: memos.api.v1.PageToken
}
var
file_api_v1_common_proto_depIdxs
=
[]
int32
{
...
...
proto/gen/api/v1/memo_service.pb.go
View file @
2a861ea4
This diff is collapsed.
Click to expand it.
proto/gen/api/v1/user_service.pb.go
View file @
2a861ea4
This diff is collapsed.
Click to expand it.
proto/gen/api/v1/webhook_service.pb.go
View file @
2a861ea4
This diff is collapsed.
Click to expand it.
proto/gen/apidocs.swagger.yaml
View file @
2a861ea4
...
...
@@ -630,8 +630,8 @@ paths:
updateTime
:
type
:
string
format
:
date-time
rowStatus
:
$ref
:
'
#/definitions/v1
RowStatus
'
state
:
$ref
:
'
#/definitions/v1
State
'
name
:
type
:
string
url
:
...
...
@@ -830,8 +830,8 @@ paths:
uid
:
type
:
string
description
:
The user defined id of the memo.
rowStatus
:
$ref
:
'
#/definitions/v1
RowStatus
'
state
:
$ref
:
'
#/definitions/v1
State
'
creator
:
type
:
string
title
:
"
The
name
of
the
creator.
\r\n
Format:
users/{id}"
...
...
@@ -1632,8 +1632,8 @@ paths:
type
:
string
password
:
type
:
string
rowStatus
:
$ref
:
'
#/definitions/v1
RowStatus
'
state
:
$ref
:
'
#/definitions/v1
State
'
createTime
:
type
:
string
format
:
date-time
...
...
@@ -1933,8 +1933,8 @@ definitions:
uid
:
type
:
string
description
:
The user defined id of the memo.
rowStatus
:
$ref
:
'
#/definitions/v1
RowStatus
'
state
:
$ref
:
'
#/definitions/v1
State
'
creator
:
type
:
string
title
:
"
The
name
of
the
creator.
\r\n
Format:
users/{id}"
...
...
@@ -2883,13 +2883,6 @@ definitions:
properties
:
markdown
:
type
:
string
v1RowStatus
:
type
:
string
enum
:
-
ROW_STATUS_UNSPECIFIED
-
ACTIVE
-
ARCHIVED
default
:
ROW_STATUS_UNSPECIFIED
v1SearchUsersResponse
:
type
:
object
properties
:
...
...
@@ -2903,6 +2896,13 @@ definitions:
properties
:
content
:
type
:
string
v1State
:
type
:
string
enum
:
-
STATE_UNSPECIFIED
-
NORMAL
-
ARCHIVED
default
:
STATE_UNSPECIFIED
v1StrikethroughNode
:
type
:
object
properties
:
...
...
@@ -3012,8 +3012,8 @@ definitions:
type
:
string
password
:
type
:
string
rowStatus
:
$ref
:
'
#/definitions/v1
RowStatus
'
state
:
$ref
:
'
#/definitions/v1
State
'
createTime
:
type
:
string
format
:
date-time
...
...
@@ -3056,8 +3056,8 @@ definitions:
updateTime
:
type
:
string
format
:
date-time
rowStatus
:
$ref
:
'
#/definitions/v1
RowStatus
'
state
:
$ref
:
'
#/definitions/v1
State
'
name
:
type
:
string
url
:
...
...
server/router/api/v1/common.go
View file @
2a861ea4
...
...
@@ -15,22 +15,22 @@ const (
DefaultPageSize
=
10
)
func
convert
RowStatusFromStore
(
rowStatus
store
.
RowStatus
)
v1pb
.
RowStatus
{
func
convert
StateFromStore
(
rowStatus
store
.
RowStatus
)
v1pb
.
State
{
switch
rowStatus
{
case
store
.
Normal
:
return
v1pb
.
RowStatus_ACTIVE
return
v1pb
.
State_NORMAL
case
store
.
Archived
:
return
v1pb
.
RowStatus
_ARCHIVED
return
v1pb
.
State
_ARCHIVED
default
:
return
v1pb
.
RowStatus_ROW_STATUS
_UNSPECIFIED
return
v1pb
.
State_STATE
_UNSPECIFIED
}
}
func
convert
RowStatusToStore
(
rowStatus
v1pb
.
RowStatus
)
store
.
RowStatus
{
switch
rowStatus
{
case
v1pb
.
RowStatus_ACTIVE
:
func
convert
StateToStore
(
state
v1pb
.
State
)
store
.
RowStatus
{
switch
state
{
case
v1pb
.
State_NORMAL
:
return
store
.
Normal
case
v1pb
.
RowStatus
_ARCHIVED
:
case
v1pb
.
State
_ARCHIVED
:
return
store
.
Archived
default
:
return
store
.
Normal
...
...
server/router/api/v1/memo_service.go
View file @
2a861ea4
...
...
@@ -271,8 +271,8 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
return
nil
,
status
.
Errorf
(
codes
.
PermissionDenied
,
"disable public memos system setting is enabled"
)
}
update
.
Visibility
=
&
visibility
}
else
if
path
==
"
row_status
"
{
rowStatus
:=
convert
RowStatusToStore
(
request
.
Memo
.
RowStatus
)
}
else
if
path
==
"
state
"
{
rowStatus
:=
convert
StateToStore
(
request
.
Memo
.
State
)
update
.
RowStatus
=
&
rowStatus
}
else
if
path
==
"create_time"
{
createdTs
:=
request
.
Memo
.
CreateTime
.
AsTime
()
.
Unix
()
...
...
server/router/api/v1/memo_service_converter.go
View file @
2a861ea4
...
...
@@ -30,7 +30,7 @@ func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Mem
memoMessage
:=
&
v1pb
.
Memo
{
Name
:
name
,
Uid
:
memo
.
UID
,
RowStatus
:
convertRowStatus
FromStore
(
memo
.
RowStatus
),
State
:
convertState
FromStore
(
memo
.
RowStatus
),
Creator
:
fmt
.
Sprintf
(
"%s%d"
,
UserNamePrefix
,
memo
.
CreatorID
),
CreateTime
:
timestamppb
.
New
(
time
.
Unix
(
memo
.
CreatedTs
,
0
)),
UpdateTime
:
timestamppb
.
New
(
time
.
Unix
(
memo
.
UpdatedTs
,
0
)),
...
...
server/router/api/v1/memo_service_filter.go
View file @
2a861ea4
...
...
@@ -9,6 +9,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apiv1
"github.com/usememos/memos/proto/gen/api/v1"
"github.com/usememos/memos/store"
)
...
...
@@ -141,7 +142,7 @@ var MemoFilterCELAttributes = []cel.EnvOption{
cel
.
Variable
(
"display_time_after"
,
cel
.
IntType
),
cel
.
Variable
(
"creator"
,
cel
.
StringType
),
cel
.
Variable
(
"uid"
,
cel
.
StringType
),
cel
.
Variable
(
"
row_status
"
,
cel
.
StringType
),
cel
.
Variable
(
"
state
"
,
cel
.
StringType
),
cel
.
Variable
(
"random"
,
cel
.
BoolType
),
cel
.
Variable
(
"limit"
,
cel
.
IntType
),
cel
.
Variable
(
"include_comments"
,
cel
.
BoolType
),
...
...
@@ -229,9 +230,9 @@ func findMemoField(callExpr *expr.Expr_Call, filter *MemoFilter) {
}
else
if
idExpr
.
Name
==
"creator"
{
creator
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetStringValue
()
filter
.
Creator
=
&
creator
}
else
if
idExpr
.
Name
==
"
row_status
"
{
rowStatus
:=
store
.
RowStatus
(
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetStringValue
(
))
filter
.
RowStatus
=
&
rowStatus
}
else
if
idExpr
.
Name
==
"
state
"
{
state
:=
convertStateToStore
(
apiv1
.
State
(
apiv1
.
State_value
[
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetStringValue
()]
))
filter
.
RowStatus
=
&
state
}
else
if
idExpr
.
Name
==
"random"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
Random
=
value
...
...
server/router/api/v1/user_service.go
View file @
2a861ea4
...
...
@@ -229,8 +229,8 @@ func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserR
}
passwordHashStr
:=
string
(
passwordHash
)
update
.
PasswordHash
=
&
passwordHashStr
}
else
if
field
==
"
row_status
"
{
rowStatus
:=
convert
RowStatusToStore
(
request
.
User
.
RowStatus
)
}
else
if
field
==
"
state
"
{
rowStatus
:=
convert
StateToStore
(
request
.
User
.
State
)
update
.
RowStatus
=
&
rowStatus
}
else
{
return
nil
,
status
.
Errorf
(
codes
.
InvalidArgument
,
"invalid update path: %s"
,
field
)
...
...
@@ -557,7 +557,7 @@ func convertUserFromStore(user *store.User) *v1pb.User {
userpb
:=
&
v1pb
.
User
{
Name
:
fmt
.
Sprintf
(
"%s%d"
,
UserNamePrefix
,
user
.
ID
),
Id
:
user
.
ID
,
RowStatus
:
convertRowStatus
FromStore
(
user
.
RowStatus
),
State
:
convertState
FromStore
(
user
.
RowStatus
),
CreateTime
:
timestamppb
.
New
(
time
.
Unix
(
user
.
CreatedTs
,
0
)),
UpdateTime
:
timestamppb
.
New
(
time
.
Unix
(
user
.
UpdatedTs
,
0
)),
Role
:
convertUserRoleFromStore
(
user
.
Role
),
...
...
server/router/api/v1/webhook_service.go
View file @
2a861ea4
...
...
@@ -74,9 +74,6 @@ func (s *APIV1Service) UpdateWebhook(ctx context.Context, request *v1pb.UpdateWe
update
:=
&
store
.
UpdateWebhook
{}
for
_
,
field
:=
range
request
.
UpdateMask
.
Paths
{
switch
field
{
case
"row_status"
:
rowStatus
:=
store
.
RowStatus
(
request
.
Webhook
.
RowStatus
.
String
())
update
.
RowStatus
=
&
rowStatus
case
"name"
:
update
.
Name
=
&
request
.
Webhook
.
Name
case
"url"
:
...
...
@@ -106,7 +103,7 @@ func convertWebhookFromStore(webhook *store.Webhook) *v1pb.Webhook {
Id
:
webhook
.
ID
,
CreateTime
:
timestamppb
.
New
(
time
.
Unix
(
webhook
.
CreatedTs
,
0
)),
UpdateTime
:
timestamppb
.
New
(
time
.
Unix
(
webhook
.
UpdatedTs
,
0
)),
RowStatus
:
convertRowStatus
FromStore
(
webhook
.
RowStatus
),
State
:
convertState
FromStore
(
webhook
.
RowStatus
),
CreatorId
:
webhook
.
CreatorID
,
Name
:
webhook
.
Name
,
Url
:
webhook
.
URL
,
...
...
web/src/components/MemoActionMenu.tsx
View file @
2a861ea4
...
...
@@ -17,7 +17,7 @@ import { useLocation } from "react-router-dom";
import
{
markdownServiceClient
}
from
"@/grpcweb"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
NodeType
}
from
"@/types/proto/api/v1/markdown_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
...
@@ -48,7 +48,7 @@ const MemoActionMenu = (props: Props) => {
const
location
=
useLocation
();
const
navigateTo
=
useNavigateTo
();
const
memoStore
=
useMemoStore
();
const
isArchived
=
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
;
const
isArchived
=
memo
.
state
===
State
.
ARCHIVED
;
const
hasCompletedTaskList
=
checkHasCompletedTaskList
(
memo
);
const
isInMemoDetailPage
=
location
.
pathname
.
startsWith
(
`/m/
${
memo
.
uid
}
`
);
...
...
@@ -84,15 +84,15 @@ const MemoActionMenu = (props: Props) => {
};
const
handleToggleMemoStatusClick
=
async
()
=>
{
const
stat
us
=
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
RowStatus
.
ACTIVE
:
RowStatus
.
ARCHIVED
;
const
message
=
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
t
(
"message.restored-successfully"
)
:
t
(
"message.archived-successfully"
);
const
stat
e
=
memo
.
state
===
State
.
ARCHIVED
?
State
.
NORMAL
:
State
.
ARCHIVED
;
const
message
=
memo
.
state
===
State
.
ARCHIVED
?
t
(
"message.restored-successfully"
)
:
t
(
"message.archived-successfully"
);
try
{
await
memoStore
.
updateMemo
(
{
name
:
memo
.
name
,
rowStatus
:
status
,
state
,
},
[
"
row_status
"
],
[
"
state
"
],
);
toast
(
message
);
}
catch
(
error
:
any
)
{
...
...
@@ -102,7 +102,7 @@ const MemoActionMenu = (props: Props) => {
}
if
(
isInMemoDetailPage
)
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
navigateTo
(
"/"
)
:
navigateTo
(
"/archived"
);
memo
.
state
===
State
.
ARCHIVED
?
navigateTo
(
"/"
)
:
navigateTo
(
"/archived"
);
}
};
...
...
@@ -186,12 +186,8 @@ const MemoActionMenu = (props: Props) => {
</
MenuItem
>
)
}
<
MenuItem
color=
"warning"
onClick=
{
handleToggleMemoStatusClick
}
>
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
(
<
ArchiveRestoreIcon
className=
"w-4 h-auto"
/>
)
:
(
<
ArchiveIcon
className=
"w-4 h-auto"
/>
)
}
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
t
(
"common.restore"
)
:
t
(
"common.archive"
)
}
{
isArchived
?
<
ArchiveRestoreIcon
className=
"w-4 h-auto"
/>
:
<
ArchiveIcon
className=
"w-4 h-auto"
/>
}
{
isArchived
?
t
(
"common.restore"
)
:
t
(
"common.archive"
)
}
</
MenuItem
>
<
MenuItem
color=
"danger"
onClick=
{
handleDeleteMemoClick
}
>
<
TrashIcon
className=
"w-4 h-auto"
/>
...
...
web/src/components/MemoEditor/ActionButton/AddMemoRelationPopover.tsx
View file @
2a861ea4
...
...
@@ -44,7 +44,7 @@ const AddMemoRelationPopover = (props: Props) => {
setIsFetching
(
true
);
try
{
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
row_status
== "NORMAL"`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
state
== "NORMAL"`
];
if
(
searchText
)
{
filters
.
push
(
`content_search == [
${
JSON
.
stringify
(
searchText
)}
]`
);
}
...
...
web/src/components/MemoReactionListView.tsx
View file @
2a861ea4
...
...
@@ -2,7 +2,7 @@ import { uniq } from "lodash-es";
import
{
memo
,
useEffect
,
useState
}
from
"react"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useUserStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Reaction
}
from
"@/types/proto/api/v1/reaction_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
...
...
@@ -19,7 +19,7 @@ const MemoReactionListView = (props: Props) => {
const
currentUser
=
useCurrentUser
();
const
userStore
=
useUserStore
();
const
[
reactionGroup
,
setReactionGroup
]
=
useState
<
Map
<
string
,
User
[]
>>
(
new
Map
());
const
readonly
=
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
;
const
readonly
=
memo
.
state
===
State
.
ARCHIVED
;
useEffect
(()
=>
{
(
async
()
=>
{
...
...
web/src/components/MemoView.tsx
View file @
2a861ea4
...
...
@@ -7,7 +7,7 @@ import useAsyncEffect from "@/hooks/useAsyncEffect";
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useUserStore
,
useWorkspaceSettingStore
,
useMemoStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
MemoRelation_Type
}
from
"@/types/proto/api/v1/memo_relation_service"
;
import
{
Memo
,
Visibility
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
WorkspaceMemoRelatedSetting
}
from
"@/types/proto/api/v1/workspace_setting_service"
;
...
...
@@ -58,7 +58,7 @@ const MemoView: React.FC<Props> = (props: Props) => {
(
relation
)
=>
relation
.
type
===
MemoRelation_Type
.
COMMENT
&&
relation
.
relatedMemo
?.
name
===
memo
.
name
,
).
length
;
const
relativeTimeFormat
=
Date
.
now
()
-
memo
.
displayTime
!
.
getTime
()
>
1000
*
60
*
60
*
24
?
"datetime"
:
"auto"
;
const
isArchived
=
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
;
const
isArchived
=
memo
.
state
===
State
.
ARCHIVED
;
const
readonly
=
memo
.
creator
!==
user
?.
name
&&
!
isSuperUser
(
user
);
const
isInMemoDetailPage
=
location
.
pathname
.
startsWith
(
`/m/
${
memo
.
uid
}
`
);
const
parentPage
=
props
.
parentPage
||
location
.
pathname
;
...
...
web/src/components/ReactionView.tsx
View file @
2a861ea4
...
...
@@ -3,7 +3,7 @@ import clsx from "clsx";
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
...
...
@@ -33,7 +33,7 @@ const ReactionView = (props: Props) => {
const
currentUser
=
useCurrentUser
();
const
memoStore
=
useMemoStore
();
const
hasReaction
=
users
.
some
((
user
)
=>
currentUser
&&
user
.
username
===
currentUser
.
username
);
const
readonly
=
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
;
const
readonly
=
memo
.
state
===
State
.
ARCHIVED
;
const
handleReactionClick
=
async
()
=>
{
if
(
!
currentUser
||
readonly
)
{
...
...
web/src/components/Settings/MemberSection.tsx
View file @
2a861ea4
...
...
@@ -7,12 +7,12 @@ import { toast } from "react-hot-toast";
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
stringifyUserRole
,
useUserStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
User
,
User_Role
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showChangeMemberPasswordDialog
from
"../ChangeMemberPasswordDialog"
;
interface
State
{
interface
Local
State
{
creatingUser
:
User
;
}
...
...
@@ -20,7 +20,7 @@ const MemberSection = () => {
const
t
=
useTranslate
();
const
currentUser
=
useCurrentUser
();
const
userStore
=
useUserStore
();
const
[
state
,
setState
]
=
useState
<
State
>
({
const
[
state
,
setState
]
=
useState
<
Local
State
>
({
creatingUser
:
User
.
fromPartial
({
username
:
""
,
password
:
""
,
...
...
@@ -107,9 +107,9 @@ const MemberSection = () => {
await
userServiceClient
.
updateUser
({
user
:
{
name
:
user
.
name
,
rowStatus
:
RowStatus
.
ARCHIVED
,
state
:
State
.
ARCHIVED
,
},
updateMask
:
[
"
row_status
"
],
updateMask
:
[
"
state
"
],
});
fetchUsers
();
}
...
...
@@ -119,9 +119,9 @@ const MemberSection = () => {
await
userServiceClient
.
updateUser
({
user
:
{
name
:
user
.
name
,
rowStatus
:
RowStatus
.
ACTIVE
,
state
:
State
.
NORMAL
,
},
updateMask
:
[
"
row_status
"
],
updateMask
:
[
"
state
"
],
});
fetchUsers
();
};
...
...
@@ -197,7 +197,7 @@ const MemberSection = () => {
<
td
className=
"whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-400"
>
{
stringifyUserRole
(
user
.
role
)
}
</
td
>
<
td
className=
"whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-400"
>
{
user
.
username
}
<
span
className=
"ml-1 italic"
>
{
user
.
rowStatus
===
RowStatus
.
ARCHIVED
&&
"(Archived)"
}
</
span
>
<
span
className=
"ml-1 italic"
>
{
user
.
state
===
State
.
ARCHIVED
&&
"(Archived)"
}
</
span
>
</
td
>
<
td
className=
"whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-400"
>
{
user
.
nickname
}
</
td
>
<
td
className=
"whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-400"
>
{
user
.
email
}
</
td
>
...
...
@@ -213,7 +213,7 @@ const MemberSection = () => {
<
MenuItem
onClick=
{
()
=>
handleChangePasswordClick
(
user
)
}
>
{
t
(
"setting.account-section.change-password"
)
}
</
MenuItem
>
{
user
.
rowStatus
===
RowStatus
.
ACTIVE
?
(
{
user
.
state
===
State
.
NORMAL
?
(
<
MenuItem
onClick=
{
()
=>
handleArchiveUserClick
(
user
)
}
>
{
t
(
"setting.member-section.archive-member"
)
}
</
MenuItem
>
)
:
(
<>
...
...
web/src/pages/Archived.tsx
View file @
2a861ea4
...
...
@@ -8,7 +8,7 @@ import PagedMemoList from "@/components/PagedMemoList";
import
SearchBar
from
"@/components/SearchBar"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
...
@@ -18,7 +18,7 @@ const Archived = () => {
const
memoFilterStore
=
useMemoFilterStore
();
const
memoListFilter
=
useMemo
(()
=>
{
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
row_status
== "ARCHIVED"`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
state
== "ARCHIVED"`
];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
for
(
const
filter
of
memoFilterStore
.
filters
)
{
...
...
@@ -59,7 +59,7 @@ const Archived = () => {
renderer=
{
(
memo
:
Memo
)
=>
<
MemoView
key=
{
`${memo.name}-${memo.updateTime}`
}
memo=
{
memo
}
showVisibility
compact
/>
}
listSort=
{
(
memos
:
Memo
[])
=>
memos
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
ARCHIVED
)
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
...
...
web/src/pages/Explore.tsx
View file @
2a861ea4
...
...
@@ -9,7 +9,7 @@ import PagedMemoList from "@/components/PagedMemoList";
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
const
Explore
=
()
=>
{
...
...
@@ -18,7 +18,7 @@ const Explore = () => {
const
memoFilterStore
=
useMemoFilterStore
();
const
memoListFilter
=
useMemo
(()
=>
{
const
filters
=
[
`
row_status
== "NORMAL"`
,
`visibilities == [
${
user
?
"'PUBLIC', 'PROTECTED'"
:
"'PUBLIC'"
}
]`
];
const
filters
=
[
`
state
== "NORMAL"`
,
`visibilities == [
${
user
?
"'PUBLIC', 'PROTECTED'"
:
"'PUBLIC'"
}
]`
];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
for
(
const
filter
of
memoFilterStore
.
filters
)
{
...
...
@@ -55,7 +55,7 @@ const Explore = () => {
renderer=
{
(
memo
:
Memo
)
=>
<
MemoView
key=
{
`${memo.name}-${memo.updateTime}`
}
memo=
{
memo
}
showCreator
showVisibility
compact
/>
}
listSort=
{
(
memos
:
Memo
[])
=>
memos
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
...
...
web/src/pages/Home.tsx
View file @
2a861ea4
...
...
@@ -10,7 +10,7 @@ import PagedMemoList from "@/components/PagedMemoList";
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
const
Home
=
()
=>
{
...
...
@@ -19,7 +19,7 @@ const Home = () => {
const
memoFilterStore
=
useMemoFilterStore
();
const
memoListFilter
=
useMemo
(()
=>
{
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
row_status
== "NORMAL"`
,
`order_by_pinned == true`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
state
== "NORMAL"`
,
`order_by_pinned == true`
];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
for
(
const
filter
of
memoFilterStore
.
filters
)
{
...
...
@@ -69,7 +69,7 @@ const Home = () => {
renderer=
{
(
memo
:
Memo
)
=>
<
MemoView
key=
{
`${memo.name}-${memo.displayTime}`
}
memo=
{
memo
}
showVisibility
showPinned
compact
/>
}
listSort=
{
(
memos
:
Memo
[])
=>
memos
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
...
...
web/src/pages/UserProfile.tsx
View file @
2a861ea4
...
...
@@ -12,7 +12,7 @@ import PagedMemoList from "@/components/PagedMemoList";
import
UserAvatar
from
"@/components/UserAvatar"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useMemoFilterStore
,
useUserStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
...
@@ -52,7 +52,7 @@ const UserProfile = () => {
return
""
;
}
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
row_status
== "NORMAL"`
,
`order_by_pinned == true`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`
state
== "NORMAL"`
,
`order_by_pinned == true`
];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
for
(
const
filter
of
memoFilterStore
.
filters
)
{
...
...
@@ -111,7 +111,7 @@ const UserProfile = () => {
)
}
listSort=
{
(
memos
:
Memo
[])
=>
memos
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
...
...
web/src/store/v1/memoMetadata.ts
View file @
2a861ea4
...
...
@@ -27,7 +27,7 @@ export const useMemoMetadataStore = create(
setState
:
(
state
:
State
)
=>
set
(
state
),
getState
:
()
=>
get
(),
fetchMemoMetadata
:
async
(
params
:
{
user
?:
User
;
location
?:
Location
<
any
>
})
=>
{
const
filters
=
[
`
row_status
== "NORMAL"`
];
const
filters
=
[
`
state
== "NORMAL"`
];
if
(
params
.
user
)
{
if
(
params
.
location
?.
pathname
===
Routes
.
EXPLORE
)
{
filters
.
push
(
`visibilities == ["PUBLIC", "PROTECTED"]`
);
...
...
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