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
707e5caf
Commit
707e5caf
authored
Apr 12, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: update workspace setting store
parent
17e8fc54
Changes
18
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
369 additions
and
464 deletions
+369
-464
workspace_setting_service.proto
proto/api/v2/workspace_setting_service.proto
+2
-2
README.md
proto/gen/api/v2/README.md
+1
-1
workspace_setting_service.pb.go
proto/gen/api/v2/workspace_setting_service.pb.go
+78
-76
README.md
proto/gen/store/README.md
+1
-1
workspace_setting.pb.go
proto/gen/store/workspace_setting.pb.go
+60
-59
workspace_setting.proto
proto/store/workspace_setting.proto
+2
-2
apidocs.swagger.yaml
server/route/api/v2/apidocs.swagger.yaml
+2
-2
resource_service.go
server/route/api/v2/resource_service.go
+2
-2
workspace_setting_service.go
server/route/api/v2/workspace_setting_service.go
+8
-6
common.go
store/common.go
+9
-0
user_setting.go
store/db/mysql/user_setting.go
+8
-59
user_setting.go
store/db/postgres/user_setting.go
+8
-59
user_setting.go
store/db/sqlite/user_setting.go
+8
-59
driver.go
store/driver.go
+2
-2
user_setting.go
store/user_setting.go
+86
-7
workspace_setting.go
store/workspace_setting.go
+20
-5
StorageSection.tsx
web/src/components/Settings/StorageSection.tsx
+72
-34
UpdateLocalStorageDialog.tsx
web/src/components/UpdateLocalStorageDialog.tsx
+0
-88
No files found.
proto/api/v2/workspace_setting_service.proto
View file @
707e5caf
...
...
@@ -93,9 +93,9 @@ message WorkspaceStorageSetting {
StorageType
storage_type
=
1
;
// The id of actived external storage.
optional
int32
actived_external_storage_id
=
2
;
// The
local storage path for STORAGE_TYPE_LOCAL
.
// The
template of local storage path
.
// e.g. assets/{timestamp}_{filename}
string
local_storage_path
=
3
;
string
local_storage_path
_template
=
3
;
// The max upload size in megabytes.
int64
upload_size_limit_mb
=
4
;
...
...
proto/gen/api/v2/README.md
View file @
707e5caf
...
...
@@ -3084,7 +3084,7 @@ Used internally for obfuscating the page token.
| ----- | ---- | ----- | ----------- |
| storage_type |
[
WorkspaceStorageSetting.StorageType
](
#memos-api-v2-WorkspaceStorageSetting-StorageType
)
| | storage_type is the storage type. |
| actived_external_storage_id |
[
int32
](
#int32
)
| optional | The id of actived external storage. |
| local_storage_path
|
[
string
](
#string
)
| | The local storage path for STORAGE_TYPE_LOCAL
. e.g. assets/{timestamp}_{filename} |
| local_storage_path
_template |
[
string
](
#string
)
| | The template of local storage path
. e.g. assets/{timestamp}_{filename} |
| upload_size_limit_mb |
[
int64
](
#int64
)
| | The max upload size in megabytes. |
...
...
proto/gen/api/v2/workspace_setting_service.pb.go
View file @
707e5caf
This diff is collapsed.
Click to expand it.
proto/gen/store/README.md
View file @
707e5caf
...
...
@@ -636,7 +636,7 @@
| ----- | ---- | ----- | ----------- |
| storage_type |
[
WorkspaceStorageSetting.StorageType
](
#memos-store-WorkspaceStorageSetting-StorageType
)
| | storage_type is the storage type. |
| actived_external_storage_id |
[
int32
](
#int32
)
| optional | The id of actived external storage. |
| local_storage_path
|
[
string
](
#string
)
| | The local storage path for STORAGE_TYPE_LOCAL
. e.g. assets/{timestamp}_{filename} |
| local_storage_path
_template |
[
string
](
#string
)
| | The template of local storage path
. e.g. assets/{timestamp}_{filename} |
| upload_size_limit_mb |
[
int64
](
#int64
)
| | The max upload size in megabytes. |
...
...
proto/gen/store/workspace_setting.pb.go
View file @
707e5caf
This diff is collapsed.
Click to expand it.
proto/store/workspace_setting.proto
View file @
707e5caf
...
...
@@ -62,9 +62,9 @@ message WorkspaceStorageSetting {
StorageType
storage_type
=
1
;
// The id of actived external storage.
optional
int32
actived_external_storage_id
=
2
;
// The
local storage path for STORAGE_TYPE_LOCAL
.
// The
template of local storage path
.
// e.g. assets/{timestamp}_{filename}
string
local_storage_path
=
3
;
string
local_storage_path
_template
=
3
;
// The max upload size in megabytes.
int64
upload_size_limit_mb
=
4
;
...
...
server/route/api/v2/apidocs.swagger.yaml
View file @
707e5caf
...
...
@@ -2069,10 +2069,10 @@ definitions:
type
:
integer
format
:
int32
description
:
The id of actived external storage.
localStoragePath
:
localStoragePath
Template
:
type
:
string
title
:
|-
The
local storage path for STORAGE_TYPE_LOCAL
.
The
template of local storage path
.
e.g. assets/{timestamp}_{filename}
uploadSizeLimitMb
:
type
:
string
...
...
server/route/api/v2/resource_service.go
View file @
707e5caf
...
...
@@ -260,8 +260,8 @@ func SaveResourceBlob(ctx context.Context, s *store.Store, create *store.Resourc
if
workspaceStorageSetting
.
StorageType
==
storepb
.
WorkspaceStorageSetting_STORAGE_TYPE_LOCAL
{
localStoragePath
:=
"assets/{timestamp}_{filename}"
if
workspaceStorageSetting
.
LocalStoragePath
!=
""
{
localStoragePath
=
workspaceStorageSetting
.
LocalStoragePath
if
workspaceStorageSetting
.
LocalStoragePath
Template
!=
""
{
localStoragePath
=
workspaceStorageSetting
.
LocalStoragePath
Template
}
internalPath
:=
localStoragePath
...
...
server/route/api/v2/workspace_setting_service.go
View file @
707e5caf
...
...
@@ -177,8 +177,9 @@ func convertWorkspaceStorageSettingFromStore(setting *storepb.WorkspaceStorageSe
}
return
&
apiv2pb
.
WorkspaceStorageSetting
{
StorageType
:
apiv2pb
.
WorkspaceStorageSetting_StorageType
(
setting
.
StorageType
),
LocalStoragePath
:
setting
.
LocalStoragePath
,
LocalStoragePath
Template
:
setting
.
LocalStoragePathTemplate
,
UploadSizeLimitMb
:
setting
.
UploadSizeLimitMb
,
ActivedExternalStorageId
:
setting
.
ActivedExternalStorageId
,
}
}
...
...
@@ -188,8 +189,9 @@ func convertWorkspaceStorageSettingToStore(setting *apiv2pb.WorkspaceStorageSett
}
return
&
storepb
.
WorkspaceStorageSetting
{
StorageType
:
storepb
.
WorkspaceStorageSetting_StorageType
(
setting
.
StorageType
),
LocalStoragePath
:
setting
.
LocalStoragePath
,
LocalStoragePath
Template
:
setting
.
LocalStoragePathTemplate
,
UploadSizeLimitMb
:
setting
.
UploadSizeLimitMb
,
ActivedExternalStorageId
:
setting
.
ActivedExternalStorageId
,
}
}
...
...
store/common.go
View file @
707e5caf
package
store
import
"google.golang.org/protobuf/encoding/protojson"
var
(
protojsonUnmarshaler
=
protojson
.
UnmarshalOptions
{
AllowPartial
:
true
,
DiscardUnknown
:
true
,
}
)
// RowStatus is the status for a row.
type
RowStatus
string
...
...
store/db/mysql/user_setting.go
View file @
707e5caf
...
...
@@ -5,42 +5,19 @@ import (
"database/sql"
"strings"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb
"github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func
(
d
*
DB
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
store
pb
.
UserSetting
)
(
*
storepb
.
UserSetting
,
error
)
{
func
(
d
*
DB
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
store
.
UserSetting
)
(
*
store
.
UserSetting
,
error
)
{
stmt
:=
"INSERT INTO `user_setting` (`user_id`, `key`, `value`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `value` = ?"
var
valueString
string
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
{
valueBytes
,
err
:=
protojson
.
Marshal
(
upsert
.
GetAccessTokens
())
if
err
!=
nil
{
return
nil
,
err
}
valueString
=
string
(
valueBytes
)
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_LOCALE
{
valueString
=
upsert
.
GetLocale
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
{
valueString
=
upsert
.
GetAppearance
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
{
valueString
=
upsert
.
GetMemoVisibility
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
{
valueString
=
upsert
.
GetTelegramUserId
()
}
else
{
return
nil
,
errors
.
Errorf
(
"unknown user setting key: %s"
,
upsert
.
Key
.
String
())
}
if
_
,
err
:=
d
.
db
.
ExecContext
(
ctx
,
stmt
,
upsert
.
UserId
,
upsert
.
Key
.
String
(),
valueString
,
valueString
);
err
!=
nil
{
if
_
,
err
:=
d
.
db
.
ExecContext
(
ctx
,
stmt
,
upsert
.
UserID
,
upsert
.
Key
.
String
(),
upsert
.
Value
,
upsert
.
Value
);
err
!=
nil
{
return
nil
,
err
}
return
upsert
,
nil
}
func
(
d
*
DB
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
store
.
FindUserSetting
)
([]
*
store
pb
.
UserSetting
,
error
)
{
func
(
d
*
DB
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
store
.
FindUserSetting
)
([]
*
store
.
UserSetting
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
if
v
:=
find
.
Key
;
v
!=
storepb
.
UserSettingKey_USER_SETTING_KEY_UNSPECIFIED
{
...
...
@@ -57,46 +34,18 @@ func (d *DB) ListUserSettings(ctx context.Context, find *store.FindUserSetting)
}
defer
rows
.
Close
()
userSettingList
:=
make
([]
*
store
pb
.
UserSetting
,
0
)
userSettingList
:=
make
([]
*
store
.
UserSetting
,
0
)
for
rows
.
Next
()
{
userSetting
:=
&
store
pb
.
UserSetting
{}
var
keyString
,
valueString
string
userSetting
:=
&
store
.
UserSetting
{}
var
keyString
string
if
err
:=
rows
.
Scan
(
&
userSetting
.
UserI
d
,
&
userSetting
.
UserI
D
,
&
keyString
,
&
valueString
,
&
userSetting
.
Value
,
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Key
=
storepb
.
UserSettingKey
(
storepb
.
UserSettingKey_value
[
keyString
])
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
{
accessTokensUserSetting
:=
&
storepb
.
AccessTokensUserSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
valueString
),
accessTokensUserSetting
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Value
=
&
storepb
.
UserSetting_AccessTokens
{
AccessTokens
:
accessTokensUserSetting
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_LOCALE
{
userSetting
.
Value
=
&
storepb
.
UserSetting_Locale
{
Locale
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
{
userSetting
.
Value
=
&
storepb
.
UserSetting_Appearance
{
Appearance
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
{
userSetting
.
Value
=
&
storepb
.
UserSetting_MemoVisibility
{
MemoVisibility
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
{
userSetting
.
Value
=
&
storepb
.
UserSetting_TelegramUserId
{
TelegramUserId
:
valueString
,
}
}
else
{
// Skip unknown user setting key.
continue
}
userSettingList
=
append
(
userSettingList
,
userSetting
)
}
...
...
store/db/postgres/user_setting.go
View file @
707e5caf
...
...
@@ -5,14 +5,11 @@ import (
"database/sql"
"strings"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb
"github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func
(
d
*
DB
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
store
pb
.
UserSetting
)
(
*
storepb
.
UserSetting
,
error
)
{
func
(
d
*
DB
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
store
.
UserSetting
)
(
*
store
.
UserSetting
,
error
)
{
stmt
:=
`
INSERT INTO user_setting (
user_id, key, value
...
...
@@ -21,33 +18,13 @@ func (d *DB) UpsertUserSetting(ctx context.Context, upsert *storepb.UserSetting)
ON CONFLICT(user_id, key) DO UPDATE
SET value = EXCLUDED.value
`
var
valueString
string
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
{
valueBytes
,
err
:=
protojson
.
Marshal
(
upsert
.
GetAccessTokens
())
if
err
!=
nil
{
return
nil
,
err
}
valueString
=
string
(
valueBytes
)
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_LOCALE
{
valueString
=
upsert
.
GetLocale
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
{
valueString
=
upsert
.
GetAppearance
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
{
valueString
=
upsert
.
GetMemoVisibility
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
{
valueString
=
upsert
.
GetTelegramUserId
()
}
else
{
return
nil
,
errors
.
Errorf
(
"unknown user setting key: %s"
,
upsert
.
Key
.
String
())
}
if
_
,
err
:=
d
.
db
.
ExecContext
(
ctx
,
stmt
,
upsert
.
UserId
,
upsert
.
Key
.
String
(),
valueString
);
err
!=
nil
{
if
_
,
err
:=
d
.
db
.
ExecContext
(
ctx
,
stmt
,
upsert
.
UserID
,
upsert
.
Key
.
String
(),
upsert
.
Value
);
err
!=
nil
{
return
nil
,
err
}
return
upsert
,
nil
}
func
(
d
*
DB
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
store
.
FindUserSetting
)
([]
*
store
pb
.
UserSetting
,
error
)
{
func
(
d
*
DB
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
store
.
FindUserSetting
)
([]
*
store
.
UserSetting
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
if
v
:=
find
.
Key
;
v
!=
storepb
.
UserSettingKey_USER_SETTING_KEY_UNSPECIFIED
{
...
...
@@ -70,46 +47,18 @@ func (d *DB) ListUserSettings(ctx context.Context, find *store.FindUserSetting)
}
defer
rows
.
Close
()
userSettingList
:=
make
([]
*
store
pb
.
UserSetting
,
0
)
userSettingList
:=
make
([]
*
store
.
UserSetting
,
0
)
for
rows
.
Next
()
{
userSetting
:=
&
store
pb
.
UserSetting
{}
var
keyString
,
valueString
string
userSetting
:=
&
store
.
UserSetting
{}
var
keyString
string
if
err
:=
rows
.
Scan
(
&
userSetting
.
UserI
d
,
&
userSetting
.
UserI
D
,
&
keyString
,
&
valueString
,
&
userSetting
.
Value
,
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Key
=
storepb
.
UserSettingKey
(
storepb
.
UserSettingKey_value
[
keyString
])
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
{
accessTokensUserSetting
:=
&
storepb
.
AccessTokensUserSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
valueString
),
accessTokensUserSetting
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Value
=
&
storepb
.
UserSetting_AccessTokens
{
AccessTokens
:
accessTokensUserSetting
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_LOCALE
{
userSetting
.
Value
=
&
storepb
.
UserSetting_Locale
{
Locale
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
{
userSetting
.
Value
=
&
storepb
.
UserSetting_Appearance
{
Appearance
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
{
userSetting
.
Value
=
&
storepb
.
UserSetting_MemoVisibility
{
MemoVisibility
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
{
userSetting
.
Value
=
&
storepb
.
UserSetting_TelegramUserId
{
TelegramUserId
:
valueString
,
}
}
else
{
// Skip unknown user setting key.
continue
}
userSettingList
=
append
(
userSettingList
,
userSetting
)
}
...
...
store/db/sqlite/user_setting.go
View file @
707e5caf
...
...
@@ -5,14 +5,11 @@ import (
"database/sql"
"strings"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb
"github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func
(
d
*
DB
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
store
pb
.
UserSetting
)
(
*
storepb
.
UserSetting
,
error
)
{
func
(
d
*
DB
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
store
.
UserSetting
)
(
*
store
.
UserSetting
,
error
)
{
stmt
:=
`
INSERT INTO user_setting (
user_id, key, value
...
...
@@ -21,33 +18,13 @@ func (d *DB) UpsertUserSetting(ctx context.Context, upsert *storepb.UserSetting)
ON CONFLICT(user_id, key) DO UPDATE
SET value = EXCLUDED.value
`
var
valueString
string
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
{
valueBytes
,
err
:=
protojson
.
Marshal
(
upsert
.
GetAccessTokens
())
if
err
!=
nil
{
return
nil
,
err
}
valueString
=
string
(
valueBytes
)
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_LOCALE
{
valueString
=
upsert
.
GetLocale
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
{
valueString
=
upsert
.
GetAppearance
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
{
valueString
=
upsert
.
GetMemoVisibility
()
}
else
if
upsert
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
{
valueString
=
upsert
.
GetTelegramUserId
()
}
else
{
return
nil
,
errors
.
Errorf
(
"unknown user setting key: %s"
,
upsert
.
Key
.
String
())
}
if
_
,
err
:=
d
.
db
.
ExecContext
(
ctx
,
stmt
,
upsert
.
UserId
,
upsert
.
Key
.
String
(),
valueString
);
err
!=
nil
{
if
_
,
err
:=
d
.
db
.
ExecContext
(
ctx
,
stmt
,
upsert
.
UserID
,
upsert
.
Key
.
String
(),
upsert
.
Value
);
err
!=
nil
{
return
nil
,
err
}
return
upsert
,
nil
}
func
(
d
*
DB
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
store
.
FindUserSetting
)
([]
*
store
pb
.
UserSetting
,
error
)
{
func
(
d
*
DB
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
store
.
FindUserSetting
)
([]
*
store
.
UserSetting
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
if
v
:=
find
.
Key
;
v
!=
storepb
.
UserSettingKey_USER_SETTING_KEY_UNSPECIFIED
{
...
...
@@ -70,46 +47,18 @@ func (d *DB) ListUserSettings(ctx context.Context, find *store.FindUserSetting)
}
defer
rows
.
Close
()
userSettingList
:=
make
([]
*
store
pb
.
UserSetting
,
0
)
userSettingList
:=
make
([]
*
store
.
UserSetting
,
0
)
for
rows
.
Next
()
{
userSetting
:=
&
store
pb
.
UserSetting
{}
var
keyString
,
valueString
string
userSetting
:=
&
store
.
UserSetting
{}
var
keyString
string
if
err
:=
rows
.
Scan
(
&
userSetting
.
UserI
d
,
&
userSetting
.
UserI
D
,
&
keyString
,
&
valueString
,
&
userSetting
.
Value
,
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Key
=
storepb
.
UserSettingKey
(
storepb
.
UserSettingKey_value
[
keyString
])
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
{
accessTokensUserSetting
:=
&
storepb
.
AccessTokensUserSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
valueString
),
accessTokensUserSetting
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Value
=
&
storepb
.
UserSetting_AccessTokens
{
AccessTokens
:
accessTokensUserSetting
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_LOCALE
{
userSetting
.
Value
=
&
storepb
.
UserSetting_Locale
{
Locale
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
{
userSetting
.
Value
=
&
storepb
.
UserSetting_Appearance
{
Appearance
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
{
userSetting
.
Value
=
&
storepb
.
UserSetting_MemoVisibility
{
MemoVisibility
:
valueString
,
}
}
else
if
userSetting
.
Key
==
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
{
userSetting
.
Value
=
&
storepb
.
UserSetting_TelegramUserId
{
TelegramUserId
:
valueString
,
}
}
else
{
// Skip unknown user setting key.
continue
}
userSettingList
=
append
(
userSettingList
,
userSetting
)
}
if
err
:=
rows
.
Err
();
err
!=
nil
{
...
...
store/driver.go
View file @
707e5caf
...
...
@@ -61,8 +61,8 @@ type Driver interface {
DeleteUser
(
ctx
context
.
Context
,
delete
*
DeleteUser
)
error
// UserSetting model related methods.
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
storepb
.
UserSetting
)
(
*
storepb
.
UserSetting
,
error
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
FindUserSetting
)
([]
*
storepb
.
UserSetting
,
error
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
UserSetting
)
(
*
UserSetting
,
error
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
FindUserSetting
)
([]
*
UserSetting
,
error
)
// IdentityProvider model related methods.
CreateIdentityProvider
(
ctx
context
.
Context
,
create
*
IdentityProvider
)
(
*
IdentityProvider
,
error
)
...
...
store/user_setting.go
View file @
707e5caf
...
...
@@ -3,34 +3,56 @@ package store
import
(
"context"
"github.com/pkg/errors"
storepb
"github.com/usememos/memos/proto/gen/store"
"google.golang.org/protobuf/encoding/protojson"
)
type
UserSetting
struct
{
UserID
int32
Key
storepb
.
UserSettingKey
Value
string
}
type
FindUserSetting
struct
{
UserID
*
int32
Key
storepb
.
UserSettingKey
}
func
(
s
*
Store
)
UpsertUserSetting
(
ctx
context
.
Context
,
upsert
*
storepb
.
UserSetting
)
(
*
storepb
.
UserSetting
,
error
)
{
userSettingMessage
,
err
:=
s
.
driver
.
UpsertUserSetting
(
ctx
,
upsert
)
userSettingRaw
,
err
:=
convertUserSettingToRaw
(
upsert
)
if
err
!=
nil
{
return
nil
,
err
}
userSettingRaw
,
err
=
s
.
driver
.
UpsertUserSetting
(
ctx
,
userSettingRaw
)
if
err
!=
nil
{
return
nil
,
err
}
s
.
userSettingCache
.
Store
(
getUserSettingV1CacheKey
(
userSettingMessage
.
UserId
,
userSettingMessage
.
Key
.
String
()),
userSettingMessage
)
return
userSettingMessage
,
nil
userSetting
,
err
:=
convertUserSettingFromRaw
(
userSettingRaw
)
if
err
!=
nil
{
return
nil
,
err
}
s
.
userSettingCache
.
Store
(
getUserSettingV1CacheKey
(
userSetting
.
UserId
,
userSetting
.
Key
.
String
()),
userSetting
)
return
userSetting
,
nil
}
func
(
s
*
Store
)
ListUserSettings
(
ctx
context
.
Context
,
find
*
FindUserSetting
)
([]
*
storepb
.
UserSetting
,
error
)
{
userSettingList
,
err
:=
s
.
driver
.
ListUserSettings
(
ctx
,
find
)
userSetting
Raw
List
,
err
:=
s
.
driver
.
ListUserSettings
(
ctx
,
find
)
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
userSetting
:=
range
userSettingList
{
userSettings
:=
[]
*
storepb
.
UserSetting
{}
for
_
,
userSettingRaw
:=
range
userSettingRawList
{
userSetting
,
err
:=
convertUserSettingFromRaw
(
userSettingRaw
)
if
err
!=
nil
{
return
nil
,
err
}
s
.
userSettingCache
.
Store
(
getUserSettingV1CacheKey
(
userSetting
.
UserId
,
userSetting
.
Key
.
String
()),
userSetting
)
userSettings
=
append
(
userSettings
,
userSetting
)
}
return
userSetting
List
,
nil
return
userSetting
s
,
nil
}
func
(
s
*
Store
)
GetUserSetting
(
ctx
context
.
Context
,
find
*
FindUserSetting
)
(
*
storepb
.
UserSetting
,
error
)
{
...
...
@@ -44,10 +66,12 @@ func (s *Store) GetUserSetting(ctx context.Context, find *FindUserSetting) (*sto
if
err
!=
nil
{
return
nil
,
err
}
if
len
(
list
)
==
0
{
return
nil
,
nil
}
if
len
(
list
)
>
1
{
return
nil
,
errors
.
Errorf
(
"expected 1 user setting, but got %d"
,
len
(
list
))
}
userSetting
:=
list
[
0
]
s
.
userSettingCache
.
Store
(
getUserSettingV1CacheKey
(
userSetting
.
UserId
,
userSetting
.
Key
.
String
()),
userSetting
)
...
...
@@ -97,3 +121,58 @@ func (s *Store) RemoveUserAccessToken(ctx context.Context, userID int32, token s
return
err
}
func
convertUserSettingFromRaw
(
raw
*
UserSetting
)
(
*
storepb
.
UserSetting
,
error
)
{
userSetting
:=
&
storepb
.
UserSetting
{
UserId
:
raw
.
UserID
,
Key
:
raw
.
Key
,
}
switch
raw
.
Key
{
case
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
:
accessTokensUserSetting
:=
&
storepb
.
AccessTokensUserSetting
{}
if
err
:=
protojsonUnmarshaler
.
Unmarshal
([]
byte
(
raw
.
Value
),
accessTokensUserSetting
);
err
!=
nil
{
return
nil
,
err
}
userSetting
.
Value
=
&
storepb
.
UserSetting_AccessTokens
{
AccessTokens
:
accessTokensUserSetting
}
case
storepb
.
UserSettingKey_USER_SETTING_LOCALE
:
userSetting
.
Value
=
&
storepb
.
UserSetting_Locale
{
Locale
:
raw
.
Value
}
case
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
:
userSetting
.
Value
=
&
storepb
.
UserSetting_Appearance
{
Appearance
:
raw
.
Value
}
case
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
:
userSetting
.
Value
=
&
storepb
.
UserSetting_MemoVisibility
{
MemoVisibility
:
raw
.
Value
}
case
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
:
userSetting
.
Value
=
&
storepb
.
UserSetting_TelegramUserId
{
TelegramUserId
:
raw
.
Value
}
default
:
return
nil
,
errors
.
Errorf
(
"unsupported user setting key: %v"
,
raw
.
Key
)
}
return
userSetting
,
nil
}
func
convertUserSettingToRaw
(
userSetting
*
storepb
.
UserSetting
)
(
*
UserSetting
,
error
)
{
raw
:=
&
UserSetting
{
UserID
:
userSetting
.
UserId
,
Key
:
userSetting
.
Key
,
}
switch
userSetting
.
Key
{
case
storepb
.
UserSettingKey_USER_SETTING_ACCESS_TOKENS
:
accessTokensUserSetting
:=
userSetting
.
GetAccessTokens
()
value
,
err
:=
protojson
.
Marshal
(
accessTokensUserSetting
)
if
err
!=
nil
{
return
nil
,
err
}
raw
.
Value
=
string
(
value
)
case
storepb
.
UserSettingKey_USER_SETTING_LOCALE
:
raw
.
Value
=
userSetting
.
GetLocale
()
case
storepb
.
UserSettingKey_USER_SETTING_APPEARANCE
:
raw
.
Value
=
userSetting
.
GetAppearance
()
case
storepb
.
UserSettingKey_USER_SETTING_MEMO_VISIBILITY
:
raw
.
Value
=
userSetting
.
GetMemoVisibility
()
case
storepb
.
UserSettingKey_USER_SETTING_TELEGRAM_USER_ID
:
raw
.
Value
=
userSetting
.
GetTelegramUserId
()
default
:
return
nil
,
errors
.
Errorf
(
"unsupported user setting key: %v"
,
userSetting
.
Key
)
}
return
raw
,
nil
}
store/workspace_setting.go
View file @
707e5caf
...
...
@@ -186,6 +186,12 @@ func (s *Store) GetWorkspaceMemoRelatedSetting(ctx context.Context) (*storepb.Wo
return
workspaceMemoRelatedSetting
,
nil
}
const
(
defaultWorkspaceStorageType
=
storepb
.
WorkspaceStorageSetting_STORAGE_TYPE_DATABASE
defaultWorkspaceUploadSizeLimitMb
=
30
defaultWorkspaceLocalStoragePathTemplate
=
"assets/{timestamp}_{filename}"
)
func
(
s
*
Store
)
GetWorkspaceStorageSetting
(
ctx
context
.
Context
)
(
*
storepb
.
WorkspaceStorageSetting
,
error
)
{
workspaceSetting
,
err
:=
s
.
GetWorkspaceSettingV1
(
ctx
,
&
FindWorkspaceSetting
{
Name
:
storepb
.
WorkspaceSettingKey_WORKSPACE_SETTING_STORAGE
.
String
(),
...
...
@@ -198,6 +204,15 @@ func (s *Store) GetWorkspaceStorageSetting(ctx context.Context) (*storepb.Worksp
if
workspaceSetting
!=
nil
{
workspaceStorageSetting
=
workspaceSetting
.
GetStorageSetting
()
}
if
workspaceStorageSetting
.
StorageType
==
storepb
.
WorkspaceStorageSetting_STORAGE_TYPE_UNSPECIFIED
{
workspaceStorageSetting
.
StorageType
=
defaultWorkspaceStorageType
}
if
workspaceStorageSetting
.
UploadSizeLimitMb
==
0
{
workspaceStorageSetting
.
UploadSizeLimitMb
=
defaultWorkspaceUploadSizeLimitMb
}
if
workspaceStorageSetting
.
LocalStoragePathTemplate
==
""
{
workspaceStorageSetting
.
LocalStoragePathTemplate
=
defaultWorkspaceLocalStoragePathTemplate
}
return
workspaceStorageSetting
,
nil
}
...
...
@@ -208,31 +223,31 @@ func convertWorkspaceSettingFromRaw(workspaceSettingRaw *WorkspaceSetting) (*sto
switch
workspaceSettingRaw
.
Name
{
case
storepb
.
WorkspaceSettingKey_WORKSPACE_SETTING_BASIC
.
String
()
:
basicSetting
:=
&
storepb
.
WorkspaceBasicSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
basicSetting
);
err
!=
nil
{
if
err
:=
protojson
Unmarshaler
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
basicSetting
);
err
!=
nil
{
return
nil
,
err
}
workspaceSetting
.
Value
=
&
storepb
.
WorkspaceSetting_BasicSetting
{
BasicSetting
:
basicSetting
}
case
storepb
.
WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL
.
String
()
:
generalSetting
:=
&
storepb
.
WorkspaceGeneralSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
generalSetting
);
err
!=
nil
{
if
err
:=
protojson
Unmarshaler
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
generalSetting
);
err
!=
nil
{
return
nil
,
err
}
workspaceSetting
.
Value
=
&
storepb
.
WorkspaceSetting_GeneralSetting
{
GeneralSetting
:
generalSetting
}
case
storepb
.
WorkspaceSettingKey_WORKSPACE_SETTING_STORAGE
.
String
()
:
storageSetting
:=
&
storepb
.
WorkspaceStorageSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
storageSetting
);
err
!=
nil
{
if
err
:=
protojson
Unmarshaler
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
storageSetting
);
err
!=
nil
{
return
nil
,
err
}
workspaceSetting
.
Value
=
&
storepb
.
WorkspaceSetting_StorageSetting
{
StorageSetting
:
storageSetting
}
case
storepb
.
WorkspaceSettingKey_WORKSPACE_SETTING_MEMO_RELATED
.
String
()
:
memoRelatedSetting
:=
&
storepb
.
WorkspaceMemoRelatedSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
memoRelatedSetting
);
err
!=
nil
{
if
err
:=
protojson
Unmarshaler
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
memoRelatedSetting
);
err
!=
nil
{
return
nil
,
err
}
workspaceSetting
.
Value
=
&
storepb
.
WorkspaceSetting_MemoRelatedSetting
{
MemoRelatedSetting
:
memoRelatedSetting
}
case
storepb
.
WorkspaceSettingKey_WORKSPACE_SETTING_TELEGRAM_INTEGRATION
.
String
()
:
telegramIntegrationSetting
:=
&
storepb
.
WorkspaceTelegramIntegrationSetting
{}
if
err
:=
protojson
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
telegramIntegrationSetting
);
err
!=
nil
{
if
err
:=
protojson
Unmarshaler
.
Unmarshal
([]
byte
(
workspaceSettingRaw
.
Value
),
telegramIntegrationSetting
);
err
!=
nil
{
return
nil
,
err
}
workspaceSetting
.
Value
=
&
storepb
.
WorkspaceSetting_TelegramIntegrationSetting
{
TelegramIntegrationSetting
:
telegramIntegrationSetting
}
...
...
web/src/components/Settings/StorageSection.tsx
View file @
707e5caf
...
...
@@ -2,7 +2,6 @@ import {
Button
,
Divider
,
Dropdown
,
IconButton
,
Input
,
List
,
ListItem
,
...
...
@@ -11,9 +10,12 @@ import {
MenuItem
,
Radio
,
RadioGroup
,
Select
,
Tooltip
,
Option
,
}
from
"@mui/joy"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
useEffect
,
useMemo
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
Link
}
from
"react-router-dom"
;
import
*
as
api
from
"@/helpers/api"
;
...
...
@@ -25,7 +27,6 @@ import showCreateStorageServiceDialog from "../CreateStorageServiceDialog";
import
{
showCommonDialog
}
from
"../Dialog/CommonDialog"
;
import
Icon
from
"../Icon"
;
import
LearnMore
from
"../LearnMore"
;
import
showUpdateLocalStorageDialog
from
"../UpdateLocalStorageDialog"
;
const
StorageSection
=
()
=>
{
const
t
=
useTranslate
();
...
...
@@ -37,6 +38,26 @@ const StorageSection = () => {
),
);
const
allowSaveStorageSetting
=
useMemo
(()
=>
{
if
(
workspaceStorageSetting
.
uploadSizeLimitMb
<=
0
)
{
return
false
;
}
const
origin
=
WorkspaceStorageSetting
.
fromPartial
(
workspaceSettingStore
.
getWorkspaceSettingByKey
(
WorkspaceSettingKey
.
WORKSPACE_SETTING_STORAGE
)?.
storageSetting
||
{},
);
if
(
workspaceStorageSetting
.
storageType
===
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_LOCAL
)
{
if
(
workspaceStorageSetting
.
localStoragePathTemplate
.
length
===
0
)
{
return
false
;
}
}
else
if
(
workspaceStorageSetting
.
storageType
===
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_EXTERNAL
)
{
if
(
!
workspaceStorageSetting
.
activedExternalStorageId
||
workspaceStorageSetting
.
activedExternalStorageId
===
0
)
{
return
false
;
}
}
return
!
isEqual
(
origin
,
workspaceStorageSetting
);
},
[
workspaceStorageSetting
,
workspaceSettingStore
.
getState
()]);
useEffect
(()
=>
{
fetchStorageList
();
},
[]);
...
...
@@ -56,10 +77,14 @@ const StorageSection = () => {
uploadSizeLimitMb
:
num
,
};
setWorkspaceStorageSetting
(
update
);
workspaceSettingStore
.
setWorkspaceSetting
({
name
:
`
${
WorkspaceSettingPrefix
}${
WorkspaceSettingKey
.
WORKSPACE_SETTING_STORAGE
}
`
,
storageSetting
:
update
,
});
};
const
handleLocalStoragePathTemplateChanged
=
async
(
event
:
React
.
FocusEvent
<
HTMLInputElement
>
)
=>
{
const
update
:
WorkspaceStorageSetting
=
{
...
workspaceStorageSetting
,
localStoragePathTemplate
:
event
.
target
.
value
,
};
setWorkspaceStorageSetting
(
update
);
};
const
handleStorageTypeChanged
=
async
(
storageType
:
WorkspaceStorageSetting_StorageType
)
=>
{
...
...
@@ -68,10 +93,6 @@ const StorageSection = () => {
storageType
:
storageType
,
};
setWorkspaceStorageSetting
(
update
);
await
workspaceSettingStore
.
setWorkspaceSetting
({
name
:
`
${
WorkspaceSettingPrefix
}${
WorkspaceSettingKey
.
WORKSPACE_SETTING_STORAGE
}
`
,
storageSetting
:
update
,
});
};
const
handleActivedExternalStorageIdChanged
=
async
(
activedExternalStorageId
:
number
)
=>
{
...
...
@@ -80,10 +101,14 @@ const StorageSection = () => {
activedExternalStorageId
:
activedExternalStorageId
,
};
setWorkspaceStorageSetting
(
update
);
};
const
saveWorkspaceStorageSetting
=
async
()
=>
{
await
workspaceSettingStore
.
setWorkspaceSetting
({
name
:
`
${
WorkspaceSettingPrefix
}${
WorkspaceSettingKey
.
WORKSPACE_SETTING_STORAGE
}
`
,
storageSetting
:
update
,
storageSetting
:
workspaceStorageSetting
,
});
toast
.
success
(
"Updated"
);
};
const
handleDeleteStorage
=
(
storage
:
ObjectStorage
)
=>
{
...
...
@@ -106,10 +131,9 @@ const StorageSection = () => {
return
(
<
div
className=
"w-full flex flex-col gap-2 pt-2 pb-4"
>
<
div
className=
"w-full flex flex-row justify-start items-center"
>
<
span
className=
"font-mono text-sm text-gray-400 mr-2 dark:text-gray-500"
>
{
t
(
"setting.storage-section.current-storage"
)
}
</
span
>
</
div
>
<
div
className=
"font-medium text-gray-700 dark:text-gray-500"
>
{
t
(
"setting.storage-section.current-storage"
)
}
</
div
>
<
RadioGroup
orientation=
"horizontal"
className=
"w-full"
value=
{
workspaceStorageSetting
.
storageType
}
onChange=
{
(
event
)
=>
{
...
...
@@ -117,28 +141,12 @@ const StorageSection = () => {
}
}
>
<
Radio
value=
{
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_DATABASE
}
label=
{
t
(
"setting.storage-section.type-database"
)
}
/>
<
div
>
<
Radio
value=
{
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_LOCAL
}
label=
{
t
(
"setting.storage-section.type-local"
)
}
/>
<
IconButton
size=
"sm"
onClick=
{
()
=>
showUpdateLocalStorageDialog
()
}
>
<
Icon
.
PenBox
className=
"w-4 h-auto"
/>
</
IconButton
>
</
div
>
<
Radio
value=
{
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_EXTERNAL
}
label=
{
"S3"
}
/>
</
RadioGroup
>
<
RadioGroup
className=
"w-full"
value=
{
workspaceStorageSetting
.
activedExternalStorageId
}
onChange=
{
(
event
)
=>
{
handleActivedExternalStorageIdChanged
(
Number
(
event
.
target
.
value
));
}
}
>
{
storageList
.
map
((
storage
)
=>
(
<
Radio
key=
{
storage
.
id
}
value=
{
storage
.
id
}
label=
{
storage
.
name
}
/>
))
}
<
Radio
value=
{
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_EXTERNAL
}
disabled=
{
storageList
.
length
===
0
}
label=
{
"S3"
}
/>
</
RadioGroup
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
div
className=
"flex flex-row items-center"
>
<
span
className=
"mr-1"
>
{
t
(
"setting.system-section.max-upload-size"
)
}
</
span
>
<
span
className=
"
text-gray-700 dark:text-gray-500
mr-1"
>
{
t
(
"setting.system-section.max-upload-size"
)
}
</
span
>
<
Tooltip
title=
{
t
(
"setting.system-section.max-upload-size-hint"
)
}
placement=
"top"
>
<
Icon
.
HelpCircle
className=
"w-4 h-auto"
/>
</
Tooltip
>
...
...
@@ -152,6 +160,36 @@ const StorageSection = () => {
onChange=
{
handleMaxUploadSizeChanged
}
/>
</
div
>
{
workspaceStorageSetting
.
storageType
===
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_LOCAL
&&
(
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
span
className=
"text-gray-700 dark:text-gray-500 mr-1"
>
Local file path template
</
span
>
<
Input
defaultValue=
{
workspaceStorageSetting
.
localStoragePathTemplate
}
placeholder=
"assets/
{
timestamp
}
_
{
filename
}"
onChange=
{
handleLocalStoragePathTemplateChanged
}
/>
</
div
>
)
}
{
workspaceStorageSetting
.
storageType
===
WorkspaceStorageSetting_StorageType
.
STORAGE_TYPE_EXTERNAL
&&
(
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
span
className=
"text-gray-700 dark:text-gray-500 mr-1"
>
Actived storage
</
span
>
<
Select
onChange=
{
(
_
,
value
)
=>
handleActivedExternalStorageIdChanged
(
value
as
number
)
}
defaultValue=
{
workspaceStorageSetting
.
activedExternalStorageId
}
>
{
storageList
.
map
((
storage
)
=>
(
<
Option
key=
{
storage
.
id
}
value=
{
storage
.
id
}
>
{
storage
.
name
}
</
Option
>
))
}
</
Select
>
</
div
>
)
}
<
div
>
<
Button
disabled=
{
!
allowSaveStorageSetting
}
onClick=
{
saveWorkspaceStorageSetting
}
>
{
t
(
"common.save"
)
}
</
Button
>
</
div
>
<
Divider
className=
"!my-2"
/>
<
div
className=
"mb-2 w-full flex flex-row justify-between items-center gap-1"
>
<
div
className=
"flex items-center gap-1"
>
...
...
web/src/components/UpdateLocalStorageDialog.tsx
deleted
100644 → 0
View file @
17e8fc54
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
WorkspaceSettingPrefix
,
useWorkspaceSettingStore
}
from
"@/store/v1"
;
import
{
WorkspaceSettingKey
,
WorkspaceStorageSetting
}
from
"@/types/proto/store/workspace_setting"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
LearnMore
from
"./LearnMore"
;
interface
Props
extends
DialogProps
{
confirmCallback
?:
()
=>
void
;
}
const
UpdateLocalStorageDialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
t
=
useTranslate
();
const
{
destroy
,
confirmCallback
}
=
props
;
const
workspaceSettingStore
=
useWorkspaceSettingStore
();
const
[
workspaceStorageSetting
,
setWorkspaceStorageSetting
]
=
useState
<
WorkspaceStorageSetting
>
(
WorkspaceStorageSetting
.
fromPartial
(
workspaceSettingStore
.
getWorkspaceSettingByKey
(
WorkspaceSettingKey
.
WORKSPACE_SETTING_STORAGE
)?.
storageSetting
||
{},
),
);
const
handleCloseBtnClick
=
()
=>
{
destroy
();
};
const
handleConfirmBtnClick
=
async
()
=>
{
try
{
await
workspaceSettingStore
.
setWorkspaceSetting
({
name
:
`
${
WorkspaceSettingPrefix
}${
WorkspaceSettingKey
.
WORKSPACE_SETTING_STORAGE
}
`
,
storageSetting
:
workspaceStorageSetting
,
});
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
toast
.
error
(
error
.
details
);
}
if
(
confirmCallback
)
{
confirmCallback
();
}
destroy
();
};
return
(
<>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
{
t
(
"setting.storage-section.update-local-path"
)
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
</
IconButton
>
</
div
>
<
div
className=
"dialog-content-container max-w-xs"
>
<
p
className=
"text-sm break-words mb-1"
>
{
t
(
"setting.storage-section.update-local-path-description"
)
}
</
p
>
<
div
className=
"flex flex-row items-center mb-2 gap-x-2"
>
<
span
className=
"text-sm text-gray-400 break-all"
>
e.g.
{
"assets/{timestamp}_{filename}"
}
</
span
>
<
LearnMore
url=
"https://usememos.com/docs/advanced-settings/local-storage"
/>
</
div
>
<
Input
className=
"mb-2"
placeholder=
{
t
(
"setting.storage-section.local-storage-path"
)
}
fullWidth
value=
{
workspaceStorageSetting
.
localStoragePath
}
onChange=
{
(
e
)
=>
setWorkspaceStorageSetting
({
...
workspaceStorageSetting
,
localStoragePath
:
e
.
target
.
value
})
}
/>
<
div
className=
"mt-2 w-full flex flex-row justify-end items-center space-x-1"
>
<
Button
variant=
"plain"
color=
"neutral"
onClick=
{
handleCloseBtnClick
}
>
{
t
(
"common.cancel"
)
}
</
Button
>
<
Button
onClick=
{
handleConfirmBtnClick
}
>
{
t
(
"common.update"
)
}
</
Button
>
</
div
>
</
div
>
</>
);
};
function
showUpdateLocalStorageDialog
(
confirmCallback
?:
()
=>
void
)
{
generateDialog
(
{
className
:
"update-local-storage-dialog"
,
dialogName
:
"update-local-storage-dialog"
,
},
UpdateLocalStorageDialog
,
{
confirmCallback
},
);
}
export
default
showUpdateLocalStorageDialog
;
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