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
3fa91816
Commit
3fa91816
authored
Feb 04, 2022
by
email
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: sync frontend
parent
4535e0ce
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
447 additions
and
311 deletions
+447
-311
CreateShortcutDialog.tsx
web/src/components/CreateShortcutDialog.tsx
+20
-20
DeletedMemo.tsx
web/src/components/DeletedMemo.tsx
+1
-1
MemoEditor.tsx
web/src/components/MemoEditor.tsx
+1
-1
MemoFilter.tsx
web/src/components/MemoFilter.tsx
+4
-4
MemoList.tsx
web/src/components/MemoList.tsx
+4
-4
MemosHeader.tsx
web/src/components/MemosHeader.tsx
+5
-5
MyAccountSection.tsx
web/src/components/MyAccountSection.tsx
+7
-7
ShareMemoImageDialog.tsx
web/src/components/ShareMemoImageDialog.tsx
+1
-1
ShortcutList.tsx
web/src/components/ShortcutList.tsx
+38
-38
Sidebar.tsx
web/src/components/Sidebar.tsx
+2
-2
UserBanner.tsx
web/src/components/UserBanner.tsx
+1
-1
api.ts
web/src/helpers/api.ts
+74
-52
utils.ts
web/src/helpers/utils.ts
+4
-0
create-shortcut-dialog.less
web/src/less/create-shortcut-dialog.less
+2
-2
shortcut-list.less
web/src/less/shortcut-list.less
+9
-9
MemoTrash.tsx
web/src/pages/MemoTrash.tsx
+4
-4
Signin.tsx
web/src/pages/Signin.tsx
+3
-13
index.ts
web/src/services/index.ts
+2
-2
locationService.ts
web/src/services/locationService.ts
+6
-6
memoService.ts
web/src/services/memoService.ts
+21
-12
queryService.ts
web/src/services/queryService.ts
+0
-82
resourceService.ts
web/src/services/resourceService.ts
+1
-1
shortcutService.ts
web/src/services/shortcutService.ts
+93
-0
userService.ts
web/src/services/userService.ts
+19
-8
appStore.ts
web/src/stores/appStore.ts
+5
-5
globalStateStore.ts
web/src/stores/globalStateStore.ts
+2
-2
locationStore.ts
web/src/stores/locationStore.ts
+10
-10
shortcutStore.ts
web/src/stores/shortcutStore.ts
+92
-0
userStore.ts
web/src/stores/userStore.ts
+2
-2
api.d.ts
web/src/types/api.d.ts
+1
-6
location.d.ts
web/src/types/location.d.ts
+1
-1
models.d.ts
web/src/types/models.d.ts
+9
-7
vite.config.ts
web/vite.config.ts
+3
-3
No files found.
web/src/components/Create
Query
Dialog.tsx
→
web/src/components/Create
Shortcut
Dialog.tsx
View file @
3fa91816
import
{
memo
,
useCallback
,
useEffect
,
useState
}
from
"react"
;
import
{
memoService
,
query
Service
}
from
"../services"
;
import
{
memoService
,
shortcut
Service
}
from
"../services"
;
import
{
checkShouldShowMemoWithFilters
,
filterConsts
,
getDefaultFilter
,
relationConsts
}
from
"../helpers/filter"
;
import
useLoading
from
"../hooks/useLoading"
;
import
{
showDialog
}
from
"./Dialog"
;
import
toastHelper
from
"./Toast"
;
import
Selector
from
"./common/Selector"
;
import
"../less/create-
query
-dialog.less"
;
import
"../less/create-
shortcut
-dialog.less"
;
interface
Props
extends
DialogProps
{
query
Id
?:
string
;
shortcut
Id
?:
string
;
}
const
Create
Query
Dialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
destroy
,
query
Id
}
=
props
;
const
Create
Shortcut
Dialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
destroy
,
shortcut
Id
}
=
props
;
const
[
title
,
setTitle
]
=
useState
<
string
>
(
""
);
const
[
filters
,
setFilters
]
=
useState
<
Filter
[]
>
([]);
...
...
@@ -23,15 +23,15 @@ const CreateQueryDialog: React.FC<Props> = (props: Props) => {
}).
length
;
useEffect
(()
=>
{
const
queryTemp
=
queryService
.
getQueryById
(
query
Id
??
""
);
if
(
query
Temp
)
{
setTitle
(
query
Temp
.
title
);
const
temp
=
JSON
.
parse
(
queryTemp
.
querystring
);
const
shortcutTemp
=
shortcutService
.
getShortcutById
(
shortcut
Id
??
""
);
if
(
shortcut
Temp
)
{
setTitle
(
shortcut
Temp
.
title
);
const
temp
=
JSON
.
parse
(
shortcutTemp
.
payload
);
if
(
Array
.
isArray
(
temp
))
{
setFilters
(
temp
);
}
}
},
[
query
Id
]);
},
[
shortcut
Id
]);
const
handleTitleInputChange
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
text
=
e
.
target
.
value
as
string
;
...
...
@@ -45,12 +45,12 @@ const CreateQueryDialog: React.FC<Props> = (props: Props) => {
}
try
{
if
(
query
Id
)
{
const
edited
Query
=
await
queryService
.
updateQuery
(
query
Id
,
title
,
JSON
.
stringify
(
filters
));
queryService
.
editQuery
(
editedQuery
);
if
(
shortcut
Id
)
{
const
edited
Shortcut
=
await
shortcutService
.
updateShortcut
(
shortcut
Id
,
title
,
JSON
.
stringify
(
filters
));
shortcutService
.
editShortcut
(
shortcutService
.
convertResponseModelShortcut
(
editedShortcut
)
);
}
else
{
const
query
=
await
queryService
.
createQuery
(
title
,
JSON
.
stringify
(
filters
));
queryService
.
pushQuery
(
query
);
const
shortcut
=
await
shortcutService
.
createShortcut
(
title
,
JSON
.
stringify
(
filters
));
shortcutService
.
pushShortcut
(
shortcutService
.
convertResponseModelShortcut
(
shortcut
)
);
}
}
catch
(
error
:
any
)
{
toastHelper
.
error
(
error
.
message
);
...
...
@@ -90,7 +90,7 @@ const CreateQueryDialog: React.FC<Props> = (props: Props) => {
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
<
span
className=
"icon-text"
>
🔖
</
span
>
{
query
Id
?
"编辑检索"
:
"创建检索"
}
{
shortcut
Id
?
"编辑检索"
:
"创建检索"
}
</
p
>
<
button
className=
"btn close-btn"
onClick=
{
destroy
}
>
<
img
className=
"icon-img"
src=
"/icons/close.svg"
/>
...
...
@@ -298,12 +298,12 @@ const FilterInputer: React.FC<MemoFilterInputerProps> = (props: MemoFilterInpute
const
MemoFilterInputer
:
React
.
FC
<
MemoFilterInputerProps
>
=
memo
(
FilterInputer
);
export
default
function
showCreate
QueryDialog
(
query
Id
?:
string
):
void
{
export
default
function
showCreate
ShortcutDialog
(
shortcut
Id
?:
string
):
void
{
showDialog
(
{
className
:
"create-
query
-dialog"
,
className
:
"create-
shortcut
-dialog"
,
},
Create
Query
Dialog
,
{
query
Id
}
Create
Shortcut
Dialog
,
{
shortcut
Id
}
);
}
web/src/components/DeletedMemo.tsx
View file @
3fa91816
...
...
@@ -18,7 +18,7 @@ const DeletedMemo: React.FC<Props> = (props: Props) => {
const
memo
:
FormattedMemo
=
{
...
propsMemo
,
createdAtStr
:
utils
.
getDateTimeString
(
propsMemo
.
createdAt
),
deletedAtStr
:
utils
.
getDateTimeString
(
propsMemo
.
dele
tedAt
??
Date
.
now
()),
deletedAtStr
:
utils
.
getDateTimeString
(
propsMemo
.
upda
tedAt
??
Date
.
now
()),
};
const
[
showConfirmDeleteBtn
,
toggleConfirmDeleteBtn
]
=
useToggle
(
false
);
const
imageUrls
=
Array
.
from
(
memo
.
content
.
match
(
IMAGE_URL_REG
)
??
[]);
...
...
web/src/components/MemoEditor.tsx
View file @
3fa91816
...
...
@@ -130,7 +130,7 @@ const MemoEditor: React.FC<Props> = () => {
try
{
const
image
=
await
resourceService
.
upload
(
file
);
const
url
=
`/r/
${
image
.
id
}
/
${
image
.
filename
}
`
;
const
url
=
`/
h/
r/
${
image
.
id
}
/
${
image
.
filename
}
`
;
return
url
;
}
catch
(
error
:
any
)
{
...
...
web/src/components/MemoFilter.tsx
View file @
3fa91816
import
{
useContext
}
from
"react"
;
import
appContext
from
"../stores/appContext"
;
import
{
locationService
,
query
Service
}
from
"../services"
;
import
{
locationService
,
shortcut
Service
}
from
"../services"
;
import
utils
from
"../helpers/utils"
;
import
{
getTextWithMemoType
}
from
"../helpers/filter"
;
import
"../less/memo-filter.less"
;
...
...
@@ -12,8 +12,8 @@ const MemoFilter: React.FC<FilterProps> = () => {
locationState
:
{
query
},
}
=
useContext
(
appContext
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
filter
}
=
query
;
const
queryFilter
=
queryService
.
getQueryById
(
filter
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
}
=
query
;
const
queryFilter
=
shortcutService
.
getShortcutById
(
shortcutId
);
const
showFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
queryFilter
);
return
(
...
...
@@ -22,7 +22,7 @@ const MemoFilter: React.FC<FilterProps> = () => {
<
div
className=
{
"filter-item-container "
+
(
queryFilter
?
""
:
"hidden"
)
}
onClick=
{
()
=>
{
locationService
.
setMemo
Filter
(
""
);
locationService
.
setMemo
Shortcut
(
""
);
}
}
>
<
span
className=
"icon-text"
>
🔖
</
span
>
{
queryFilter
?.
title
}
...
...
web/src/components/MemoList.tsx
View file @
3fa91816
import
{
useCallback
,
useContext
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext"
;
import
{
locationService
,
memoService
,
query
Service
}
from
"../services"
;
import
{
locationService
,
memoService
,
shortcut
Service
}
from
"../services"
;
import
{
IMAGE_URL_REG
,
LINK_REG
,
MEMO_LINK_REG
,
TAG_REG
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
{
checkShouldShowMemoWithFilters
}
from
"../helpers/filter"
;
...
...
@@ -18,8 +18,8 @@ const MemoList: React.FC<Props> = () => {
const
[
isFetching
,
setFetchStatus
]
=
useState
(
true
);
const
wrapperElement
=
useRef
<
HTMLDivElement
>
(
null
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
filter
:
query
Id
}
=
query
;
const
queryFilter
=
queryService
.
getQueryById
(
query
Id
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcut
Id
}
=
query
;
const
queryFilter
=
shortcutService
.
getShortcutById
(
shortcut
Id
);
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
queryFilter
);
const
shownMemos
=
...
...
@@ -28,7 +28,7 @@ const MemoList: React.FC<Props> = () => {
let
shouldShow
=
true
;
if
(
queryFilter
)
{
const
filters
=
JSON
.
parse
(
queryFilter
.
querystring
)
as
Filter
[];
const
filters
=
JSON
.
parse
(
queryFilter
.
payload
)
as
Filter
[];
if
(
Array
.
isArray
(
filters
))
{
shouldShow
=
checkShouldShowMemoWithFilters
(
memo
,
filters
);
}
...
...
web/src/components/MemosHeader.tsx
View file @
3fa91816
import
{
useCallback
,
useContext
,
useEffect
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext"
;
import
SearchBar
from
"./SearchBar"
;
import
{
globalStateService
,
memoService
,
query
Service
}
from
"../services"
;
import
{
globalStateService
,
memoService
,
shortcut
Service
}
from
"../services"
;
import
Only
from
"./common/OnlyWhen"
;
import
"../less/memos-header.less"
;
...
...
@@ -12,22 +12,22 @@ interface Props {}
const
MemosHeader
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
locationState
:
{
query
:
{
filter
},
query
:
{
shortcutId
},
},
globalState
:
{
isMobileView
},
queryState
:
{
querie
s
},
shortcutState
:
{
shortcut
s
},
}
=
useContext
(
appContext
);
const
[
titleText
,
setTitleText
]
=
useState
(
"MEMOS"
);
useEffect
(()
=>
{
const
query
=
queryService
.
getQueryById
(
filter
);
const
query
=
shortcutService
.
getShortcutById
(
shortcutId
);
if
(
query
)
{
setTitleText
(
query
.
title
);
}
else
{
setTitleText
(
"MEMOS"
);
}
},
[
filter
,
querie
s
]);
},
[
shortcutId
,
shortcut
s
]);
const
handleMemoTextClick
=
useCallback
(()
=>
{
const
now
=
Date
.
now
();
...
...
web/src/components/MyAccountSection.tsx
View file @
3fa91816
...
...
@@ -20,8 +20,8 @@ interface Props {}
const
MyAccountSection
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
userState
}
=
useContext
(
appContext
);
const
user
=
userState
.
user
as
Model
.
User
;
const
[
username
,
setUsername
]
=
useState
<
string
>
(
user
.
user
name
);
const
openAPIRoute
=
`
${
window
.
location
.
origin
}
/
api/whs/memo/
${
user
.
openId
}
`
;
const
[
username
,
setUsername
]
=
useState
<
string
>
(
user
.
name
);
const
openAPIRoute
=
`
${
window
.
location
.
origin
}
/
h/
${
user
.
openId
}
/memo
`
;
const
handleUsernameChanged
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
nextUsername
=
e
.
target
.
value
as
string
;
...
...
@@ -29,12 +29,12 @@ const MyAccountSection: React.FC<Props> = () => {
};
const
handleConfirmEditUsernameBtnClick
=
async
()
=>
{
if
(
user
.
user
name
===
"guest"
)
{
if
(
user
.
name
===
"guest"
)
{
toastHelper
.
info
(
"🈲 不要修改我的用户名"
);
return
;
}
if
(
username
===
user
.
user
name
)
{
if
(
username
===
user
.
name
)
{
return
;
}
...
...
@@ -61,7 +61,7 @@ const MyAccountSection: React.FC<Props> = () => {
};
const
handleChangePasswordBtnClick
=
()
=>
{
if
(
user
.
user
name
===
"guest"
)
{
if
(
user
.
name
===
"guest"
)
{
toastHelper
.
info
(
"🈲 不要修改我的密码"
);
return
;
}
...
...
@@ -93,14 +93,14 @@ const MyAccountSection: React.FC<Props> = () => {
<
label
className=
"form-label input-form-label username-label"
>
<
span
className=
"normal-text"
>
账号:
</
span
>
<
input
type=
"text"
value=
{
username
}
onChange=
{
handleUsernameChanged
}
/>
<
div
className=
{
`btns-container ${username === user.
user
name ? "hidden" : ""}`
}
onClick=
{
handlePreventDefault
}
>
<
div
className=
{
`btns-container ${username === user.name ? "hidden" : ""}`
}
onClick=
{
handlePreventDefault
}
>
<
span
className=
"btn confirm-btn"
onClick=
{
handleConfirmEditUsernameBtnClick
}
>
保存
</
span
>
<
span
className=
"btn cancel-btn"
onClick=
{
()
=>
{
setUsername
(
user
.
user
name
);
setUsername
(
user
.
name
);
}
}
>
撤销
...
...
web/src/components/ShareMemoImageDialog.tsx
View file @
3fa91816
...
...
@@ -97,7 +97,7 @@ const ShareMemoImageDialog: React.FC<Props> = (props: Props) => {
</
Only
>
<
div
className=
"watermark-container"
>
<
span
className=
"normal-text"
>
<
span
className=
"icon-text"
>
✍️
</
span
>
by
<
span
className=
"name-text"
>
{
userinfo
?.
user
name
}
</
span
>
<
span
className=
"icon-text"
>
✍️
</
span
>
by
<
span
className=
"name-text"
>
{
userinfo
?.
name
}
</
span
>
</
span
>
</
div
>
</
div
>
...
...
web/src/components/
Query
List.tsx
→
web/src/components/
Shortcut
List.tsx
View file @
3fa91816
...
...
@@ -5,27 +5,27 @@ import useLoading from "../hooks/useLoading";
import
Only
from
"./common/OnlyWhen"
;
import
utils
from
"../helpers/utils"
;
import
toastHelper
from
"./Toast"
;
import
{
locationService
,
query
Service
}
from
"../services"
;
import
showCreateQueryDialog
from
"./Create
Query
Dialog"
;
import
"../less/
query
-list.less"
;
import
{
locationService
,
shortcut
Service
}
from
"../services"
;
import
showCreateQueryDialog
from
"./Create
Shortcut
Dialog"
;
import
"../less/
shortcut
-list.less"
;
interface
Props
{}
const
Query
List
:
React
.
FC
<
Props
>
=
()
=>
{
const
Shortcut
List
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
queryState
:
{
querie
s
},
shortcutState
:
{
shortcut
s
},
locationState
:
{
query
:
{
filter
},
query
:
{
shortcutId
},
},
}
=
useContext
(
appContext
);
const
loadingState
=
useLoading
();
const
sorted
Queries
=
querie
s
const
sorted
Shortcuts
=
shortcut
s
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
createdAt
)
-
utils
.
getTimeStampByDate
(
a
.
createdAt
))
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
pinnedAt
??
0
)
-
utils
.
getTimeStampByDate
(
a
.
pinnedAt
??
0
));
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
updatedAt
)
-
utils
.
getTimeStampByDate
(
a
.
updatedAt
));
useEffect
(()
=>
{
query
Service
.
getMyAll
Querie
s
()
shortcut
Service
.
getMyAll
Shortcut
s
()
.
catch
(()
=>
{
// do nth
})
...
...
@@ -35,47 +35,47 @@ const QueryList: React.FC<Props> = () => {
},
[]);
return
(
<
div
className=
"
querie
s-wrapper"
>
<
div
className=
"
shortcut
s-wrapper"
>
<
p
className=
"title-text"
>
<
span
className=
"normal-text"
>
快速检索
</
span
>
<
span
className=
"btn"
onClick=
{
()
=>
showCreateQueryDialog
()
}
>
+
</
span
>
</
p
>
<
Only
when=
{
loadingState
.
isSucceed
&&
sorted
Querie
s
.
length
===
0
}
>
<
div
className=
"create-
query
-btn-container"
>
<
Only
when=
{
loadingState
.
isSucceed
&&
sorted
Shortcut
s
.
length
===
0
}
>
<
div
className=
"create-
shortcut
-btn-container"
>
<
span
className=
"btn"
onClick=
{
()
=>
showCreateQueryDialog
()
}
>
创建检索
</
span
>
</
div
>
</
Only
>
<
div
className=
"
querie
s-container"
>
{
sorted
Queries
.
map
((
q
)
=>
{
return
<
QueryItemContainer
key=
{
q
.
id
}
query=
{
q
}
isActive=
{
q
.
id
===
filter
}
/>;
<
div
className=
"
shortcut
s-container"
>
{
sorted
Shortcuts
.
map
((
s
)
=>
{
return
<
ShortcutContainer
key=
{
s
.
id
}
shortcut=
{
s
}
isActive=
{
s
.
id
===
shortcutId
}
/>;
})
}
</
div
>
</
div
>
);
};
interface
QueryItem
ContainerProps
{
query
:
Model
.
Query
;
interface
Shortcut
ContainerProps
{
shortcut
:
Model
.
Shortcut
;
isActive
:
boolean
;
}
const
QueryItemContainer
:
React
.
FC
<
QueryItemContainerProps
>
=
(
props
:
QueryItem
ContainerProps
)
=>
{
const
{
query
,
isActive
}
=
props
;
const
ShortcutContainer
:
React
.
FC
<
ShortcutContainerProps
>
=
(
props
:
Shortcut
ContainerProps
)
=>
{
const
{
shortcut
,
isActive
}
=
props
;
const
[
showActionBtns
,
toggleShowActionBtns
]
=
useToggle
(
false
);
const
[
showConfirmDeleteBtn
,
toggleConfirmDeleteBtn
]
=
useToggle
(
false
);
const
handleQueryClick
=
()
=>
{
if
(
isActive
)
{
locationService
.
setMemo
Filter
(
""
);
locationService
.
setMemo
Shortcut
(
""
);
}
else
{
if
(
!
[
"/"
,
"/recycle"
].
includes
(
locationService
.
getState
().
pathname
))
{
locationService
.
setPathname
(
"/"
);
}
locationService
.
setMemo
Filter
(
query
.
id
);
locationService
.
setMemo
Shortcut
(
shortcut
.
id
);
}
};
...
...
@@ -93,7 +93,7 @@ const QueryItemContainer: React.FC<QueryItemContainerProps> = (props: QueryItemC
if
(
showConfirmDeleteBtn
)
{
try
{
await
queryService
.
deleteQuery
(
query
.
id
);
await
shortcutService
.
deleteShortcut
(
shortcut
.
id
);
}
catch
(
error
:
any
)
{
toastHelper
.
error
(
error
.
message
);
}
...
...
@@ -104,24 +104,24 @@ const QueryItemContainer: React.FC<QueryItemContainerProps> = (props: QueryItemC
const
handleEditQueryBtnClick
=
(
event
:
React
.
MouseEvent
)
=>
{
event
.
stopPropagation
();
showCreateQueryDialog
(
query
.
id
);
showCreateQueryDialog
(
shortcut
.
id
);
};
const
handlePinQueryBtnClick
=
async
(
event
:
React
.
MouseEvent
)
=>
{
event
.
stopPropagation
();
try
{
if
(
query
.
pinnedAt
)
{
await
queryService
.
unpinQuery
(
query
.
id
);
queryService
.
editQuery
({
...
query
,
pinnedAt
:
"
"
,
if
(
shortcut
.
rowStatus
===
"ARCHIVED"
)
{
await
shortcutService
.
unpinShortcut
(
shortcut
.
id
);
shortcutService
.
editShortcut
({
...
shortcut
,
rowStatus
:
"NORMAL
"
,
});
}
else
{
await
queryService
.
pinQuery
(
query
.
id
);
queryService
.
editQuery
({
...
query
,
pinnedAt
:
utils
.
getDateTimeString
(
Date
.
now
())
,
await
shortcutService
.
pinShortcut
(
shortcut
.
id
);
shortcutService
.
editShortcut
({
...
shortcut
,
rowStatus
:
"NORMAL"
,
});
}
}
catch
(
error
)
{
...
...
@@ -135,10 +135,10 @@ const QueryItemContainer: React.FC<QueryItemContainerProps> = (props: QueryItemC
return
(
<>
<
div
className=
{
`
query-item
-container ${isActive ? "active" : ""}`
}
onClick=
{
handleQueryClick
}
>
<
div
className=
"
query
-text-container"
>
<
div
className=
{
`
shortcut
-container ${isActive ? "active" : ""}`
}
onClick=
{
handleQueryClick
}
>
<
div
className=
"
shortcut
-text-container"
>
<
span
className=
"icon-text"
>
#
</
span
>
<
span
className=
"
query-text"
>
{
query
.
title
}
</
span
>
<
span
className=
"
shortcut-text"
>
{
shortcut
.
title
}
</
span
>
</
div
>
<
div
className=
"btns-container"
>
<
span
className=
"action-btn toggle-btn"
onClick=
{
handleShowActionBtnClick
}
>
...
...
@@ -147,7 +147,7 @@ const QueryItemContainer: React.FC<QueryItemContainerProps> = (props: QueryItemC
<
div
className=
{
`action-btns-wrapper ${showActionBtns ? "" : "hidden"}`
}
onMouseLeave=
{
handleActionBtnContainerMouseLeave
}
>
<
div
className=
"action-btns-container"
>
<
span
className=
"btn"
onClick=
{
handlePinQueryBtnClick
}
>
{
query
.
pinnedAt
?
"取消置顶"
:
"置顶"
}
{
shortcut
.
rowStatus
===
"ARCHIVED"
?
"取消置顶"
:
"置顶"
}
</
span
>
<
span
className=
"btn"
onClick=
{
handleEditQueryBtnClick
}
>
编辑
...
...
@@ -167,4 +167,4 @@ const QueryItemContainer: React.FC<QueryItemContainerProps> = (props: QueryItemC
);
};
export
default
Query
List
;
export
default
Shortcut
List
;
web/src/components/Sidebar.tsx
View file @
3fa91816
...
...
@@ -3,7 +3,7 @@ import appContext from "../stores/appContext";
import
{
SHOW_SIDERBAR_MOBILE_CLASSNAME
}
from
"../helpers/consts"
;
import
{
globalStateService
}
from
"../services"
;
import
UserBanner
from
"./UserBanner"
;
import
QueryList
from
"./Query
List"
;
import
ShortcutList
from
"./Shortcut
List"
;
import
TagList
from
"./TagList"
;
import
UsageHeatMap
from
"./UsageHeatMap"
;
import
"../less/siderbar.less"
;
...
...
@@ -66,7 +66,7 @@ const Sidebar: React.FC<Props> = () => {
<
aside
className=
"sidebar-wrapper"
ref=
{
wrapperElRef
}
>
<
UserBanner
/>
<
UsageHeatMap
/>
<
Query
List
/>
<
Shortcut
List
/>
<
TagList
/>
</
aside
>
);
...
...
web/src/components/UserBanner.tsx
View file @
3fa91816
...
...
@@ -13,7 +13,7 @@ const UserBanner: React.FC<Props> = () => {
memoState
:
{
memos
,
tags
},
userState
:
{
user
},
}
=
useContext
(
appContext
);
const
username
=
user
?
user
.
user
name
:
"Memos"
;
const
username
=
user
?
user
.
name
:
"Memos"
;
const
createdDays
=
user
?
Math
.
ceil
((
Date
.
now
()
-
utils
.
getTimeStampByDate
(
user
.
createdAt
))
/
1000
/
3600
/
24
)
:
0
;
const
[
shouldShowPopupBtns
,
setShouldShowPopupBtns
]
=
useState
(
false
);
...
...
web/src/helpers/api.ts
View file @
3fa91816
import
utils
from
"./utils"
;
type
ResponseType
<
T
=
unknown
>
=
{
succeed
:
boolean
;
message
:
string
;
type
ResponseObject
<
T
>
=
{
data
:
T
;
error
?:
string
;
message
?:
string
;
};
type
RequestConfig
=
{
...
...
@@ -13,7 +11,7 @@ type RequestConfig = {
dataType
?:
"json"
|
"file"
;
};
async
function
request
<
T
>
(
config
:
RequestConfig
):
Promise
<
ResponseType
<
T
>
>
{
async
function
request
<
T
>
(
config
:
RequestConfig
):
Promise
<
T
>
{
const
{
method
,
url
,
data
,
dataType
}
=
config
;
const
requestConfig
:
RequestInit
=
{
method
,
...
...
@@ -31,13 +29,13 @@ async function request<T>(config: RequestConfig): Promise<ResponseType<T>> {
}
const
response
=
await
fetch
(
url
,
requestConfig
);
const
responseData
=
(
await
response
.
json
())
as
Response
Type
<
T
>
;
const
responseData
=
(
await
response
.
json
())
as
Response
Object
<
T
>
;
if
(
!
responseData
.
succeed
)
{
throw
responseData
;
if
(
responseData
.
error
||
responseData
.
message
)
{
throw
new
Error
(
responseData
.
error
||
responseData
.
message
)
;
}
return
responseData
;
return
responseData
.
data
;
}
namespace
api
{
...
...
@@ -48,34 +46,42 @@ namespace api {
});
}
export
function
signin
(
user
name
:
string
,
password
:
string
)
{
return
request
({
export
function
login
(
name
:
string
,
password
:
string
)
{
return
request
<
Model
.
User
>
({
method
:
"POST"
,
url
:
"/api/auth/signin"
,
data
:
{
username
,
password
},
url
:
"/api/auth/login"
,
data
:
{
name
,
password
,
},
});
}
export
function
signup
(
user
name
:
string
,
password
:
string
)
{
return
request
({
export
function
signup
(
name
:
string
,
password
:
string
)
{
return
request
<
Model
.
User
>
({
method
:
"POST"
,
url
:
"/api/auth/signup"
,
data
:
{
username
,
password
},
data
:
{
name
,
password
,
},
});
}
export
function
signout
()
{
return
request
({
method
:
"POST"
,
url
:
"/api/auth/
sign
out"
,
url
:
"/api/auth/
log
out"
,
});
}
export
function
checkUsernameUsable
(
user
name
:
string
)
{
export
function
checkUsernameUsable
(
name
:
string
)
{
return
request
<
boolean
>
({
method
:
"POST"
,
url
:
"/api/user/checkusername"
,
data
:
{
username
},
data
:
{
name
,
},
});
}
...
...
@@ -83,11 +89,13 @@ namespace api {
return
request
<
boolean
>
({
method
:
"POST"
,
url
:
"/api/user/validpassword"
,
data
:
{
password
},
data
:
{
password
,
},
});
}
export
function
updateUserinfo
(
userinfo
:
Partial
<
{
user
name
:
string
;
password
:
string
}
>
)
{
export
function
updateUserinfo
(
userinfo
:
Partial
<
{
name
:
string
;
password
:
string
}
>
)
{
return
request
({
method
:
"PATCH"
,
url
:
"/api/user/me"
,
...
...
@@ -105,22 +113,24 @@ namespace api {
export
function
getMyMemos
()
{
return
request
<
Model
.
Memo
[]
>
({
method
:
"GET"
,
url
:
"/api/memo
/all
"
,
url
:
"/api/memo"
,
});
}
export
function
getMyDeletedMemos
()
{
return
request
<
Model
.
Memo
[]
>
({
method
:
"GET"
,
url
:
"/api/memo/
all?deleted
=true"
,
url
:
"/api/memo/
?hidden
=true"
,
});
}
export
function
createMemo
(
content
:
string
)
{
return
request
<
Model
.
Memo
>
({
method
:
"PUT"
,
url
:
"/api/memo/"
,
data
:
{
content
},
method
:
"POST"
,
url
:
"/api/memo"
,
data
:
{
content
,
},
});
}
...
...
@@ -128,7 +138,9 @@ namespace api {
return
request
<
Model
.
Memo
>
({
method
:
"PATCH"
,
url
:
`/api/memo/
${
memoId
}
`
,
data
:
{
content
},
data
:
{
content
,
},
});
}
...
...
@@ -137,7 +149,7 @@ namespace api {
method
:
"PATCH"
,
url
:
`/api/memo/
${
memoId
}
`
,
data
:
{
deletedAt
:
utils
.
getDateTimeString
(
Date
.
now
())
,
rowStatus
:
"HIDDEN"
,
},
});
}
...
...
@@ -147,7 +159,7 @@ namespace api {
method
:
"PATCH"
,
url
:
`/api/memo/
${
memoId
}
`
,
data
:
{
deletedAt
:
"
"
,
rowStatus
:
"NORMAL
"
,
},
});
}
...
...
@@ -159,56 +171,66 @@ namespace api {
});
}
export
function
getMy
Querie
s
()
{
return
request
<
Model
.
Query
[]
>
({
export
function
getMy
Shortcut
s
()
{
return
request
<
Model
.
Shortcut
[]
>
({
method
:
"GET"
,
url
:
"/api/
query/all
"
,
url
:
"/api/
shortcut
"
,
});
}
export
function
createQuery
(
title
:
string
,
querystring
:
string
)
{
return
request
<
Model
.
Query
>
({
method
:
"PUT"
,
url
:
"/api/query/"
,
data
:
{
title
,
querystring
},
export
function
createShortcut
(
title
:
string
,
payload
:
string
)
{
return
request
<
Model
.
Shortcut
>
({
method
:
"POST"
,
url
:
"/api/shortcut"
,
data
:
{
title
,
payload
,
},
});
}
export
function
update
Query
(
queryId
:
string
,
title
:
string
,
querystring
:
string
)
{
return
request
<
Model
.
Query
>
({
export
function
update
Shortcut
(
shortcutId
:
string
,
title
:
string
,
payload
:
string
)
{
return
request
<
Model
.
Shortcut
>
({
method
:
"PATCH"
,
url
:
`/api/query/
${
queryId
}
`
,
data
:
{
title
,
querystring
},
url
:
`/api/shortcut/
${
shortcutId
}
`
,
data
:
{
title
,
payload
,
},
});
}
export
function
delete
QueryById
(
query
Id
:
string
)
{
export
function
delete
ShortcutById
(
shortcut
Id
:
string
)
{
return
request
({
method
:
"DELETE"
,
url
:
`/api/
query/
${
query
Id
}
`
,
url
:
`/api/
shortcut/
${
shortcut
Id
}
`
,
});
}
export
function
pin
Query
(
query
Id
:
string
)
{
export
function
pin
Shortcut
(
shortcut
Id
:
string
)
{
return
request
({
method
:
"PATCH"
,
url
:
`/api/query/
${
queryId
}
`
,
data
:
{
pinnedAt
:
utils
.
getDateTimeString
(
Date
.
now
())
},
url
:
`/api/shortcut/
${
shortcutId
}
`
,
data
:
{
rowStatus
:
"ARCHIVED"
,
},
});
}
export
function
unpin
Query
(
query
Id
:
string
)
{
export
function
unpin
Shortcut
(
shortcut
Id
:
string
)
{
return
request
({
method
:
"PATCH"
,
url
:
`/api/query/
${
queryId
}
`
,
data
:
{
pinnedAt
:
""
},
url
:
`/api/shortcut/
${
shortcutId
}
`
,
data
:
{
rowStatus
:
"NORMAL"
,
},
});
}
export
function
uploadFile
(
formData
:
FormData
)
{
return
request
<
Model
.
Resource
>
({
method
:
"P
U
T"
,
url
:
"/api/resource
/
"
,
method
:
"P
OS
T"
,
url
:
"/api/resource"
,
data
:
formData
,
dataType
:
"file"
,
});
...
...
web/src/helpers/utils.ts
View file @
3fa91816
...
...
@@ -43,6 +43,10 @@ namespace utils {
return
`
${
year
}
/
${
month
}
/
${
date
}
`
;
}
export
function
getDataStringWithTs
(
ts
:
number
):
string
{
return
getDateTimeString
(
ts
*
1000
);
}
export
function
getTimeString
(
t
:
Date
|
number
|
string
):
string
{
const
d
=
new
Date
(
getTimeStampByDate
(
t
));
...
...
web/src/less/create-
query
-dialog.less
→
web/src/less/create-
shortcut
-dialog.less
View file @
3fa91816
@import "./mixin.less";
.create-
query
-dialog {
.create-
shortcut
-dialog {
> .dialog-container {
width: 420px;
...
...
@@ -155,7 +155,7 @@
}
@media only screen and (max-width: 875px) {
.dialog-wrapper.create-
query
-dialog {
.dialog-wrapper.create-
shortcut
-dialog {
padding: 24px 16px;
padding-top: 64px;
justify-content: unset;
...
...
web/src/less/
query
-list.less
→
web/src/less/
shortcut
-list.less
View file @
3fa91816
@import "./mixin.less";
.
querie
s-wrapper {
.
shortcut
s-wrapper {
.flex(column, flex-start, flex-start);
width: 100%;
padding: 0 8px;
...
...
@@ -35,7 +35,7 @@
}
}
> .create-
query
-btn-container {
> .create-
shortcut
-btn-container {
.flex(row, center, center);
width: 100%;
margin-top: 8px;
...
...
@@ -55,7 +55,7 @@
}
}
> .
querie
s-container {
> .
shortcut
s-container {
.flex(column, flex-start, flex-start);
position: relative;
width: 100%;
...
...
@@ -63,7 +63,7 @@
flex-wrap: nowrap;
margin-bottom: 8px;
> .
query-item
-container {
> .
shortcut
-container {
.flex(row, space-between, center);
width: 100%;
height: 40px;
...
...
@@ -86,7 +86,7 @@
&.active {
background-color: @text-green !important;
> .
query
-text-container {
> .
shortcut
-text-container {
font-weight: bold;
> * {
...
...
@@ -95,7 +95,7 @@
}
}
> .
query
-text-container {
> .
shortcut
-text-container {
.flex(row, flex-start, center);
max-width: calc(100% - 24px);
color: @text-black;
...
...
@@ -110,7 +110,7 @@
flex-shrink: 0;
}
> .
query
-text {
> .
shortcut
-text {
flex-shrink: 0;
}
}
...
...
@@ -181,7 +181,7 @@
}
@media only screen and (max-width: 875px) {
.
querie
s-container {
.
shortcut
s-container {
height: auto;
&:last-child {
...
...
@@ -192,7 +192,7 @@
font-size: 13px;
}
> .
query-item
-container {
> .
shortcut
-container {
font-size: 15px;
}
}
...
...
web/src/pages/MemoTrash.tsx
View file @
3fa91816
import
{
useCallback
,
useContext
,
useEffect
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext"
;
import
useLoading
from
"../hooks/useLoading"
;
import
{
globalStateService
,
locationService
,
memoService
,
query
Service
}
from
"../services"
;
import
{
globalStateService
,
locationService
,
memoService
,
shortcut
Service
}
from
"../services"
;
import
{
IMAGE_URL_REG
,
LINK_REG
,
MEMO_LINK_REG
,
TAG_REG
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
{
checkShouldShowMemoWithFilters
}
from
"../helpers/filter"
;
...
...
@@ -21,8 +21,8 @@ const MemoTrash: React.FC<Props> = () => {
const
loadingState
=
useLoading
();
const
[
deletedMemos
,
setDeletedMemos
]
=
useState
<
Model
.
Memo
[]
>
([]);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
filter
:
query
Id
}
=
query
;
const
queryFilter
=
queryService
.
getQueryById
(
query
Id
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcut
Id
}
=
query
;
const
queryFilter
=
shortcutService
.
getShortcutById
(
shortcut
Id
);
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
queryFilter
);
const
shownMemos
=
...
...
@@ -31,7 +31,7 @@ const MemoTrash: React.FC<Props> = () => {
let
shouldShow
=
true
;
if
(
queryFilter
)
{
const
filters
=
JSON
.
parse
(
queryFilter
.
querystring
)
as
Filter
[];
const
filters
=
JSON
.
parse
(
queryFilter
.
payload
)
as
Filter
[];
if
(
Array
.
isArray
(
filters
))
{
shouldShow
=
checkShouldShowMemoWithFilters
(
memo
,
filters
);
}
...
...
web/src/pages/Signin.tsx
View file @
3fa91816
...
...
@@ -67,16 +67,11 @@ const Signin: React.FC<Props> = () => {
try
{
signinBtnsClickLoadingState
.
setLoading
();
let
actionFunc
=
api
.
sign
in
;
let
actionFunc
=
api
.
log
in
;
if
(
action
===
"signup"
)
{
actionFunc
=
api
.
signup
;
}
const
{
succeed
,
message
}
=
await
actionFunc
(
username
,
password
);
if
(
!
succeed
&&
message
)
{
toastHelper
.
error
(
"😟 "
+
message
);
return
;
}
await
actionFunc
(
username
,
password
);
const
user
=
await
userService
.
doSignIn
();
if
(
user
)
{
...
...
@@ -106,12 +101,7 @@ const Signin: React.FC<Props> = () => {
try
{
signinBtnsClickLoadingState
.
setLoading
();
const
{
succeed
,
message
}
=
await
api
.
signin
(
"guest"
,
"123456"
);
if
(
!
succeed
&&
message
)
{
toastHelper
.
error
(
"😟 "
+
message
);
return
;
}
await
api
.
login
(
"guest"
,
"123456"
);
const
user
=
await
userService
.
doSignIn
();
if
(
user
)
{
...
...
web/src/services/index.ts
View file @
3fa91816
import
globalStateService
from
"./globalStateService"
;
import
locationService
from
"./locationService"
;
import
memoService
from
"./memoService"
;
import
queryService
from
"./query
Service"
;
import
shortcutService
from
"./shortcut
Service"
;
import
userService
from
"./userService"
;
import
resourceService
from
"./resourceService"
;
export
{
globalStateService
,
locationService
,
memoService
,
query
Service
,
userService
,
resourceService
};
export
{
globalStateService
,
locationService
,
memoService
,
shortcut
Service
,
userService
,
resourceService
};
web/src/services/locationService.ts
View file @
3fa91816
...
...
@@ -36,13 +36,13 @@ class LocationService {
duration
:
null
,
text
:
""
,
type
:
""
,
filter
:
""
,
shortcutId
:
""
,
},
};
state
.
query
.
tag
=
urlParams
.
get
(
"tag"
)
??
""
;
state
.
query
.
type
=
(
urlParams
.
get
(
"type"
)
??
""
)
as
MemoSpecType
;
state
.
query
.
text
=
urlParams
.
get
(
"text"
)
??
""
;
state
.
query
.
filter
=
urlParams
.
get
(
"filter"
)
??
""
;
state
.
query
.
shortcutId
=
urlParams
.
get
(
"filter"
)
??
""
;
const
from
=
parseInt
(
urlParams
.
get
(
"from"
)
??
"0"
);
const
to
=
parseInt
(
urlParams
.
get
(
"to"
)
??
"0"
);
if
(
to
>
from
&&
to
!==
0
)
{
...
...
@@ -71,7 +71,7 @@ class LocationService {
duration
:
null
,
text
:
""
,
type
:
""
,
filter
:
""
,
shortcutId
:
""
,
},
});
...
...
@@ -142,10 +142,10 @@ class LocationService {
updateLocationUrl
();
};
public
setMemo
Filter
=
(
filter
Id
:
string
)
=>
{
public
setMemo
Shortcut
=
(
shortcut
Id
:
string
)
=>
{
appStore
.
dispatch
({
type
:
"SET_
QUERY_FILTER
"
,
payload
:
filter
Id
,
type
:
"SET_
SHORTCUT_ID
"
,
payload
:
shortcut
Id
,
});
updateLocationUrl
();
...
...
web/src/services/memoService.ts
View file @
3fa91816
...
...
@@ -16,11 +16,10 @@ class MemoService {
return
false
;
}
const
{
data
}
=
await
api
.
getMyMemos
();
const
memos
=
[];
for
(
const
m
of
data
)
{
memos
.
push
(
m
);
}
const
data
=
await
api
.
getMyMemos
();
const
memos
:
Model
.
Memo
[]
=
data
.
map
((
m
)
=>
{
return
this
.
convertResponseModelMemo
(
m
);
});
appStore
.
dispatch
({
type
:
"SET_MEMOS"
,
payload
:
{
...
...
@@ -40,9 +39,11 @@ class MemoService {
return
false
;
}
const
{
data
}
=
await
api
.
getMyDeletedMemos
();
data
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
deletedAt
)
-
utils
.
getTimeStampByDate
(
a
.
deletedAt
));
return
data
;
const
data
=
await
api
.
getMyDeletedMemos
();
const
deletedMemos
:
Model
.
Memo
[]
=
data
.
map
((
m
)
=>
{
return
this
.
convertResponseModelMemo
(
m
);
});
return
deletedMemos
;
}
public
pushMemo
(
memo
:
Model
.
Memo
)
{
...
...
@@ -125,13 +126,21 @@ class MemoService {
}
public
async
createMemo
(
text
:
string
):
Promise
<
Model
.
Memo
>
{
const
{
data
:
memo
}
=
await
api
.
createMemo
(
text
);
return
memo
;
const
memo
=
await
api
.
createMemo
(
text
);
return
this
.
convertResponseModelMemo
(
memo
)
;
}
public
async
updateMemo
(
memoId
:
string
,
text
:
string
):
Promise
<
Model
.
Memo
>
{
const
{
data
:
memo
}
=
await
api
.
updateMemo
(
memoId
,
text
);
return
memo
;
const
memo
=
await
api
.
updateMemo
(
memoId
,
text
);
return
this
.
convertResponseModelMemo
(
memo
);
}
private
convertResponseModelMemo
(
memo
:
Model
.
Memo
):
Model
.
Memo
{
return
{
...
memo
,
createdAt
:
utils
.
getDataStringWithTs
(
memo
.
createdTs
),
updatedAt
:
utils
.
getDataStringWithTs
(
memo
.
updatedTs
),
};
}
}
...
...
web/src/services/queryService.ts
deleted
100644 → 0
View file @
4535e0ce
import
userService
from
"./userService"
;
import
api
from
"../helpers/api"
;
import
appStore
from
"../stores/appStore"
;
class
QueryService
{
public
getState
()
{
return
appStore
.
getState
().
queryState
;
}
public
async
getMyAllQueries
()
{
if
(
!
userService
.
getState
().
user
)
{
return
false
;
}
const
{
data
}
=
await
api
.
getMyQueries
();
appStore
.
dispatch
({
type
:
"SET_QUERIES"
,
payload
:
{
queries
:
data
,
},
});
return
data
;
}
public
getQueryById
(
id
:
string
)
{
for
(
const
q
of
this
.
getState
().
queries
)
{
if
(
q
.
id
===
id
)
{
return
q
;
}
}
}
public
pushQuery
(
query
:
Model
.
Query
)
{
appStore
.
dispatch
({
type
:
"INSERT_QUERY"
,
payload
:
{
query
:
{
...
query
,
},
},
});
}
public
editQuery
(
query
:
Model
.
Query
)
{
appStore
.
dispatch
({
type
:
"UPDATE_QUERY"
,
payload
:
query
,
});
}
public
async
deleteQuery
(
queryId
:
string
)
{
await
api
.
deleteQueryById
(
queryId
);
appStore
.
dispatch
({
type
:
"DELETE_QUERY_BY_ID"
,
payload
:
{
id
:
queryId
,
},
});
}
public
async
createQuery
(
title
:
string
,
querystring
:
string
)
{
const
{
data
}
=
await
api
.
createQuery
(
title
,
querystring
);
return
data
;
}
public
async
updateQuery
(
queryId
:
string
,
title
:
string
,
querystring
:
string
)
{
const
{
data
}
=
await
api
.
updateQuery
(
queryId
,
title
,
querystring
);
return
data
;
}
public
async
pinQuery
(
queryId
:
string
)
{
await
api
.
pinQuery
(
queryId
);
}
public
async
unpinQuery
(
queryId
:
string
)
{
await
api
.
unpinQuery
(
queryId
);
}
}
const
queryService
=
new
QueryService
();
export
default
queryService
;
web/src/services/resourceService.ts
View file @
3fa91816
...
...
@@ -17,7 +17,7 @@ class ResourceService {
formData
.
append
(
"file"
,
file
,
filename
);
const
{
data
}
=
await
api
.
uploadFile
(
formData
);
const
data
=
await
api
.
uploadFile
(
formData
);
return
data
;
}
...
...
web/src/services/shortcutService.ts
0 → 100644
View file @
3fa91816
import
userService
from
"./userService"
;
import
api
from
"../helpers/api"
;
import
appStore
from
"../stores/appStore"
;
import
utils
from
"../helpers/utils"
;
class
ShortcutService
{
public
getState
()
{
return
appStore
.
getState
().
shortcutState
;
}
public
async
getMyAllShortcuts
()
{
if
(
!
userService
.
getState
().
user
)
{
return
false
;
}
const
data
=
await
api
.
getMyShortcuts
();
appStore
.
dispatch
({
type
:
"SET_SHORTCUTS"
,
payload
:
{
shortcuts
:
data
.
map
((
s
)
=>
this
.
convertResponseModelShortcut
(
s
)),
},
});
return
data
;
}
public
getShortcutById
(
id
:
string
)
{
for
(
const
q
of
this
.
getState
().
shortcuts
)
{
if
(
q
.
id
===
id
)
{
return
q
;
}
}
return
null
;
}
public
pushShortcut
(
shortcut
:
Model
.
Shortcut
)
{
appStore
.
dispatch
({
type
:
"INSERT_SHORTCUT"
,
payload
:
{
shortcut
:
{
...
shortcut
,
},
},
});
}
public
editShortcut
(
shortcut
:
Model
.
Shortcut
)
{
appStore
.
dispatch
({
type
:
"UPDATE_SHORTCUT"
,
payload
:
shortcut
,
});
}
public
async
deleteShortcut
(
shortcutId
:
string
)
{
await
api
.
deleteShortcutById
(
shortcutId
);
appStore
.
dispatch
({
type
:
"DELETE_SHORTCUT_BY_ID"
,
payload
:
{
id
:
shortcutId
,
},
});
}
public
async
createShortcut
(
title
:
string
,
shortcutstring
:
string
)
{
const
data
=
await
api
.
createShortcut
(
title
,
shortcutstring
);
return
data
;
}
public
async
updateShortcut
(
shortcutId
:
string
,
title
:
string
,
shortcutstring
:
string
)
{
const
data
=
await
api
.
updateShortcut
(
shortcutId
,
title
,
shortcutstring
);
return
data
;
}
public
async
pinShortcut
(
shortcutId
:
string
)
{
await
api
.
pinShortcut
(
shortcutId
);
}
public
async
unpinShortcut
(
shortcutId
:
string
)
{
await
api
.
unpinShortcut
(
shortcutId
);
}
public
convertResponseModelShortcut
(
shortcut
:
Model
.
Shortcut
):
Model
.
Shortcut
{
return
{
...
shortcut
,
createdAt
:
utils
.
getDataStringWithTs
(
shortcut
.
createdTs
),
updatedAt
:
utils
.
getDataStringWithTs
(
shortcut
.
updatedTs
),
};
}
}
const
shortcutService
=
new
ShortcutService
();
export
default
shortcutService
;
web/src/services/userService.ts
View file @
3fa91816
import
api
from
"../helpers/api"
;
import
utils
from
"../helpers/utils"
;
import
appStore
from
"../stores/appStore"
;
class
UserService
{
...
...
@@ -7,11 +8,13 @@ class UserService {
}
public
async
doSignIn
()
{
const
{
data
:
user
}
=
await
api
.
getUserInfo
();
const
user
=
await
api
.
getUserInfo
();
if
(
user
)
{
appStore
.
dispatch
({
type
:
"SIGN_IN"
,
payload
:
{
user
},
type
:
"LOGIN"
,
payload
:
{
user
:
this
.
convertResponseModelUser
(
user
),
},
});
}
else
{
userService
.
doSignOut
();
...
...
@@ -30,18 +33,18 @@ class UserService {
}
public
async
checkUsernameUsable
(
username
:
string
):
Promise
<
boolean
>
{
const
{
data
:
isUsable
}
=
await
api
.
checkUsernameUsable
(
username
);
const
isUsable
=
await
api
.
checkUsernameUsable
(
username
);
return
isUsable
;
}
public
async
updateUsername
(
user
name
:
string
):
Promise
<
void
>
{
public
async
updateUsername
(
name
:
string
):
Promise
<
void
>
{
await
api
.
updateUserinfo
({
user
name
,
name
,
});
}
public
async
checkPasswordValid
(
password
:
string
):
Promise
<
boolean
>
{
const
{
data
:
isValid
}
=
await
api
.
checkPasswordValid
(
password
);
const
isValid
=
await
api
.
checkPasswordValid
(
password
);
return
isValid
;
}
...
...
@@ -52,13 +55,21 @@ class UserService {
}
public
async
resetOpenId
():
Promise
<
string
>
{
const
{
data
:
openId
}
=
await
api
.
resetOpenId
();
const
openId
=
await
api
.
resetOpenId
();
appStore
.
dispatch
({
type
:
"RESET_OPENID"
,
payload
:
openId
,
});
return
openId
;
}
private
convertResponseModelUser
(
user
:
Model
.
User
):
Model
.
User
{
return
{
...
user
,
createdAt
:
utils
.
getDataStringWithTs
(
user
.
createdTs
),
updatedAt
:
utils
.
getDataStringWithTs
(
user
.
updatedTs
),
};
}
}
const
userService
=
new
UserService
();
...
...
web/src/stores/appStore.ts
View file @
3fa91816
...
...
@@ -4,17 +4,17 @@ import * as globalStore from "./globalStateStore";
import
*
as
locationStore
from
"./locationStore"
;
import
*
as
memoStore
from
"./memoStore"
;
import
*
as
userStore
from
"./userStore"
;
import
*
as
queryStore
from
"./query
Store"
;
import
*
as
shortcutStore
from
"./shortcut
Store"
;
interface
AppState
{
globalState
:
globalStore
.
State
;
locationState
:
locationStore
.
State
;
memoState
:
memoStore
.
State
;
userState
:
userStore
.
State
;
queryState
:
query
Store
.
State
;
shortcutState
:
shortcut
Store
.
State
;
}
type
AppStateActions
=
globalStore
.
Actions
|
locationStore
.
Actions
|
memoStore
.
Actions
|
userStore
.
Actions
|
query
Store
.
Actions
;
type
AppStateActions
=
globalStore
.
Actions
|
locationStore
.
Actions
|
memoStore
.
Actions
|
userStore
.
Actions
|
shortcut
Store
.
Actions
;
const
appStore
=
createStore
<
AppState
,
AppStateActions
>
(
{
...
...
@@ -22,14 +22,14 @@ const appStore = createStore<AppState, AppStateActions>(
locationState
:
locationStore
.
defaultState
,
memoState
:
memoStore
.
defaultState
,
userState
:
userStore
.
defaultState
,
queryState
:
query
Store
.
defaultState
,
shortcutState
:
shortcut
Store
.
defaultState
,
},
combineReducers
<
AppState
,
AppStateActions
>
({
globalState
:
globalStore
.
reducer
,
locationState
:
locationStore
.
reducer
,
memoState
:
memoStore
.
reducer
,
userState
:
userStore
.
reducer
,
queryState
:
query
Store
.
reducer
,
shortcutState
:
shortcut
Store
.
reducer
,
})
);
...
...
web/src/stores/globalStateStore.ts
View file @
3fa91816
...
...
@@ -6,10 +6,10 @@ export interface AppSetting {
}
export
interface
State
extends
AppSetting
{
markMemoId
:
string
;
editMemoId
:
string
;
isMobileView
:
boolean
;
showSiderbarInMobileView
:
boolean
;
markMemoId
:
string
;
editMemoId
:
string
;
}
interface
SetMarkMemoIdAction
{
...
...
web/src/stores/locationStore.ts
View file @
3fa91816
export
type
State
=
AppLocation
;
interface
SetLocation
{
interface
SetLocation
Action
{
type
:
"SET_LOCATION"
;
payload
:
State
;
}
...
...
@@ -12,13 +12,13 @@ interface SetPathnameAction {
};
}
interface
SetQuery
{
interface
SetQuery
Action
{
type
:
"SET_QUERY"
;
payload
:
Query
;
}
interface
Set
QueryFilter
Action
{
type
:
"SET_
QUERY_FILTER
"
;
interface
Set
ShortcutId
Action
{
type
:
"SET_
SHORTCUT_ID
"
;
payload
:
string
;
}
...
...
@@ -58,14 +58,14 @@ interface SetHashAction {
}
export
type
Actions
=
|
SetLocation
|
SetLocation
Action
|
SetPathnameAction
|
SetQuery
|
SetQuery
Action
|
SetTagQueryAction
|
SetFromAndToQueryAction
|
SetTypeAction
|
SetTextAction
|
Set
QueryFilter
Action
|
Set
ShortcutId
Action
|
SetHashAction
;
export
function
reducer
(
state
:
State
,
action
:
Actions
)
{
...
...
@@ -156,8 +156,8 @@ export function reducer(state: State, action: Actions) {
},
};
}
case
"SET_
QUERY_FILTER
"
:
{
if
(
action
.
payload
===
state
.
query
.
filter
)
{
case
"SET_
SHORTCUT_ID
"
:
{
if
(
action
.
payload
===
state
.
query
.
shortcutId
)
{
return
state
;
}
...
...
@@ -183,6 +183,6 @@ export const defaultState: State = {
duration
:
null
,
type
:
""
,
text
:
""
,
filter
:
""
,
shortcutId
:
""
,
},
};
web/src/stores/
query
Store.ts
→
web/src/stores/
shortcut
Store.ts
View file @
3fa91816
import
utils
from
"../helpers/utils"
;
export
interface
State
{
queries
:
Model
.
Query
[];
shortcuts
:
Model
.
Shortcut
[];
}
interface
Set
Queries
{
type
:
"SET_
QUERIE
S"
;
interface
Set
ShortcutsAction
{
type
:
"SET_
SHORTCUT
S"
;
payload
:
{
queries
:
Model
.
Query
[];
shortcuts
:
Model
.
Shortcut
[];
};
}
interface
Insert
Query
Action
{
type
:
"INSERT_
QUERY
"
;
interface
Insert
Shortcut
Action
{
type
:
"INSERT_
SHORTCUT
"
;
payload
:
{
query
:
Model
.
Query
;
shortcut
:
Model
.
Shortcut
;
};
}
interface
Delete
Query
ByIdAction
{
type
:
"DELETE_
QUERY
_BY_ID"
;
interface
Delete
Shortcut
ByIdAction
{
type
:
"DELETE_
SHORTCUT
_BY_ID"
;
payload
:
{
id
:
string
;
};
}
interface
Update
Query
Action
{
type
:
"UPDATE_
QUERY
"
;
payload
:
Model
.
Query
;
interface
Update
Shortcut
Action
{
type
:
"UPDATE_
SHORTCUT
"
;
payload
:
Model
.
Shortcut
;
}
export
type
Actions
=
Set
Queries
|
InsertQueryAction
|
DeleteQueryByIdAction
|
UpdateQuery
Action
;
export
type
Actions
=
Set
ShortcutsAction
|
InsertShortcutAction
|
DeleteShortcutByIdAction
|
UpdateShortcut
Action
;
export
function
reducer
(
state
:
State
,
action
:
Actions
):
State
{
switch
(
action
.
type
)
{
case
"SET_
QUERIE
S"
:
{
const
querie
s
=
utils
.
dedupeObjectWithId
(
action
.
payload
.
querie
s
case
"SET_
SHORTCUT
S"
:
{
const
shortcut
s
=
utils
.
dedupeObjectWithId
(
action
.
payload
.
shortcut
s
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
createdAt
)
-
utils
.
getTimeStampByDate
(
a
.
createdAt
))
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
pinnedAt
??
0
)
-
utils
.
getTimeStampByDate
(
a
.
pinnedAt
??
0
))
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
updatedAt
)
-
utils
.
getTimeStampByDate
(
a
.
updatedAt
))
);
return
{
...
state
,
querie
s
,
shortcut
s
,
};
}
case
"INSERT_
QUERY
"
:
{
const
querie
s
=
utils
.
dedupeObjectWithId
(
[
action
.
payload
.
query
,
...
state
.
querie
s
].
sort
(
case
"INSERT_
SHORTCUT
"
:
{
const
shortcut
s
=
utils
.
dedupeObjectWithId
(
[
action
.
payload
.
shortcut
,
...
state
.
shortcut
s
].
sort
(
(
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
createdAt
)
-
utils
.
getTimeStampByDate
(
a
.
createdAt
)
)
);
return
{
...
state
,
querie
s
,
shortcut
s
,
};
}
case
"DELETE_
QUERY
_BY_ID"
:
{
case
"DELETE_
SHORTCUT
_BY_ID"
:
{
return
{
...
state
,
queries
:
[...
state
.
queries
].
filter
((
query
)
=>
query
.
id
!==
action
.
payload
.
id
),
shortcuts
:
[...
state
.
shortcuts
].
filter
((
shortcut
)
=>
shortcut
.
id
!==
action
.
payload
.
id
),
};
}
case
"UPDATE_
QUERY
"
:
{
const
queries
=
state
.
querie
s
.
map
((
m
)
=>
{
case
"UPDATE_
SHORTCUT
"
:
{
const
shortcuts
=
state
.
shortcut
s
.
map
((
m
)
=>
{
if
(
m
.
id
===
action
.
payload
.
id
)
{
return
{
...
m
,
...
...
@@ -78,7 +78,7 @@ export function reducer(state: State, action: Actions): State {
return
{
...
state
,
querie
s
,
shortcut
s
,
};
}
default
:
{
...
...
@@ -88,5 +88,5 @@ export function reducer(state: State, action: Actions): State {
}
export
const
defaultState
:
State
=
{
querie
s
:
[],
shortcut
s
:
[],
};
web/src/stores/userStore.ts
View file @
3fa91816
...
...
@@ -3,7 +3,7 @@ export interface State {
}
interface
SignInAction
{
type
:
"
SIGN_
IN"
;
type
:
"
LOG
IN"
;
payload
:
State
;
}
...
...
@@ -21,7 +21,7 @@ export type Actions = SignInAction | SignOutAction | ResetOpenIdAction;
export
function
reducer
(
state
:
State
,
action
:
Actions
):
State
{
switch
(
action
.
type
)
{
case
"
SIGN_
IN"
:
{
case
"
LOG
IN"
:
{
return
{
user
:
action
.
payload
.
user
,
};
...
...
web/src/types/api.d.ts
View file @
3fa91816
declare
namespace
Api
{
interface
MemosStat
{
timestamp
:
string
;
amount
:
number
;
}
}
declare
namespace
Api
{}
web/src/types/location.d.ts
View file @
3fa91816
...
...
@@ -8,7 +8,7 @@ interface Query {
duration
:
Duration
|
null
;
type
:
MemoSpecType
|
""
;
text
:
string
;
filter
:
string
;
shortcutId
:
string
;
}
type
AppRouter
=
"/"
|
"/signin"
|
"/recycle"
|
"/setting"
;
...
...
web/src/types/models.d.ts
View file @
3fa91816
declare
namespace
Model
{
interface
BaseModel
{
id
:
string
;
createdTs
:
number
;
updatedTs
:
number
;
createdAt
:
string
;
updatedAt
:
string
;
}
interface
User
extends
BaseModel
{
user
name
:
string
;
name
:
string
;
openId
:
string
;
}
interface
Memo
extends
BaseModel
{
content
:
string
;
deletedAt
:
string
;
rowStatus
:
"NORMAL"
|
"HIDDEN"
;
}
interface
Query
extends
BaseModel
{
interface
Shortcut
extends
BaseModel
{
title
:
string
;
querystring
:
string
;
pinnedAt
:
string
;
payload
:
string
;
rowStatus
:
"NORMAL"
|
"ARCHIVED"
;
}
interface
Resource
{
id
:
string
;
interface
Resource
extends
BaseModel
{
filename
:
string
;
type
:
string
;
size
:
string
;
...
...
web/vite.config.ts
View file @
3fa91816
...
...
@@ -8,11 +8,11 @@ export default defineConfig({
cors
:
true
,
proxy
:
{
"/api"
:
{
//
target: "http://localhost:8080/",
target
:
"https://memos.justsven.top/"
,
target
:
"http://localhost:8080/"
,
//
target: "https://memos.justsven.top/",
changeOrigin
:
true
,
},
"/
r
/"
:
{
"/
h
/"
:
{
target
:
"https://memos.justsven.top/"
,
changeOrigin
:
true
,
},
...
...
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