feat: add max upload size setting to UI & UI improvements (#1646)

* Add preliminar Windows support for both
development and production environments.

Default profile.Data will be set to "C:\ProgramData\memos" on Windows.
Folder will be created if it does not exist, as this behavior is
expected for Windows applications.

System service installation can be achieved with third-party tools,
explained in docs/windows-service.md.

Not sure if it's worth using https://github.com/kardianos/service
to make service support built-in.

This could be a nice addition alongside #1583 (add Windows artifacts)

* feat: improve Windows support

- Fix local file storage path handling on Windows

- Improve Windows dev script

* feat: add max upload size setting to UI & more

- feat: add max upload size setting to UI

- feat: max upload size setting is checked on UI during upload,
but also enforced by the server

- fix: overflowing mobile layout for Create SSO, Create Storage
and other Settings dialogs

- feat: add HelpButton component with some links to docs were appropriate

- remove LearnMore component in favor of HelpButton

- refactor: change some if/else to switch statements

- refactor: inline some err == nil checks

! Existing databases without the new setting 'max-upload-size-mib'
will show an upload error, but this can be user-fixed by simply
setting the value on system settings UI.

* improvements requested by @boojack
This commit is contained in:
Lincoln Nogueira
2023-05-13 11:27:28 -03:00
committed by GitHub
parent 5c5199920e
commit 96021e518a
20 changed files with 591 additions and 204 deletions

View File

@ -2,7 +2,6 @@ package api
import (
"encoding/json"
"errors"
"fmt"
"golang.org/x/exp/slices"
@ -21,6 +20,8 @@ const (
SystemSettingIgnoreUpgradeName SystemSettingName = "ignore-upgrade"
// SystemSettingDisablePublicMemosName is the name of disable public memos setting.
SystemSettingDisablePublicMemosName SystemSettingName = "disable-public-memos"
// SystemSettingMaxUploadSizeMiBName is the name of max upload size setting.
SystemSettingMaxUploadSizeMiBName SystemSettingName = "max-upload-size-mib"
// SystemSettingAdditionalStyleName is the name of additional style.
SystemSettingAdditionalStyleName SystemSettingName = "additional-style"
// SystemSettingAdditionalScriptName is the name of additional script.
@ -68,6 +69,8 @@ func (key SystemSettingName) String() string {
return "ignore-upgrade"
case SystemSettingDisablePublicMemosName:
return "disable-public-memos"
case SystemSettingMaxUploadSizeMiBName:
return "max-upload-size-mib"
case SystemSettingAdditionalStyleName:
return "additional-style"
case SystemSettingAdditionalScriptName:
@ -97,40 +100,50 @@ type SystemSettingUpsert struct {
Description string `json:"description"`
}
const systemSettingUnmarshalError = `failed to unmarshal value from system setting "%v"`
func (upsert SystemSettingUpsert) Validate() error {
if upsert.Name == SystemSettingServerIDName {
return errors.New("update server id is not allowed")
} else if upsert.Name == SystemSettingAllowSignUpName {
value := false
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting allow signup value")
switch settingName := upsert.Name; settingName {
case SystemSettingServerIDName:
return fmt.Errorf("updating %v is not allowed", settingName)
case SystemSettingAllowSignUpName:
var value bool
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else if upsert.Name == SystemSettingIgnoreUpgradeName {
value := false
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting ignore upgrade value")
case SystemSettingIgnoreUpgradeName:
var value bool
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else if upsert.Name == SystemSettingDisablePublicMemosName {
value := false
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting disable public memos value")
case SystemSettingDisablePublicMemosName:
var value bool
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else if upsert.Name == SystemSettingAdditionalStyleName {
value := ""
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting additional style value")
case SystemSettingMaxUploadSizeMiBName:
var value int
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else if upsert.Name == SystemSettingAdditionalScriptName {
value := ""
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting additional script value")
case SystemSettingAdditionalStyleName:
var value string
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else if upsert.Name == SystemSettingCustomizedProfileName {
case SystemSettingAdditionalScriptName:
var value string
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
case SystemSettingCustomizedProfileName:
customizedProfile := CustomizedProfile{
Name: "memos",
LogoURL: "",
@ -139,36 +152,37 @@ func (upsert SystemSettingUpsert) Validate() error {
Appearance: "system",
ExternalURL: "",
}
err := json.Unmarshal([]byte(upsert.Value), &customizedProfile)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting customized profile value")
if err := json.Unmarshal([]byte(upsert.Value), &customizedProfile); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
if !slices.Contains(UserSettingLocaleValue, customizedProfile.Locale) {
return fmt.Errorf("invalid locale value")
return fmt.Errorf(`invalid locale value for system setting "%v"`, settingName)
}
if !slices.Contains(UserSettingAppearanceValue, customizedProfile.Appearance) {
return fmt.Errorf("invalid appearance value")
return fmt.Errorf(`invalid appearance value for system setting "%v"`, settingName)
}
} else if upsert.Name == SystemSettingStorageServiceIDName {
case SystemSettingStorageServiceIDName:
value := DatabaseStorage
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting storage service id value")
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
return nil
} else if upsert.Name == SystemSettingLocalStoragePathName {
case SystemSettingLocalStoragePathName:
value := ""
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting local storage path value")
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else if upsert.Name == SystemSettingOpenAIConfigName {
case SystemSettingOpenAIConfigName:
value := OpenAIConfig{}
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting openai api config value")
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return fmt.Errorf(systemSettingUnmarshalError, settingName)
}
} else {
default:
return fmt.Errorf("invalid system setting name")
}