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
d1b0b0da
Unverified
Commit
d1b0b0da
authored
Aug 03, 2023
by
boojack
Committed by
GitHub
Aug 03, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: remove shortcuts in frontend (#2071)
parent
11abc454
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
16 additions
and
977 deletions
+16
-977
CreateShortcutDialog.tsx
web/src/components/CreateShortcutDialog.tsx
+0
-293
HomeSidebar.tsx
web/src/components/HomeSidebar.tsx
+0
-2
MemoFilter.tsx
web/src/components/MemoFilter.tsx
+3
-14
MemoList.tsx
web/src/components/MemoList.tsx
+4
-13
MobileHeader.tsx
web/src/components/MobileHeader.tsx
+3
-19
ShortcutList.tsx
web/src/components/ShortcutList.tsx
+0
-169
api.ts
web/src/helpers/api.ts
+0
-20
create-shortcut-dialog.less
web/src/less/create-shortcut-dialog.less
+0
-101
de.json
web/src/locales/de.json
+1
-11
en.json
web/src/locales/en.json
+0
-10
es.json
web/src/locales/es.json
+0
-10
fr.json
web/src/locales/fr.json
+0
-10
hi.json
web/src/locales/hi.json
+1
-11
hr.json
web/src/locales/hr.json
+0
-10
it.json
web/src/locales/it.json
+0
-10
ja.json
web/src/locales/ja.json
+0
-10
ko.json
web/src/locales/ko.json
+0
-10
nl.json
web/src/locales/nl.json
+0
-10
pl.json
web/src/locales/pl.json
+0
-10
pt-BR.json
web/src/locales/pt-BR.json
+1
-11
ru.json
web/src/locales/ru.json
+1
-11
sl.json
web/src/locales/sl.json
+1
-11
sv.json
web/src/locales/sv.json
+0
-10
tr.json
web/src/locales/tr.json
+0
-10
uk.json
web/src/locales/uk.json
+0
-10
vi.json
web/src/locales/vi.json
+0
-10
zh-Hans.json
web/src/locales/zh-Hans.json
+0
-10
zh-Hant.json
web/src/locales/zh-Hant.json
+1
-11
index.ts
web/src/store/index.ts
+0
-2
filter.ts
web/src/store/module/filter.ts
+0
-8
index.ts
web/src/store/module/index.ts
+0
-1
shortcut.ts
web/src/store/module/shortcut.ts
+0
-49
filter.ts
web/src/store/reducer/filter.ts
+0
-1
shortcut.ts
web/src/store/reducer/shortcut.ts
+0
-51
shortcut.d.ts
web/src/types/modules/shortcut.d.ts
+0
-28
No files found.
web/src/components/CreateShortcutDialog.tsx
deleted
100644 → 0
View file @
11abc454
import
{
useCallback
,
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
getNormalizedTimeString
}
from
"@/helpers/datetime"
;
import
{
filterConsts
,
getDefaultFilter
,
relationConsts
}
from
"@/helpers/filter"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useShortcutStore
,
useTagStore
}
from
"@/store/module"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
Selector
from
"./kit/Selector"
;
import
"@/less/create-shortcut-dialog.less"
;
interface
Props
extends
DialogProps
{
shortcutId
?:
ShortcutId
;
}
const
CreateShortcutDialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
destroy
,
shortcutId
}
=
props
;
const
shortcutStore
=
useShortcutStore
();
const
[
title
,
setTitle
]
=
useState
<
string
>
(
""
);
const
[
filters
,
setFilters
]
=
useState
<
Filter
[]
>
([]);
const
requestState
=
useLoading
(
false
);
const
t
=
useTranslate
();
useEffect
(()
=>
{
if
(
shortcutId
)
{
const
shortcutTemp
=
shortcutStore
.
getShortcutById
(
shortcutId
);
if
(
shortcutTemp
)
{
setTitle
(
shortcutTemp
.
title
);
const
temp
=
JSON
.
parse
(
shortcutTemp
.
payload
);
if
(
Array
.
isArray
(
temp
))
{
setFilters
(
temp
);
}
}
}
},
[
shortcutId
]);
const
handleTitleInputChange
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
text
=
e
.
target
.
value
as
string
;
setTitle
(
text
);
};
const
handleSaveBtnClick
=
async
()
=>
{
if
(
!
title
)
{
toast
.
error
(
t
(
"shortcut-list.title-required"
));
return
;
}
for
(
const
filter
of
filters
)
{
if
(
!
filter
.
value
.
value
)
{
toast
.
error
(
t
(
"shortcut-list.value-required"
));
return
;
}
}
try
{
if
(
shortcutId
)
{
await
shortcutStore
.
patchShortcut
({
id
:
shortcutId
,
title
,
payload
:
JSON
.
stringify
(
filters
),
});
}
else
{
await
shortcutStore
.
createShortcut
({
title
,
payload
:
JSON
.
stringify
(
filters
),
});
}
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
}
destroy
();
};
const
handleAddFilterBtnClick
=
()
=>
{
if
(
filters
.
length
>
0
)
{
const
lastFilter
=
filters
[
filters
.
length
-
1
];
if
(
lastFilter
.
value
.
value
===
""
)
{
toast
(
t
(
"shortcut-list.fill-previous"
));
return
;
}
}
setFilters
([...
filters
,
getDefaultFilter
()]);
};
const
handleFilterChange
=
useCallback
((
index
:
number
,
filter
:
Filter
)
=>
{
setFilters
((
filters
)
=>
{
const
temp
=
[...
filters
];
temp
[
index
]
=
filter
;
return
temp
;
});
},
[]);
const
handleFilterRemove
=
useCallback
((
index
:
number
)
=>
{
setFilters
((
filters
)
=>
{
const
temp
=
filters
.
filter
((
_
,
i
)
=>
i
!==
index
);
return
temp
;
});
},
[]);
return
(
<>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
{
shortcutId
?
t
(
"shortcut-list.edit-shortcut"
)
:
t
(
"shortcut-list.create-shortcut"
)
}
</
p
>
<
button
className=
"btn close-btn"
onClick=
{
destroy
}
>
<
Icon
.
X
/>
</
button
>
</
div
>
<
div
className=
"dialog-content-container"
>
<
div
className=
"form-item-container input-form-container"
>
<
span
className=
"normal-text"
>
{
t
(
"common.title"
)
}
</
span
>
<
input
className=
"title-input"
type=
"text"
placeholder=
{
t
(
"shortcut-list.shortcut-title"
)
}
value=
{
title
}
onChange=
{
handleTitleInputChange
}
/>
</
div
>
<
div
className=
"form-item-container filter-form-container"
>
<
span
className=
"normal-text"
>
{
t
(
"common.filter"
)
}
</
span
>
<
div
className=
"filters-wrapper"
>
{
filters
.
map
((
f
,
index
)
=>
{
return
(
<
MemoFilterInputer
key=
{
index
}
index=
{
index
}
filter=
{
f
}
handleFilterChange=
{
handleFilterChange
}
handleFilterRemove=
{
handleFilterRemove
}
/>
);
})
}
<
div
className=
"create-filter-btn"
onClick=
{
handleAddFilterBtnClick
}
>
{
t
(
"filter.new-filter"
)
}
</
div
>
</
div
>
</
div
>
</
div
>
<
div
className=
"dialog-footer-container"
>
<
div
></
div
>
<
div
className=
"btns-container"
>
<
button
className=
{
`btn-primary ${requestState.isLoading ? "requesting" : ""}`
}
onClick=
{
handleSaveBtnClick
}
>
{
t
(
"common.save"
)
}
</
button
>
</
div
>
</
div
>
</>
);
};
interface
MemoFilterInputerProps
{
index
:
number
;
filter
:
Filter
;
handleFilterChange
:
(
index
:
number
,
filter
:
Filter
)
=>
void
;
handleFilterRemove
:
(
index
:
number
)
=>
void
;
}
const
MemoFilterInputer
:
React
.
FC
<
MemoFilterInputerProps
>
=
(
props
:
MemoFilterInputerProps
)
=>
{
const
{
index
,
filter
,
handleFilterChange
,
handleFilterRemove
}
=
props
;
const
t
=
useTranslate
();
const
tagStore
=
useTagStore
();
const
[
value
,
setValue
]
=
useState
<
string
>
(
filter
.
value
.
value
);
const
tags
=
Array
.
from
(
tagStore
.
getState
().
tags
);
const
{
type
}
=
filter
;
const
typeDataSource
=
Object
.
values
(
filterConsts
).
map
(({
text
,
value
})
=>
({
text
:
t
(
text
),
value
}));
const
operatorDataSource
=
Object
.
values
(
filterConsts
[
type
as
FilterType
].
operators
).
map
(({
text
,
value
})
=>
({
text
:
t
(
text
),
value
}));
const
relationDataSource
=
Object
.
values
(
relationConsts
).
map
(({
text
,
value
})
=>
({
text
:
t
(
text
),
value
}));
const
valueDataSource
=
type
===
"TYPE"
?
filterConsts
[
"TYPE"
].
values
.
map
(({
text
,
value
})
=>
({
text
:
t
(
text
),
value
}))
:
type
===
"VISIBILITY"
?
filterConsts
[
"VISIBILITY"
].
values
.
map
(({
text
,
value
})
=>
({
text
:
t
(
text
),
value
}))
:
tags
.
sort
().
map
((
t
)
=>
{
return
{
text
:
t
,
value
:
t
};
});
const
maxDatetimeValue
=
getNormalizedTimeString
(
"9999-12-31T23:59"
);
useEffect
(()
=>
{
if
(
type
===
"DISPLAY_TIME"
)
{
const
nowDatetimeValue
=
getNormalizedTimeString
();
handleValueChange
(
nowDatetimeValue
);
}
else
{
setValue
(
filter
.
value
.
value
);
}
},
[
type
]);
const
handleRelationChange
=
(
value
:
string
)
=>
{
if
([
"AND"
,
"OR"
].
includes
(
value
))
{
handleFilterChange
(
index
,
{
...
filter
,
relation
:
value
as
MemoFilterRelation
,
});
}
};
const
handleTypeChange
=
(
value
:
string
)
=>
{
if
(
filter
.
type
!==
value
)
{
const
ops
=
Object
.
values
(
filterConsts
[
value
as
FilterType
].
operators
);
handleFilterChange
(
index
,
{
...
filter
,
type
:
value
as
FilterType
,
value
:
{
operator
:
ops
[
0
].
value
,
value
:
""
,
},
});
}
};
const
handleOperatorChange
=
(
value
:
string
)
=>
{
handleFilterChange
(
index
,
{
...
filter
,
value
:
{
...
filter
.
value
,
operator
:
value
,
},
});
};
const
handleValueChange
=
(
value
:
string
)
=>
{
setValue
(
value
);
handleFilterChange
(
index
,
{
...
filter
,
value
:
{
...
filter
.
value
,
value
,
},
});
};
const
handleRemoveBtnClick
=
()
=>
{
handleFilterRemove
(
index
);
};
return
(
<
div
className=
"memo-filter-input-wrapper"
>
{
index
>
0
?
(
<
Selector
className=
"relation-selector"
dataSource=
{
relationDataSource
}
value=
{
filter
.
relation
}
handleValueChanged=
{
handleRelationChange
}
/>
)
:
null
}
<
Selector
className=
"type-selector"
dataSource=
{
typeDataSource
}
value=
{
filter
.
type
}
handleValueChanged=
{
handleTypeChange
}
/>
<
Selector
className=
"operator-selector"
dataSource=
{
operatorDataSource
}
value=
{
filter
.
value
.
operator
}
handleValueChanged=
{
handleOperatorChange
}
/>
{
type
===
"TEXT"
?
(
<
input
type=
"text"
className=
"value-inputer"
value=
{
value
}
onChange=
{
(
event
)
=>
{
handleValueChange
(
event
.
target
.
value
);
}
}
placeholder=
{
t
(
"filter.text-placeholder"
)
}
/>
)
:
type
===
"DISPLAY_TIME"
?
(
<
input
className=
"datetime-selector"
type=
"datetime-local"
value=
{
value
}
max=
{
maxDatetimeValue
}
onChange=
{
(
event
)
=>
{
handleValueChange
(
event
.
target
.
value
);
}
}
/>
)
:
(
<
Selector
className=
"value-selector"
dataSource=
{
valueDataSource
}
value=
{
value
}
handleValueChanged=
{
handleValueChange
}
/>
)
}
<
Icon
.
X
className=
"remove-btn"
onClick=
{
handleRemoveBtnClick
}
/>
</
div
>
);
};
export
default
function
showCreateShortcutDialog
(
shortcutId
?:
ShortcutId
):
void
{
generateDialog
(
{
className
:
"create-shortcut-dialog"
,
dialogName
:
"create-shortcut-dialog"
,
},
CreateShortcutDialog
,
{
shortcutId
}
);
}
web/src/components/HomeSidebar.tsx
View file @
d1b0b0da
import
{
useLayoutStore
,
useUserStore
}
from
"../store/module"
;
import
SearchBar
from
"./SearchBar"
;
import
ShortcutList
from
"./ShortcutList"
;
import
TagList
from
"./TagList"
;
import
UsageHeatMap
from
"./UsageHeatMap"
;
...
...
@@ -32,7 +31,6 @@ const HomeSidebar = () => {
<
UsageHeatMap
/>
{
!
userStore
.
isVisitorMode
()
&&
(
<>
<
ShortcutList
/>
<
TagList
/>
</>
)
}
...
...
web/src/components/MemoFilter.tsx
View file @
d1b0b0da
...
...
@@ -2,7 +2,7 @@ import { useEffect } from "react";
import
{
useLocation
}
from
"react-router-dom"
;
import
{
getDateString
}
from
"@/helpers/datetime"
;
import
{
getTextWithMemoType
}
from
"@/helpers/filter"
;
import
{
useFilterStore
,
useShortcutStore
}
from
"@/store/module"
;
import
{
useFilterStore
}
from
"@/store/module"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
import
"@/less/memo-filter.less"
;
...
...
@@ -11,11 +11,9 @@ const MemoFilter = () => {
const
t
=
useTranslate
();
const
location
=
useLocation
();
const
filterStore
=
useFilterStore
();
const
shortcutStore
=
useShortcutStore
();
const
filter
=
filterStore
.
state
;
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
,
visibility
}
=
filter
;
const
shortcut
=
shortcutId
?
shortcutStore
.
getShortcutById
(
shortcutId
)
:
null
;
const
showFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
shortcut
||
visibility
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
visibility
}
=
filter
;
const
showFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
visibility
);
useEffect
(()
=
>
{
filterStore
.
clearFilter
();
...
...
@@ -24,15 +22,6 @@ const MemoFilter = () => {
return (
<
div
className=
{
`filter-query-container ${showFilter ? "" : "!hidden"}`
}
>
<
span
className=
"mx-2 text-gray-400"
>
{
t
(
"common.filter"
)
}
:
</
span
>
<
div
className=
{
"filter-item-container "
+
(
shortcut
?
""
:
"!hidden"
)
}
onClick=
{
()
=>
{
filterStore
.
setMemoShortcut
(
undefined
);
}
}
>
<
Icon
.
Target
className=
"icon-text"
/>
{
shortcut
?.
title
}
<
Icon
.
X
className=
"w-4 h-auto ml-1 opacity-40"
/>
</
div
>
<
div
className=
{
"filter-item-container "
+
(
tagQuery
?
""
:
"!hidden"
)
}
onClick=
{
()
=>
{
...
...
web/src/components/MemoList.tsx
View file @
d1b0b0da
...
...
@@ -2,9 +2,8 @@ import { useEffect, useRef, useState } from "react";
import
{
toast
}
from
"react-hot-toast"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
getTimeStampByDate
}
from
"@/helpers/datetime"
;
import
{
checkShouldShowMemoWithFilters
}
from
"@/helpers/filter"
;
import
{
LINK_REG
,
PLAIN_LINK_REG
,
TAG_REG
}
from
"@/labs/marked/parser"
;
import
{
useFilterStore
,
useMemoStore
,
use
ShortcutStore
,
use
UserStore
}
from
"@/store/module"
;
import
{
useFilterStore
,
useMemoStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Empty
from
"./Empty"
;
import
Memo
from
"./Memo"
;
...
...
@@ -19,28 +18,20 @@ const MemoList: React.FC<Props> = (props: Props) => {
const
t
=
useTranslate
();
const
memoStore
=
useMemoStore
();
const
userStore
=
useUserStore
();
const
shortcutStore
=
useShortcutStore
();
const
filterStore
=
useFilterStore
();
const
filter
=
filterStore
.
state
;
const
{
memos
,
isFetching
}
=
memoStore
.
state
;
const
[
isComplete
,
setIsComplete
]
=
useState
<
boolean
>
(
false
);
const
currentUsername
=
userStore
.
getCurrentUsername
();
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
,
visibility
}
=
filter
;
const
shortcut
=
shortcutId
?
shortcutStore
.
getShortcutById
(
shortcutId
)
:
null
;
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
shortcut
||
visibility
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
visibility
}
=
filter
;
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
visibility
);
const
shownMemos
=
(
showMemoFilter
||
shortcut
showMemoFilter
?
memos
.
filter
((
memo
)
=
>
{
let
shouldShow
=
true
;
if
(
shortcut
)
{
const
filters
=
JSON
.
parse
(
shortcut
.
payload
)
as
Filter
[];
if
(
Array
.
isArray
(
filters
))
{
shouldShow
=
checkShouldShowMemoWithFilters
(
memo
,
filters
);
}
}
if
(
tagQuery
)
{
const
tagsSet
=
new
Set
<
string
>
();
for
(
const
t
of
Array
.
from
(
memo
.
content
.
match
(
new
RegExp
(
TAG_REG
,
"gu"
))
??
[]))
{
...
...
web/src/components/MobileHeader.tsx
View file @
d1b0b0da
import
{
use
Effect
,
use
State
}
from
"react"
;
import
{
use
FilterStore
,
useLayoutStore
,
useShortc
utStore
}
from
"@/store/module"
;
import
{
useState
}
from
"react"
;
import
{
use
Layo
utStore
}
from
"@/store/module"
;
import
Icon
from
"./Icon"
;
interface
Props
{
...
...
@@ -8,24 +8,8 @@ interface Props {
const
MobileHeader
=
(
props
:
Props
)
=>
{
const
{
showSearch
=
true
}
=
props
;
const
filterStore
=
useFilterStore
();
const
shortcutStore
=
useShortcutStore
();
const
layoutStore
=
useLayoutStore
();
const
filter
=
filterStore
.
state
;
const
shortcuts
=
shortcutStore
.
state
.
shortcuts
;
const
[
titleText
,
setTitleText
]
=
useState
(
"MEMOS"
);
useEffect
(()
=>
{
if
(
!
filter
.
shortcutId
)
{
setTitleText
(
"MEMOS"
);
return
;
}
const
shortcut
=
shortcutStore
.
getShortcutById
(
filter
.
shortcutId
);
if
(
shortcut
)
{
setTitleText
(
shortcut
.
title
);
}
},
[
filter
,
shortcuts
]);
const
[
titleText
]
=
useState
(
"MEMOS"
);
return
(
<
div
className=
"sticky top-0 pt-4 sm:pt-1 pb-1 mb-1 backdrop-blur bg-zinc-100 dark:bg-zinc-800 bg-opacity-70 flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-2"
>
...
...
web/src/components/ShortcutList.tsx
deleted
100644 → 0
View file @
11abc454
import
{
useEffect
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
getTimeStampByDate
}
from
"@/helpers/datetime"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useToggle
from
"@/hooks/useToggle"
;
import
{
useFilterStore
,
useShortcutStore
}
from
"@/store/module"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showCreateShortcutDialog
from
"./CreateShortcutDialog"
;
import
Icon
from
"./Icon"
;
const
ShortcutList
=
()
=>
{
const
t
=
useTranslate
();
const
filterStore
=
useFilterStore
();
const
shortcutStore
=
useShortcutStore
();
const
filter
=
filterStore
.
state
;
const
shortcuts
=
shortcutStore
.
state
.
shortcuts
;
const
loadingState
=
useLoading
();
const
pinnedShortcuts
=
shortcuts
.
filter
((
s
)
=>
s
.
rowStatus
===
"ARCHIVED"
)
.
sort
((
a
,
b
)
=>
getTimeStampByDate
(
b
.
createdTs
)
-
getTimeStampByDate
(
a
.
createdTs
));
const
unpinnedShortcuts
=
shortcuts
.
filter
((
s
)
=>
s
.
rowStatus
===
"NORMAL"
)
.
sort
((
a
,
b
)
=>
getTimeStampByDate
(
b
.
createdTs
)
-
getTimeStampByDate
(
a
.
createdTs
));
const
sortedShortcuts
=
pinnedShortcuts
.
concat
(
unpinnedShortcuts
);
useEffect
(()
=>
{
shortcutStore
.
getMyAllShortcuts
()
.
catch
(()
=>
{
// do nth
})
.
finally
(()
=>
{
loadingState
.
setFinish
();
});
},
[]);
return
(
<
div
className=
"flex flex-col justify-start items-start w-full mt-2 h-auto shrink-0 flex-nowrap hide-scrollbar"
>
<
div
className=
"flex flex-row justify-start items-center w-full px-4"
>
<
span
className=
"text-sm leading-6 font-mono text-gray-400"
>
{
t
(
"common.shortcuts"
)
}
</
span
>
<
button
className=
"flex flex-col justify-center items-center w-5 h-5 bg-gray-200 dark:bg-zinc-700 rounded ml-2 hover:shadow"
onClick=
{
()
=>
showCreateShortcutDialog
()
}
>
<
Icon
.
Plus
className=
"w-4 h-4 text-gray-400"
/>
</
button
>
</
div
>
<
div
className=
"flex flex-col justify-start items-start relative w-full h-auto flex-nowrap mb-2"
>
{
sortedShortcuts
.
map
((
s
)
=>
{
return
<
ShortcutContainer
key=
{
s
.
id
}
shortcut=
{
s
}
isActive=
{
s
.
id
===
Number
(
filter
?.
shortcutId
)
}
/>;
})
}
</
div
>
</
div
>
);
};
interface
ShortcutContainerProps
{
shortcut
:
Shortcut
;
isActive
:
boolean
;
}
const
ShortcutContainer
:
React
.
FC
<
ShortcutContainerProps
>
=
(
props
:
ShortcutContainerProps
)
=>
{
const
{
shortcut
,
isActive
}
=
props
;
const
t
=
useTranslate
();
const
filterStore
=
useFilterStore
();
const
shortcutStore
=
useShortcutStore
();
const
[
showConfirmDeleteBtn
,
toggleConfirmDeleteBtn
]
=
useToggle
(
false
);
const
handleShortcutClick
=
()
=>
{
if
(
isActive
)
{
filterStore
.
setMemoShortcut
(
undefined
);
}
else
{
filterStore
.
setMemoShortcut
(
shortcut
.
id
);
}
};
const
handleDeleteMemoClick
=
async
(
event
:
React
.
MouseEvent
)
=>
{
event
.
stopPropagation
();
if
(
showConfirmDeleteBtn
)
{
try
{
await
shortcutStore
.
deleteShortcutById
(
shortcut
.
id
);
if
(
filterStore
.
getState
().
shortcutId
===
shortcut
.
id
)
{
// need clear shortcut filter
filterStore
.
setMemoShortcut
(
undefined
);
}
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
}
}
else
{
toggleConfirmDeleteBtn
();
}
};
const
handleEditShortcutBtnClick
=
(
event
:
React
.
MouseEvent
)
=>
{
event
.
stopPropagation
();
showCreateShortcutDialog
(
shortcut
.
id
);
};
const
handlePinShortcutBtnClick
=
async
(
event
:
React
.
MouseEvent
)
=>
{
event
.
stopPropagation
();
try
{
const
shortcutPatch
:
ShortcutPatch
=
{
id
:
shortcut
.
id
,
rowStatus
:
shortcut
.
rowStatus
===
"ARCHIVED"
?
"NORMAL"
:
"ARCHIVED"
,
};
await
shortcutStore
.
patchShortcut
(
shortcutPatch
);
}
catch
(
error
)
{
// do nth
}
};
const
handleDeleteBtnMouseLeave
=
()
=>
{
toggleConfirmDeleteBtn
(
false
);
};
return
(
<>
<
div
className=
"relative group flex flex-row justify-between items-center w-full h-10 py-0 px-4 mt-px first:mt-2 rounded-lg text-base cursor-pointer select-none shrink-0 hover:bg-white dark:hover:bg-zinc-700"
onClick=
{
handleShortcutClick
}
>
<
div
className=
{
`flex flex-row justify-start items-center truncate shrink leading-5 mr-1 text-black dark:text-gray-200 ${
isActive && "text-green-600"
}`
}
>
<
span
className=
"truncate"
>
{
shortcut
.
title
}
</
span
>
</
div
>
<
div
className=
"flex-row justify-end items-center hidden group/btns group-hover:flex shrink-0"
>
<
span
className=
"flex flex-row justify-center items-center toggle-btn"
>
<
Icon
.
MoreHorizontal
className=
"w-4 h-auto"
/>
</
span
>
<
div
className=
"absolute top-4 right-0 flex-col justify-start items-start w-auto h-auto px-4 pt-3 hidden group-hover/btns:flex z-1"
>
<
div
className=
"flex flex-col justify-start items-start w-32 h-auto p-1 whitespace-nowrap rounded-md bg-white dark:bg-zinc-700 shadow"
>
<
span
className=
"w-full text-sm leading-6 py-1 px-3 rounded text-left dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-zinc-800"
onClick=
{
handlePinShortcutBtnClick
}
>
{
shortcut
.
rowStatus
===
"ARCHIVED"
?
t
(
"common.unpin"
)
:
t
(
"common.pin"
)
}
</
span
>
<
span
className=
"w-full text-sm leading-6 py-1 px-3 rounded text-left dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-zinc-800"
onClick=
{
handleEditShortcutBtnClick
}
>
{
t
(
"common.edit"
)
}
</
span
>
<
span
className=
{
`w-full text-sm leading-6 py-1 px-3 rounded text-left dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-zinc-800 text-orange-600 ${
showConfirmDeleteBtn && "font-black"
}`
}
onClick=
{
handleDeleteMemoClick
}
onMouseLeave=
{
handleDeleteBtnMouseLeave
}
>
{
t
(
"common.delete"
)
}
{
showConfirmDeleteBtn
?
"!"
:
""
}
</
span
>
</
div
>
</
div
>
</
div
>
</
div
>
</>
);
};
export
default
ShortcutList
;
web/src/helpers/api.ts
View file @
d1b0b0da
...
...
@@ -142,26 +142,6 @@ export function checkOpenAIEnabled() {
return
axios
.
get
<
boolean
>
(
`/api/openai/enabled`
);
}
export
function
getShortcutList
(
shortcutFind
?:
ShortcutFind
)
{
const
queryList
=
[];
if
(
shortcutFind
?.
creatorUsername
)
{
queryList
.
push
(
`creatorUsername=
${
shortcutFind
.
creatorUsername
}
`
);
}
return
axios
.
get
<
Shortcut
[]
>
(
`/api/v1/shortcut?
${
queryList
.
join
(
"&"
)}
`
);
}
export
function
createShortcut
(
shortcutCreate
:
ShortcutCreate
)
{
return
axios
.
post
<
Shortcut
>
(
"/api/v1/shortcut"
,
shortcutCreate
);
}
export
function
patchShortcut
(
shortcutPatch
:
ShortcutPatch
)
{
return
axios
.
patch
<
Shortcut
>
(
`/api/v1/shortcut/
${
shortcutPatch
.
id
}
`
,
shortcutPatch
);
}
export
function
deleteShortcutById
(
shortcutId
:
ShortcutId
)
{
return
axios
.
delete
(
`/api/v1/shortcut/
${
shortcutId
}
`
);
}
export
function
getResourceList
()
{
return
axios
.
get
<
Resource
[]
>
(
"/api/v1/resource"
);
}
...
...
web/src/less/create-shortcut-dialog.less
deleted
100644 → 0
View file @
11abc454
.create-shortcut-dialog {
@apply px-4;
> .dialog-container {
@apply w-180 max-w-full;
> .dialog-content-container {
@apply flex flex-col justify-start items-start;
> .form-item-container {
@apply w-full mt-2 py-1 flex sm:flex-row flex-col justify-start items-start;
> .normal-text {
@apply block shrink-0 w-12 mr-8 sm:text-right text-left text-sm leading-8;
color: gray;
}
> .title-input {
@apply w-full py-1 px-2 h-9 text-sm rounded border dark:border-zinc-700 dark:bg-zinc-800 shadow-inner;
}
> .filters-wrapper {
@apply w-full flex flex-col justify-start items-start;
> .create-filter-btn {
@apply text-sm py-1 px-2 rounded shadow flex flex-row sm:justify-start justify-center items-center border dark:border-zinc-700 cursor-pointer text-blue-500 hover:opacity-80 sm:min-w-0 min-w-full sm:mb-0 mb-1;
}
}
}
}
> .dialog-footer-container {
@apply w-full mt-0 flex flex-row justify-between items-center;
> .btns-container {
@apply flex flex-row justify-start items-center;
> .tip-text {
@apply text-sm text-gray-400 mr-2;
}
> .btn {
@apply text-base px-4 py-1 leading-7 rounded shadow hover:opacity-80;
&.save-btn {
@apply bg-green-600 text-white;
&.requesting {
@apply cursor-wait opacity-80;
}
}
}
}
}
}
}
.memo-filter-input-wrapper {
@apply w-full mb-3 shrink-0 flex flex-row sm:justify-start justify-center items-center sm:flex-nowrap flex-wrap sm:gap-0 gap-3;
> .selector-wrapper {
@apply mr-1 h-9 grow-0 shrink-0 sm:min-w-0 min-w-full;
&.relation-selector {
@apply w-16;
@media only screen and (min-width: 640px) {
margin-left: -68px;
}
}
&.type-selector {
@apply w-1/4;
}
&.operator-selector {
@apply w-1/5;
}
&.value-selector {
@apply grow;
}
}
> input.value-inputer {
@media only screen and (min-width: 640px) {
max-width: calc(100% - 152px);
}
@apply h-9 px-2 shrink-0 grow mr-1 text-sm rounded border bg-transparent hover:bg-gray-50 sm:min-w-0 min-w-full;
}
> input.datetime-selector {
@media only screen and (min-width: 640px) {
max-width: calc(100% - 152px);
}
@apply h-9 px-2 shrink-0 grow mr-1 text-sm rounded border bg-transparent sm:min-w-0 min-w-full;
}
> .remove-btn {
@apply w-4 h-auto ml-1 cursor-pointer opacity-60 hover:opacity-80;
}
}
web/src/locales/de.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Abmelden"
,
"back-to-home"
:
"Zurück zur Startseite"
,
"type"
:
"Typ"
,
"shortcuts"
:
"Verknüpfungen"
,
"title"
:
"Titel"
,
"filter"
:
"Filter"
,
"tags"
:
"Tags"
,
...
...
@@ -97,7 +96,7 @@
"memo"
:
{
"view-detail"
:
"Details anzeigen"
,
"copy"
:
"Kopieren"
,
"copy-link"
:
"Link Kopieren"
,
"copy-link"
:
"Link Kopieren"
,
"visibility"
:
{
"private"
:
"Nur für dich sichtbar"
,
"protected"
:
"Für Mitglieder sichtbar"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"Lade Daten..."
,
"fetch-more"
:
"Klicke hier, um mehr zu laden"
},
"shortcut-list"
:
{
"shortcut-title"
:
"Titel der Verknüpfung"
,
"create-shortcut"
:
"Verknüpfung erstellen"
,
"edit-shortcut"
:
"Verknüpfung bearbeiten"
,
"fill-previous"
:
"Bitte vorherigen Filterwert ausfüllen"
,
"title-required"
:
"Titel wird benötigt"
,
"value-required"
:
"Filterwert wird benötigt"
,
"eligible-memo"
:
"eligible memo"
},
"filter"
:
{
"new-filter"
:
"Neuer Filter"
,
"type"
:
{
...
...
web/src/locales/en.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"Sign up"
,
"sign-out"
:
"Sign out"
,
"type"
:
"Type"
,
"shortcuts"
:
"Shortcuts"
,
"title"
:
"Title"
,
"filter"
:
"Filter"
,
"filter-period"
:
"{{from}} to {{to}}"
,
...
...
@@ -148,15 +147,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"shortcut title"
,
"create-shortcut"
:
"Create Shortcut"
,
"edit-shortcut"
:
"Edit Shortcut"
,
"eligible-memo"
:
"eligible memo"
,
"fill-previous"
:
"Please fill in previous filter value"
,
"title-required"
:
"Title is required"
,
"value-required"
:
"Filter value is required"
},
"tag-list"
:
{
"tip-text"
:
"Input `#tag` to create"
,
"create-tag"
:
"Create Tag"
,
...
...
web/src/locales/es.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Cerrar sesión"
,
"back-to-home"
:
"Volver al Inicio"
,
"type"
:
"Tipo"
,
"shortcuts"
:
"Atajos"
,
"title"
:
"Título"
,
"filter"
:
"Filtros"
,
"tags"
:
"Etiquetas"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"obteniendo datos..."
,
"fetch-more"
:
"Click aqui para obtener más información"
},
"shortcut-list"
:
{
"shortcut-title"
:
"título del atajo"
,
"create-shortcut"
:
"Crear Atajo"
,
"edit-shortcut"
:
"Editar Atajo"
,
"eligible-memo"
:
"nota elegible"
,
"fill-previous"
:
"Introduce el valor del filtro anterior"
,
"title-required"
:
"El título es obligatorio"
,
"value-required"
:
"El valor del filtro es obligatorio"
},
"filter"
:
{
"new-filter"
:
"Nuevo Filtro"
,
"type"
:
{
...
...
web/src/locales/fr.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Se déconnecter"
,
"back-to-home"
:
"Retour à l'accueil"
,
"type"
:
"Type"
,
"shortcuts"
:
"Raccourcis"
,
"title"
:
"Titre"
,
"filter"
:
"Filtre"
,
"tags"
:
"Étiquettes"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"récupération des données..."
,
"fetch-more"
:
"Cliquez ici pour en savoir plus"
},
"shortcut-list"
:
{
"shortcut-title"
:
"titre du raccourci"
,
"create-shortcut"
:
"Créer un raccourci"
,
"edit-shortcut"
:
"Editer un raccourci"
,
"eligible-memo"
:
"mémo admissible"
,
"fill-previous"
:
"Veuillez remplir la valeur du filtre précédent"
,
"title-required"
:
"Le titre est requis"
,
"value-required"
:
"La valeur du filtre est requise"
},
"filter"
:
{
"new-filter"
:
"Nouveau filtre"
,
"type"
:
{
...
...
web/src/locales/hi.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"साइन अप करें"
,
"sign-out"
:
"साइन आउट करें"
,
"type"
:
"प्रकार"
,
"shortcuts"
:
"शॉर्टकट"
,
"title"
:
"शीर्षक"
,
"filter"
:
"फ़िल्टर"
,
"filter-period"
:
"{{from}} से {{to}} तक"
,
...
...
@@ -148,15 +147,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"शॉर्टकट शीर्षक"
,
"create-shortcut"
:
"शॉर्टकट बनाएँ"
,
"edit-shortcut"
:
"शॉर्टकट संपादित करें"
,
"eligible-memo"
:
"उपयुक्त मेमो"
,
"fill-previous"
:
"कृपया पिछले फ़िल्टर मान को भरें"
,
"title-required"
:
"शीर्षक आवश्यक है"
,
"value-required"
:
"फ़िल्टर मान आवश्यक है"
},
"tag-list"
:
{
"tip-text"
:
"बनाने के लिए `#tag` इनपुट करें"
,
"create-tag"
:
"टैग बनाएँ"
,
...
...
@@ -428,4 +418,4 @@
"powered-by"
:
"द्वारा संचालित"
,
"other-projects"
:
"अन्य प्रोजेक्ट्स"
}
}
\ No newline at end of file
}
web/src/locales/hr.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"Registriraj se"
,
"sign-out"
:
"Odjavi se"
,
"type"
:
"Tip"
,
"shortcuts"
:
"Prečaci"
,
"title"
:
"Naslov"
,
"filter"
:
"Filtriraj"
,
"filter-period"
:
"{{from}} do {{to}}"
,
...
...
@@ -148,15 +147,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"ime prečaca"
,
"create-shortcut"
:
"Stvori prečac"
,
"edit-shortcut"
:
"Uredi prečac"
,
"eligible-memo"
:
"eligible memo"
,
"fill-previous"
:
"Please fill in previous filter value"
,
"title-required"
:
"Naslov je obavezan"
,
"value-required"
:
"Filter value je tražena"
},
"tag-list"
:
{
"tip-text"
:
"Unesi `#tag` kako bi stvorio"
,
"create-tag"
:
"Stvori Tag"
,
...
...
web/src/locales/it.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Esci"
,
"back-to-home"
:
"Ritorna alla Home"
,
"type"
:
"Tipo"
,
"shortcuts"
:
"Scorciatoie"
,
"title"
:
"Titolo"
,
"filter"
:
"Filtro"
,
"tags"
:
"Etichette"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"recupero i dati..."
,
"fetch-more"
:
"Clicca per caricare più dati"
},
"shortcut-list"
:
{
"shortcut-title"
:
"titolo Scorciatoia"
,
"create-shortcut"
:
"Crea Scorciatoia"
,
"edit-shortcut"
:
"Modifica Scorciatoia"
,
"eligible-memo"
:
"eligible memo"
,
"fill-previous"
:
"Compila il valore del filtro precedente"
,
"title-required"
:
"Il titolo è obbligatorio"
,
"value-required"
:
"Il valore del filtro è obbligatorio"
},
"filter"
:
{
"new-filter"
:
"Nuovo Filtro"
,
"type"
:
{
...
...
web/src/locales/ja.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"登録"
,
"sign-out"
:
"ログアウト"
,
"type"
:
"タイプ"
,
"shortcuts"
:
"ショートカット"
,
"title"
:
"タイトル"
,
"filter"
:
"フィルター"
,
"filter-period"
:
"{{from}}から{{to}}"
,
...
...
@@ -145,15 +144,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"ショートカットの名前"
,
"create-shortcut"
:
"ショートカットを作成"
,
"edit-shortcut"
:
"ショートカットを編集"
,
"eligible-memo"
:
"的確なメモ"
,
"fill-previous"
:
"前回のフィルターの値を入力してください。"
,
"title-required"
:
"タイトルは必須です"
,
"value-required"
:
"フィルターの値は必須です。"
},
"tag-list"
:
{
"tip-text"
:
"作成するには`#tag`のように入力してください"
,
"create-tag"
:
"タグを作成する"
,
...
...
web/src/locales/ko.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"회원등록"
,
"sign-out"
:
"로그아웃"
,
"type"
:
"타입"
,
"shortcuts"
:
"바로가기"
,
"title"
:
"제목"
,
"filter"
:
"필터"
,
"filter-period"
:
"{{from}} 부터 {{to}}"
,
...
...
@@ -145,15 +144,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"바로가기 이름"
,
"create-shortcut"
:
"바로가기 생성"
,
"edit-shortcut"
:
"바로가기 변경"
,
"eligible-memo"
:
"해당하는 메모"
,
"fill-previous"
:
"위의 필터 값을 채워주세요"
,
"title-required"
:
"제목이 있어야 합니다"
,
"value-required"
:
"필터 값이 있어야 합니다"
},
"tag-list"
:
{
"tip-text"
:
"`#태그명`을 입력하세요"
,
"create-tag"
:
"태그 생성"
,
...
...
web/src/locales/nl.json
View file @
d1b0b0da
...
...
@@ -32,7 +32,6 @@
"sign-out"
:
"Uitloggen"
,
"back-to-home"
:
"Terug naar homepagina"
,
"type"
:
"Type"
,
"shortcuts"
:
"Snelkoppelingen"
,
"title"
:
"Titel"
,
"filter"
:
"Filter"
,
"tags"
:
"Labels"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"data aan het ophalen..."
,
"fetch-more"
:
"Klik hier om meer op te halen"
},
"shortcut-list"
:
{
"shortcut-title"
:
"snelkoppelingstitel"
,
"create-shortcut"
:
"Maak Snelkoppeling"
,
"edit-shortcut"
:
"Wijzig Shortcut"
,
"eligible-memo"
:
"geschikte memo"
,
"fill-previous"
:
"Vul alsjeblieft het vorige filter in"
,
"title-required"
:
"Titel is verplicht"
,
"value-required"
:
"Filter is verplicht"
},
"filter"
:
{
"new-filter"
:
"Nieuw Filter"
,
"type"
:
{
...
...
web/src/locales/pl.json
View file @
d1b0b0da
...
...
@@ -35,7 +35,6 @@
"sign-out"
:
"Wyloguj"
,
"back-to-home"
:
"Powrót do Strony Głównej"
,
"type"
:
"Typ"
,
"shortcuts"
:
"Skróty"
,
"title"
:
"Tytuł"
,
"filter"
:
"Filtruj"
,
"tags"
:
"Tagi"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"pobieranie danych..."
,
"fetch-more"
:
"Kliknij, aby pobrać więcej"
},
"shortcut-list"
:
{
"shortcut-title"
:
"krótki tytuł"
,
"create-shortcut"
:
"Utwórz skrót"
,
"edit-shortcut"
:
"Edytuj skrót"
,
"eligible-memo"
:
"kwalifikująca się notatka"
,
"fill-previous"
:
"Proszę uzupełnij poprzednią wartość filtra"
,
"title-required"
:
"Tytuł jest wymagany"
,
"value-required"
:
"Wartość filtra jest wymagana"
},
"filter"
:
{
"new-filter"
:
"Nowy filtr"
,
"type"
:
{
...
...
web/src/locales/pt-BR.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"Registrar"
,
"sign-out"
:
"Sair"
,
"type"
:
"Tipo"
,
"shortcuts"
:
"Atalhos"
,
"title"
:
"Título"
,
"filter"
:
"Filtro"
,
"filter-period"
:
"{{from}} até {{to}}"
,
...
...
@@ -145,15 +144,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"título do atalho"
,
"create-shortcut"
:
"Criar atalho"
,
"edit-shortcut"
:
"Editar atalho"
,
"eligible-memo"
:
"memo elegível"
,
"fill-previous"
:
"Por favor, preencha o valor do filtro anterior"
,
"title-required"
:
"O título do atalho é obrigatório"
,
"value-required"
:
"O valor do filtro é obrigatório"
},
"tag-list"
:
{
"tip-text"
:
"Insira `#tag` para criar uma nova"
,
"create-tag"
:
"Criar Tag"
,
...
...
@@ -401,4 +391,4 @@
"powered-by"
:
"Provido por"
,
"other-projects"
:
"Outros projetos"
}
}
\ No newline at end of file
}
web/src/locales/ru.json
View file @
d1b0b0da
...
...
@@ -43,7 +43,6 @@
"sign-out"
:
"Выйти"
,
"back-to-home"
:
"Вернуться на главную"
,
"type"
:
"Тип"
,
"shortcuts"
:
"Фильтры"
,
"title"
:
"Заголовок"
,
"filter"
:
"Фильтр"
,
"filter-period"
:
"{{from}} по {{to}}"
,
...
...
@@ -179,15 +178,6 @@
"fetching-data"
:
"загрузка данных..."
,
"fetch-more"
:
"Загрузить больше"
},
"shortcut-list"
:
{
"shortcut-title"
:
"Название фильтра"
,
"create-shortcut"
:
"Создать фильтр"
,
"edit-shortcut"
:
"Редактировать фильтр"
,
"eligible-memo"
:
"связанные записи"
,
"fill-previous"
:
"Пожалуйста, заполните значение фильтра"
,
"title-required"
:
"Название обязательно"
,
"value-required"
:
"Значение фильтра обязательно"
},
"filter"
:
{
"new-filter"
:
"Новый фильтр"
,
"type"
:
{
...
...
@@ -469,4 +459,4 @@
"other-projects"
:
"Другие проекты"
,
"powered-by"
:
"Создано"
}
}
\ No newline at end of file
}
web/src/locales/sl.json
View file @
d1b0b0da
...
...
@@ -39,7 +39,6 @@
"sign-out"
:
"Odjavi se"
,
"back-to-home"
:
"Nazaj domov"
,
"type"
:
"Tip"
,
"shortcuts"
:
"Bližnjice"
,
"title"
:
"Naslov"
,
"filter"
:
"Filter"
,
"tags"
:
"Značke"
,
...
...
@@ -130,15 +129,6 @@
"fetching-data"
:
"pridobivam podatke..."
,
"fetch-more"
:
"Kliknite tu da pridobite še več"
},
"shortcut-list"
:
{
"shortcut-title"
:
"naslov bližnjice"
,
"create-shortcut"
:
"Kreiraj bližnjico"
,
"edit-shortcut"
:
"Uredi bližnjico"
,
"eligible-memo"
:
"upravičene beležke"
,
"fill-previous"
:
"Prosim izpolnite prejšnje vrednosti filtra"
,
"title-required"
:
"Naslov je obvezen"
,
"value-required"
:
"Vrednost filtra je obvezna"
},
"filter"
:
{
"new-filter"
:
"Nov filter"
,
"type"
:
{
...
...
@@ -200,7 +190,7 @@
"created_ts"
:
"Čas ustvarjanja"
,
"updated_ts"
:
"Čas posodobitve"
,
"daily-review-time-offset"
:
"Časovni odmik dnevnega pregleda"
,
"auto-collapse"
:
"Samodejno strni"
"auto-collapse"
:
"Samodejno strni"
},
"storage-section"
:
{
"storage-services-list"
:
"Seznam storitev shramb"
,
...
...
web/src/locales/sv.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Logga ut"
,
"back-to-home"
:
"Tillbaka hem"
,
"type"
:
"Typ"
,
"shortcuts"
:
"Genvägar"
,
"title"
:
"Titel"
,
"filter"
:
"Filter"
,
"tags"
:
"Taggar"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"hämtar data..."
,
"fetch-more"
:
"Klicka här för att hämta mer"
},
"shortcut-list"
:
{
"shortcut-title"
:
"Genvägs titel"
,
"create-shortcut"
:
"Skapa genväg"
,
"edit-shortcut"
:
"Ändra genväg"
,
"eligible-memo"
:
"kvalificerad anteckning"
,
"fill-previous"
:
"Vänligen fyll i tidigare filtervärde"
,
"title-required"
:
"Titel krävs"
,
"value-required"
:
"Filtervärde krävs"
},
"filter"
:
{
"new-filter"
:
"Nytt filter"
,
"type"
:
{
...
...
web/src/locales/tr.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Çıkış yap"
,
"back-to-home"
:
"Ana sayfaya dön"
,
"type"
:
"Tip"
,
"shortcuts"
:
"Kısayollar"
,
"title"
:
"Başlık"
,
"filter"
:
"Filtre"
,
"tags"
:
"Etiketler"
,
...
...
@@ -99,15 +98,6 @@
"fetching-data"
:
"Veriler yükleniyor..."
,
"fetch-more"
:
"Daha fazla yükle"
},
"shortcut-list"
:
{
"shortcut-title"
:
"Kısayol adı"
,
"create-shortcut"
:
"Kısayol oluştur"
,
"edit-shortcut"
:
"Kısayolu düzenle"
,
"eligible-memo"
:
"İlgili notlar"
,
"fill-previous"
:
"Lütfen filtre değerini doldurun"
,
"title-required"
:
"Başlık gerekli"
,
"value-required"
:
"Filtre değeri gerekli"
},
"filter"
:
{
"new-filter"
:
"Yeni filtre"
,
"type"
:
{
...
...
web/src/locales/uk.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Вийти"
,
"back-to-home"
:
"Повернутися на головну"
,
"type"
:
"Типу"
,
"shortcuts"
:
"Ярлики"
,
"title"
:
"Заголовок"
,
"filter"
:
"Фільтр"
,
"tags"
:
"Теги"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"завантаження даних..."
,
"fetch-more"
:
"Завантажити більше"
},
"shortcut-list"
:
{
"shortcut-title"
:
"назва ярлика"
,
"create-shortcut"
:
"Створити ярлик"
,
"edit-shortcut"
:
"Редагувати ярлик"
,
"eligible-memo"
:
"пов'язані нотатки"
,
"fill-previous"
:
"Будь ласка заповніть значення фільтра"
,
"title-required"
:
"Назва обов'язкова"
,
"value-required"
:
"Значення фільтра обов'язкове"
},
"filter"
:
{
"new-filter"
:
"Новий фільтр"
,
"type"
:
{
...
...
web/src/locales/vi.json
View file @
d1b0b0da
...
...
@@ -34,7 +34,6 @@
"sign-out"
:
"Đăng xuất"
,
"back-to-home"
:
"Về trang chủ"
,
"type"
:
"Kiểu"
,
"shortcuts"
:
"Lối tắt"
,
"title"
:
"Tiêu đề"
,
"filter"
:
"Bộ lọc"
,
"tags"
:
"Thẻ"
,
...
...
@@ -109,15 +108,6 @@
"fetching-data"
:
"đang tải dữ liệu..."
,
"fetch-more"
:
"Nhấp vào đây để tải thêm dữ liệu"
},
"shortcut-list"
:
{
"shortcut-title"
:
"Tên lối tắt"
,
"create-shortcut"
:
"Tạo lối tắt"
,
"edit-shortcut"
:
"Chỉnh sửa lối tắt"
,
"eligible-memo"
:
"ghi chú đạt chuẩn"
,
"fill-previous"
:
"Vui lòng nhập vào giá trị của bộ lọc trước đó"
,
"title-required"
:
"Tiêu đề là bắt buộc"
,
"value-required"
:
"Giá trị bộ lọc là bắt buộc"
},
"filter"
:
{
"new-filter"
:
"Bộ Lọc Mới"
,
"type"
:
{
...
...
web/src/locales/zh-Hans.json
View file @
d1b0b0da
...
...
@@ -49,7 +49,6 @@
"select"
:
"选择"
,
"settings"
:
"设置"
,
"share"
:
"分享"
,
"shortcuts"
:
"捷径"
,
"sign-in"
:
"登录"
,
"sign-in-with"
:
"使用{{provider}}登录"
,
"sign-out"
:
"注销"
,
...
...
@@ -440,15 +439,6 @@
"display-with-updated-time"
:
"显示最后修改时间"
}
},
"shortcut-list"
:
{
"create-shortcut"
:
"创建捷径"
,
"edit-shortcut"
:
"编辑捷径"
,
"eligible-memo"
:
"符合条件的备忘录"
,
"fill-previous"
:
"请填写之前的过滤值"
,
"shortcut-title"
:
"捷径标题"
,
"title-required"
:
"标题是必填项"
,
"value-required"
:
"过滤值是必填项"
},
"tag-list"
:
{
"all-tags"
:
"全部标签"
,
"create-tag"
:
"创建标签"
,
...
...
web/src/locales/zh-Hant.json
View file @
d1b0b0da
...
...
@@ -38,7 +38,6 @@
"sign-up"
:
"註冊"
,
"sign-out"
:
"登出"
,
"type"
:
"類型"
,
"shortcuts"
:
"捷徑"
,
"title"
:
"標題"
,
"filter"
:
"過濾器"
,
"filter-period"
:
"{{from}} 至 {{to}}"
,
...
...
@@ -148,15 +147,6 @@
}
}
},
"shortcut-list"
:
{
"shortcut-title"
:
"捷徑標題"
,
"create-shortcut"
:
"新增捷徑"
,
"edit-shortcut"
:
"編輯捷徑"
,
"eligible-memo"
:
"符合條件的備忘錄"
,
"fill-previous"
:
"請填入前一個過濾器的值"
,
"title-required"
:
"標題為必填"
,
"value-required"
:
"過濾器值為必填"
},
"tag-list"
:
{
"tip-text"
:
"輸入 `#tag` 以新增標籤"
,
"create-tag"
:
"建立標籤"
,
...
...
@@ -419,4 +409,4 @@
"powered-by"
:
"威力本源"
,
"other-projects"
:
"其他專案"
}
}
\ No newline at end of file
}
web/src/store/index.ts
View file @
d1b0b0da
...
...
@@ -6,7 +6,6 @@ import globalReducer from "./reducer/global";
import
layoutReducer
from
"./reducer/layout"
;
import
memoReducer
from
"./reducer/memo"
;
import
resourceReducer
from
"./reducer/resource"
;
import
shortcutReducer
from
"./reducer/shortcut"
;
import
tagReducer
from
"./reducer/tag"
;
import
userReducer
from
"./reducer/user"
;
...
...
@@ -16,7 +15,6 @@ const store = configureStore({
user
:
userReducer
,
memo
:
memoReducer
,
tag
:
tagReducer
,
shortcut
:
shortcutReducer
,
filter
:
filterReducer
,
resource
:
resourceReducer
,
dialog
:
dialogReducer
,
...
...
web/src/store/module/filter.ts
View file @
d1b0b0da
...
...
@@ -19,7 +19,6 @@ export const useFilterStore = () => {
type
:
undefined
,
duration
:
undefined
,
text
:
undefined
,
shortcutId
:
undefined
,
visibility
:
undefined
,
})
);
...
...
@@ -31,13 +30,6 @@ export const useFilterStore = () => {
})
);
},
setMemoShortcut
:
(
shortcutId
?:
ShortcutId
)
=>
{
store
.
dispatch
(
setFilter
({
shortcutId
:
shortcutId
,
})
);
},
setTextFilter
:
(
text
?:
string
)
=>
{
store
.
dispatch
(
setFilter
({
...
...
web/src/store/module/index.ts
View file @
d1b0b0da
...
...
@@ -3,7 +3,6 @@ export * from "./filter";
export
*
from
"./memo"
;
export
*
from
"./tag"
;
export
*
from
"./resource"
;
export
*
from
"./shortcut"
;
export
*
from
"./user"
;
export
*
from
"./dialog"
;
export
*
from
"./layout"
;
web/src/store/module/shortcut.ts
deleted
100644 → 0
View file @
11abc454
import
*
as
api
from
"@/helpers/api"
;
import
store
,
{
useAppSelector
}
from
"../"
;
import
{
createShortcut
,
deleteShortcut
,
patchShortcut
,
setShortcuts
}
from
"../reducer/shortcut"
;
const
convertResponseModelShortcut
=
(
shortcut
:
Shortcut
):
Shortcut
=>
{
return
{
...
shortcut
,
createdTs
:
shortcut
.
createdTs
*
1000
,
updatedTs
:
shortcut
.
updatedTs
*
1000
,
};
};
export
const
useShortcutStore
=
()
=>
{
const
state
=
useAppSelector
((
state
)
=>
state
.
shortcut
);
return
{
state
,
getState
:
()
=>
{
return
store
.
getState
().
shortcut
;
},
getMyAllShortcuts
:
async
()
=>
{
const
{
data
}
=
await
api
.
getShortcutList
();
const
shortcuts
=
data
.
map
((
s
)
=>
convertResponseModelShortcut
(
s
));
store
.
dispatch
(
setShortcuts
(
shortcuts
));
},
getShortcutById
:
(
id
:
ShortcutId
)
=>
{
for
(
const
s
of
state
.
shortcuts
)
{
if
(
s
.
id
===
id
)
{
return
s
;
}
}
return
null
;
},
createShortcut
:
async
(
shortcutCreate
:
ShortcutCreate
)
=>
{
const
{
data
}
=
await
api
.
createShortcut
(
shortcutCreate
);
const
shortcut
=
convertResponseModelShortcut
(
data
);
store
.
dispatch
(
createShortcut
(
shortcut
));
},
patchShortcut
:
async
(
shortcutPatch
:
ShortcutPatch
)
=>
{
const
{
data
}
=
await
api
.
patchShortcut
(
shortcutPatch
);
const
shortcut
=
convertResponseModelShortcut
(
data
);
store
.
dispatch
(
patchShortcut
(
shortcut
));
},
deleteShortcutById
:
async
(
shortcutId
:
ShortcutId
)
=>
{
await
api
.
deleteShortcutById
(
shortcutId
);
store
.
dispatch
(
deleteShortcut
(
shortcutId
));
},
};
};
web/src/store/reducer/filter.ts
View file @
d1b0b0da
...
...
@@ -10,7 +10,6 @@ interface State {
duration
?:
Duration
;
type
?:
MemoSpecType
;
text
?:
string
;
shortcutId
?:
ShortcutId
;
visibility
?:
Visibility
;
}
...
...
web/src/store/reducer/shortcut.ts
deleted
100644 → 0
View file @
11abc454
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
shortcuts
:
Shortcut
[];
}
const
shortcutSlice
=
createSlice
({
name
:
"memo"
,
initialState
:
{
shortcuts
:
[],
}
as
State
,
reducers
:
{
setShortcuts
:
(
state
,
action
:
PayloadAction
<
Shortcut
[]
>
)
=>
{
return
{
...
state
,
shortcuts
:
action
.
payload
,
};
},
createShortcut
:
(
state
,
action
:
PayloadAction
<
Shortcut
>
)
=>
{
return
{
...
state
,
shortcuts
:
state
.
shortcuts
.
concat
(
action
.
payload
).
sort
((
a
,
b
)
=>
b
.
createdTs
-
a
.
createdTs
),
};
},
patchShortcut
:
(
state
,
action
:
PayloadAction
<
Partial
<
Shortcut
>>
)
=>
{
return
{
...
state
,
shortcuts
:
state
.
shortcuts
.
map
((
s
)
=>
{
if
(
s
.
id
===
action
.
payload
.
id
)
{
return
{
...
s
,
...
action
.
payload
,
};
}
else
{
return
s
;
}
}),
};
},
deleteShortcut
:
(
state
,
action
:
PayloadAction
<
ShortcutId
>
)
=>
{
return
{
...
state
,
shortcuts
:
[...
state
.
shortcuts
].
filter
((
shortcut
)
=>
shortcut
.
id
!==
action
.
payload
),
};
},
},
});
export
const
{
setShortcuts
,
createShortcut
,
patchShortcut
,
deleteShortcut
}
=
shortcutSlice
.
actions
;
export
default
shortcutSlice
.
reducer
;
web/src/types/modules/shortcut.d.ts
deleted
100644 → 0
View file @
11abc454
type
ShortcutId
=
number
;
interface
Shortcut
{
id
:
ShortcutId
;
rowStatus
:
RowStatus
;
createdTs
:
TimeStamp
;
updatedTs
:
TimeStamp
;
title
:
string
;
payload
:
string
;
}
interface
ShortcutCreate
{
title
:
string
;
payload
:
string
;
}
interface
ShortcutPatch
{
id
:
ShortcutId
;
title
?:
string
;
payload
?:
string
;
rowStatus
?:
RowStatus
;
}
interface
ShortcutFind
{
creatorUsername
?:
string
;
}
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