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
f0e5a722
Commit
f0e5a722
authored
May 27, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: update search memo filter
parent
ba0876a5
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
216 additions
and
77 deletions
+216
-77
memo_service.go
server/router/api/v1/memo_service.go
+27
-0
memo.go
store/db/mysql/memo.go
+9
-0
memo.go
store/db/postgres/memo.go
+9
-0
memo.go
store/db/sqlite/memo.go
+9
-0
memo.go
store/memo.go
+5
-2
MemoFilter.tsx
web/src/components/MemoFilter.tsx
+74
-38
UserStatisticsView.tsx
web/src/components/UserStatisticsView.tsx
+34
-28
useFilterWithUrlParams.ts
web/src/hooks/useFilterWithUrlParams.ts
+2
-1
Home.tsx
web/src/pages/Home.tsx
+17
-6
filter.ts
web/src/store/module/filter.ts
+9
-1
filter.ts
web/src/store/reducer/filter.ts
+21
-1
No files found.
server/router/api/v1/memo_service.go
View file @
f0e5a722
...
...
@@ -883,6 +883,9 @@ func (s *APIV1Service) buildMemoFindWithFilter(ctx context.Context, find *store.
if
find
==
nil
{
find
=
&
store
.
FindMemo
{}
}
if
find
.
PayloadFind
==
nil
{
find
.
PayloadFind
=
&
store
.
FindMemoPayload
{}
}
if
filter
!=
""
{
filter
,
err
:=
parseSearchMemosFilter
(
filter
)
if
err
!=
nil
{
...
...
@@ -956,6 +959,15 @@ func (s *APIV1Service) buildMemoFindWithFilter(ctx context.Context, find *store.
if
filter
.
IncludeComments
{
find
.
ExcludeComments
=
false
}
if
filter
.
HasLink
{
find
.
PayloadFind
.
HasLink
=
true
}
if
filter
.
HasTaskList
{
find
.
PayloadFind
.
HasTaskList
=
true
}
if
filter
.
HasCode
{
find
.
PayloadFind
.
HasCode
=
true
}
}
user
,
err
:=
s
.
GetCurrentUser
(
ctx
)
...
...
@@ -1006,6 +1018,9 @@ var SearchMemosFilterCELAttributes = []cel.EnvOption{
cel
.
Variable
(
"random"
,
cel
.
BoolType
),
cel
.
Variable
(
"limit"
,
cel
.
IntType
),
cel
.
Variable
(
"include_comments"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_link"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_task_list"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_code"
,
cel
.
BoolType
),
}
type
SearchMemosFilter
struct
{
...
...
@@ -1021,6 +1036,9 @@ type SearchMemosFilter struct {
Random
bool
Limit
*
int
IncludeComments
bool
HasLink
bool
HasTaskList
bool
HasCode
bool
}
func
parseSearchMemosFilter
(
expression
string
)
(
*
SearchMemosFilter
,
error
)
{
...
...
@@ -1090,6 +1108,15 @@ func findSearchMemosField(callExpr *expr.Expr_Call, filter *SearchMemosFilter) {
}
else
if
idExpr
.
Name
==
"include_comments"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
IncludeComments
=
value
}
else
if
idExpr
.
Name
==
"has_link"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasLink
=
value
}
else
if
idExpr
.
Name
==
"has_task_list"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasTaskList
=
value
}
else
if
idExpr
.
Name
==
"has_code"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasCode
=
value
}
return
}
...
...
store/db/mysql/memo.go
View file @
f0e5a722
...
...
@@ -93,6 +93,15 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if
v
.
Tag
!=
nil
{
where
,
args
=
append
(
where
,
"JSON_CONTAINS(JSON_EXTRACT(`memo`.`payload`, '$.property.tags'), ?)"
),
append
(
args
,
fmt
.
Sprintf
(
`["%s"]`
,
*
v
.
Tag
))
}
if
v
.
HasLink
{
where
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE"
)
}
if
v
.
HasTaskList
{
where
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.hasTaskList') IS TRUE"
)
}
if
v
.
HasCode
{
where
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE"
)
}
}
if
find
.
ExcludeComments
{
having
=
append
(
having
,
"`parent_id` IS NULL"
)
...
...
store/db/postgres/memo.go
View file @
f0e5a722
...
...
@@ -84,6 +84,15 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if
v
.
Tag
!=
nil
{
where
,
args
=
append
(
where
,
"memo.payload->'property'->'tags' @> "
+
placeholder
(
len
(
args
)
+
1
)),
append
(
args
,
fmt
.
Sprintf
(
`["%s"]`
,
*
v
.
Tag
))
}
if
v
.
HasLink
{
where
=
append
(
where
,
"(memo.payload->'property'->>'hasLink')::BOOLEAN IS TRUE"
)
}
if
v
.
HasTaskList
{
where
=
append
(
where
,
"(memo.payload->'property'->>'hasTaskList')::BOOLEAN IS TRUE"
)
}
if
v
.
HasCode
{
where
=
append
(
where
,
"(memo.payload->'property'->>'hasCode')::BOOLEAN IS TRUE"
)
}
}
if
find
.
ExcludeComments
{
where
=
append
(
where
,
"memo_relation.related_memo_id IS NULL"
)
...
...
store/db/sqlite/memo.go
View file @
f0e5a722
...
...
@@ -85,6 +85,15 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if
v
.
Tag
!=
nil
{
where
,
args
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.tags') LIKE ?"
),
append
(
args
,
fmt
.
Sprintf
(
`%%"%s"%%`
,
*
v
.
Tag
))
}
if
v
.
HasLink
{
where
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE"
)
}
if
v
.
HasTaskList
{
where
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.hasTaskList') IS TRUE"
)
}
if
v
.
HasCode
{
where
=
append
(
where
,
"JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE"
)
}
}
if
find
.
ExcludeComments
{
where
=
append
(
where
,
"`parent_id` IS NULL"
)
...
...
store/memo.go
View file @
f0e5a722
...
...
@@ -83,8 +83,11 @@ type FindMemo struct {
}
type
FindMemoPayload
struct
{
Raw
*
string
Tag
*
string
Raw
*
string
Tag
*
string
HasLink
bool
HasTaskList
bool
HasCode
bool
}
type
UpdateMemo
struct
{
...
...
web/src/components/MemoFilter.tsx
View file @
f0e5a722
...
...
@@ -14,8 +14,14 @@ const MemoFilter = (props: Props) => {
const
location
=
useLocation
();
const
filterStore
=
useFilterStore
();
const
filter
=
filterStore
.
state
;
const
{
tag
:
tagQuery
,
text
:
textQuery
,
visibility
}
=
filter
;
const
showFilter
=
Boolean
(
tagQuery
||
textQuery
||
visibility
);
const
showFilter
=
Boolean
(
filter
.
tag
||
filter
.
text
||
filter
.
visibility
||
filter
.
memoPropertyFilter
?.
hasLink
||
filter
.
memoPropertyFilter
?.
hasTaskList
||
filter
.
memoPropertyFilter
?.
hasCode
,
);
useEffect
(()
=>
{
filterStore
.
clearFilter
();
...
...
@@ -36,42 +42,72 @@ const MemoFilter = (props: Props) => {
<
Icon
.
Filter
className=
"w-4 h-auto mr-1"
/>
<
span
>
{
t
(
"common.filter"
)
}
:
</
span
>
</
div
>
<
div
className=
{
"max-w-xs flex flex-row justify-start items-center px-2 mr-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through "
+
(
tagQuery
?
""
:
"!hidden"
)
}
onClick=
{
()
=>
{
filterStore
.
setTagFilter
(
undefined
);
}
}
>
<
Icon
.
Hash
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
{
tagQuery
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
<
div
className=
{
"max-w-xs flex flex-row justify-start items-center px-2 mr-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through "
+
(
visibility
?
""
:
"!hidden"
)
}
onClick=
{
()
=>
{
filterStore
.
setMemoVisibilityFilter
(
undefined
);
}
}
>
<
Icon
.
Eye
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
{
visibility
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
<
div
className=
{
"max-w-xs flex flex-row justify-start items-center px-2 mr-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through "
+
(
textQuery
?
""
:
"!hidden"
)
}
onClick=
{
()
=>
{
filterStore
.
setTextFilter
(
undefined
);
}
}
>
<
Icon
.
Search
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
{
textQuery
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
{
filter
.
tag
&&
(
<
div
className=
"max-w-xs flex flex-row justify-start items-center px-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through"
onClick=
{
()
=>
{
filterStore
.
setTagFilter
(
undefined
);
}
}
>
<
Icon
.
Hash
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
{
filter
.
tag
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
)
}
{
filter
.
visibility
&&
(
<
div
className=
"max-w-xs flex flex-row justify-start items-center px-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through"
onClick=
{
()
=>
{
filterStore
.
setMemoVisibilityFilter
(
undefined
);
}
}
>
<
Icon
.
Eye
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
{
filter
.
visibility
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
)
}
{
filter
.
text
&&
(
<
div
className=
"max-w-xs flex flex-row justify-start items-center px-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through"
onClick=
{
()
=>
{
filterStore
.
setTextFilter
(
undefined
);
}
}
>
<
Icon
.
Search
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
{
filter
.
text
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
)
}
{
filter
.
memoPropertyFilter
?.
hasLink
&&
(
<
div
className=
"max-w-xs flex flex-row justify-start items-center px-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through"
onClick=
{
()
=>
{
filterStore
.
setMemoPropertyFilter
({
hasLink
:
false
});
}
}
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
Has Link
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
)
}
{
filter
.
memoPropertyFilter
?.
hasTaskList
&&
(
<
div
className=
"max-w-xs flex flex-row justify-start items-center px-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through"
onClick=
{
()
=>
{
filterStore
.
setMemoPropertyFilter
({
hasTaskList
:
false
});
}
}
>
<
Icon
.
CheckCircle
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
Has Task
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
)
}
{
filter
.
memoPropertyFilter
?.
hasCode
&&
(
<
div
className=
"max-w-xs flex flex-row justify-start items-center px-2 cursor-pointer dark:text-gray-400 bg-gray-200 dark:bg-zinc-800 rounded whitespace-nowrap truncate hover:line-through"
onClick=
{
()
=>
{
filterStore
.
setMemoPropertyFilter
({
hasCode
:
false
});
}
}
>
<
Icon
.
Code2
className=
"w-4 h-auto mr-1 text-gray-500 dark:text-gray-400"
/>
Has Code
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
)
}
</
div
>
);
};
...
...
web/src/components/UserStatisticsView.tsx
View file @
f0e5a722
import
{
Divider
}
from
"@mui/joy"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
useMemoStore
,
useTagStore
}
from
"@/store/v1"
;
import
{
useFilterStore
}
from
"@/store/module"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
...
...
@@ -19,13 +21,12 @@ const UserStatisticsView = (props: Props) => {
const
{
user
}
=
props
;
const
t
=
useTranslate
();
const
memoStore
=
useMemoStore
();
const
tagStore
=
useTag
Store
();
const
filterStore
=
useFilter
Store
();
const
[
memoAmount
,
setMemoAmount
]
=
useState
(
0
);
const
[
isRequesting
,
setIsRequesting
]
=
useState
(
false
);
const
[
memoStats
,
setMemoStats
]
=
useState
<
UserMemoStats
>
({
links
:
0
,
todos
:
0
,
code
:
0
});
const
days
=
Math
.
ceil
((
Date
.
now
()
-
user
.
createTime
!
.
getTime
())
/
86400000
);
const
memos
=
Object
.
values
(
memoStore
.
getState
().
memoMapByName
);
const
tags
=
tagStore
.
sortedTags
().
length
;
useEffect
(()
=>
{
if
(
memos
.
length
===
0
)
{
...
...
@@ -60,7 +61,7 @@ const UserStatisticsView = (props: Props) => {
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
p
className=
"text-sm font-medium leading-6 dark:text-gray-500"
>
{
t
(
"common.statistics"
)
}
</
p
>
</
div
>
<
div
className=
"w-full grid grid-cols-
2
gap-x-4"
>
<
div
className=
"w-full grid grid-cols-
1
gap-x-4"
>
<
div
className=
"w-full flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center"
>
<
Icon
.
CalendarDays
className=
"w-4 h-auto mr-1"
/>
...
...
@@ -75,33 +76,38 @@ const UserStatisticsView = (props: Props) => {
</
div
>
{
isRequesting
?
<
Icon
.
Loader
className=
"animate-spin w-4 h-auto text-gray-400"
/>
:
<
span
className=
""
>
{
memoAmount
}
</
span
>
}
</
div
>
<
div
className=
"w-full flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center
"
>
<
Icon
.
Hash
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-base sm:text-sm"
>
{
t
(
"common.tags"
)
}
</
span
>
</
div
>
<
span
>
{
tags
}
</
span
>
</
div
>
<
div
className=
"w-full flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center"
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/
>
<
span
className=
"
block text-base sm:text-sm"
>
Links
</
span
>
<
Divider
className=
"!my-1 opacity-50"
/
>
<
div
className=
"w-full mt-1 flex flex-row justify-start items-center gap-x-2 gap-y-1 flex-wrap
"
>
<
div
className=
"w-auto border dark:border-zinc-800 px-1 rounded-md flex justify-between items-center cursor-pointer hover:opacity-80"
onClick=
{
()
=>
filterStore
.
setMemoPropertyFilter
({
hasLink
:
true
})
}
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/
>
<
span
className=
"block text-sm"
>
Links
</
span
>
<
/
div
>
<
span
className=
"
text-sm truncate"
>
{
memoStats
.
links
}
</
span
>
</
div
>
<
span
className=
""
>
{
memoStats
.
links
}
</
span
>
</
div
>
<
div
className=
"w-full flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center"
>
<
Icon
.
CheckCircle
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-base sm:text-sm"
>
Todos
</
span
>
<
div
className=
"w-auto border dark:border-zinc-800 px-1 rounded-md flex justify-between items-center cursor-pointer hover:opacity-80"
onClick=
{
()
=>
filterStore
.
setMemoPropertyFilter
({
hasTaskList
:
true
})
}
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
CheckCircle
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
Todos
</
span
>
</
div
>
<
span
className=
"text-sm truncate"
>
{
memoStats
.
todos
}
</
span
>
</
div
>
<
span
className=
""
>
{
memoStats
.
todos
}
</
span
>
</
div
>
<
div
className=
"w-full flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center"
>
<
Icon
.
Code2
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-base sm:text-sm"
>
Code
</
span
>
<
div
className=
"w-auto border dark:border-zinc-800 px-1 rounded-md flex justify-between items-center cursor-pointer hover:opacity-80"
onClick=
{
()
=>
filterStore
.
setMemoPropertyFilter
({
hasCode
:
true
})
}
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
Code2
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
Code
</
span
>
</
div
>
<
span
className=
"text-sm truncate"
>
{
memoStats
.
code
}
</
span
>
</
div
>
<
span
className=
""
>
{
memoStats
.
code
}
</
span
>
</
div
>
</
div
>
</
div
>
...
...
web/src/hooks/useFilterWithUrlParams.ts
View file @
f0e5a722
...
...
@@ -5,7 +5,7 @@ import { useFilterStore } from "@/store/module";
const
useFilterWithUrlParams
=
()
=>
{
const
location
=
useLocation
();
const
filterStore
=
useFilterStore
();
const
{
tag
,
text
}
=
filterStore
.
state
;
const
{
tag
,
text
,
memoPropertyFilter
}
=
filterStore
.
state
;
useEffect
(()
=>
{
const
urlParams
=
new
URLSearchParams
(
location
.
search
);
...
...
@@ -38,6 +38,7 @@ const useFilterWithUrlParams = () => {
return {
tag,
text,
memoPropertyFilter,
};
};
...
...
web/src/pages/Home.tsx
View file @
f0e5a722
...
...
@@ -25,7 +25,7 @@ const Home = () => {
const
memoList
=
useMemoList
();
const
[
isRequesting
,
setIsRequesting
]
=
useState
(
true
);
const
[
nextPageToken
,
setNextPageToken
]
=
useState
<
string
>
(
""
);
const
{
tag
:
tagQuery
,
text
:
textQuery
}
=
useFilterWithUrlParams
();
const
filter
=
useFilterWithUrlParams
();
const
sortedMemos
=
memoList
.
value
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
.
sort
((
a
,
b
)
=>
getTimeStampByDate
(
b
.
displayTime
)
-
getTimeStampByDate
(
a
.
displayTime
))
...
...
@@ -34,20 +34,31 @@ const Home = () => {
useEffect
(()
=>
{
memoList
.
reset
();
fetchMemos
(
""
);
},
[
tagQuery
,
textQuery
]);
},
[
filter
.
tag
,
filter
.
text
,
filter
.
memoPropertyFilter
]);
const
fetchMemos
=
async
(
nextPageToken
:
string
)
=>
{
setIsRequesting
(
true
);
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "NORMAL"`
,
`order_by_pinned == true`
];
const
contentSearch
:
string
[]
=
[];
if
(
textQuery
)
{
contentSearch
.
push
(
JSON
.
stringify
(
textQuery
));
if
(
filter
.
tag
)
{
contentSearch
.
push
(
JSON
.
stringify
(
filter
.
tag
));
}
if
(
contentSearch
.
length
>
0
)
{
filters
.
push
(
`content_search == [
${
contentSearch
.
join
(
", "
)}
]`
);
}
if
(
tagQuery
)
{
filters
.
push
(
`tag == "
${
tagQuery
}
"`
);
if
(
filter
.
text
)
{
filters
.
push
(
`tag == "
${
filter
.
text
}
"`
);
}
if
(
filter
.
memoPropertyFilter
)
{
if
(
filter
.
memoPropertyFilter
.
hasLink
)
{
filters
.
push
(
`has_link == true`
);
}
if
(
filter
.
memoPropertyFilter
.
hasTaskList
)
{
filters
.
push
(
`has_task_list == true`
);
}
if
(
filter
.
memoPropertyFilter
.
hasCode
)
{
filters
.
push
(
`has_code == true`
);
}
}
const
response
=
await
memoStore
.
fetchMemos
({
pageSize
:
DEFAULT_LIST_MEMOS_PAGE_SIZE
,
...
...
web/src/store/module/filter.ts
View file @
f0e5a722
import
{
Visibility
}
from
"@/types/proto/api/v1/memo_service"
;
import
store
,
{
useAppSelector
}
from
".."
;
import
{
set
Filter
}
from
"../reducer/filter"
;
import
{
MemoPropertyFilter
,
setFilter
,
setMemoProperty
Filter
}
from
"../reducer/filter"
;
export
const
useFilterStore
=
()
=>
{
const
state
=
useAppSelector
((
state
)
=>
state
.
filter
);
...
...
@@ -16,6 +16,7 @@ export const useFilterStore = () => {
tag
:
undefined
,
text
:
undefined
,
visibility
:
undefined
,
memoPropertyFilter
:
undefined
,
}),
);
},
...
...
@@ -40,5 +41,12 @@ export const useFilterStore = () => {
}),
);
},
setMemoPropertyFilter
:
(
memoPropertyFilter
:
Partial
<
MemoPropertyFilter
>
)
=>
{
store
.
dispatch
(
setMemoPropertyFilter
({
...
memoPropertyFilter
,
}),
);
},
};
};
web/src/store/reducer/filter.ts
View file @
f0e5a722
...
...
@@ -5,6 +5,13 @@ interface State {
tag
?:
string
;
text
?:
string
;
visibility
?:
Visibility
;
memoPropertyFilter
?:
MemoPropertyFilter
;
}
export
interface
MemoPropertyFilter
{
hasLink
?:
boolean
;
hasTaskList
?:
boolean
;
hasCode
?:
boolean
;
}
export
type
Filter
=
State
;
...
...
@@ -37,9 +44,22 @@ const filterSlice = createSlice({
...
action
.
payload
,
};
},
setMemoPropertyFilter
:
(
state
,
action
:
PayloadAction
<
Partial
<
MemoPropertyFilter
>>
)
=>
{
if
(
JSON
.
stringify
(
action
.
payload
)
===
state
.
memoPropertyFilter
)
{
return
state
;
}
return
{
...
state
,
memoPropertyFilter
:
{
...
state
.
memoPropertyFilter
,
...
action
.
payload
,
},
};
},
},
});
export
const
{
setFilter
}
=
filterSlice
.
actions
;
export
const
{
setFilter
,
setMemoPropertyFilter
}
=
filterSlice
.
actions
;
export
default
filterSlice
.
reducer
;
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