chore: retire auto backup for sqlite

This commit is contained in:
Steven 2023-12-19 22:34:06 +08:00
parent b575064d47
commit e0cacfc6d6
29 changed files with 23 additions and 385 deletions

View File

@ -26,8 +26,6 @@ type SystemStatus struct {
DisablePublicMemos bool `json:"disablePublicMemos"`
// Max upload size.
MaxUploadSizeMiB int `json:"maxUploadSizeMiB"`
// Auto Backup Interval.
AutoBackupInterval int `json:"autoBackupInterval"`
// Additional style.
AdditionalStyle string `json:"additionalStyle"`
// Additional script.
@ -124,8 +122,6 @@ func (s *APIV1Service) GetSystemStatus(c echo.Context) error {
systemStatus.DisablePublicMemos = baseValue.(bool)
case SystemSettingMaxUploadSizeMiBName.String():
systemStatus.MaxUploadSizeMiB = int(baseValue.(float64))
case SystemSettingAutoBackupIntervalName.String():
systemStatus.AutoBackupInterval = int(baseValue.(float64))
case SystemSettingAdditionalStyleName.String():
systemStatus.AdditionalStyle = baseValue.(string)
case SystemSettingAdditionalScriptName.String():

View File

@ -40,8 +40,6 @@ const (
SystemSettingTelegramBotTokenName SystemSettingName = "telegram-bot-token"
// SystemSettingMemoDisplayWithUpdatedTsName is the name of memo display with updated ts.
SystemSettingMemoDisplayWithUpdatedTsName SystemSettingName = "memo-display-with-updated-ts"
// SystemSettingAutoBackupIntervalName is the name of auto backup interval as seconds.
SystemSettingAutoBackupIntervalName SystemSettingName = "auto-backup-interval"
// SystemSettingInstanceURLName is the name of instance url setting.
SystemSettingInstanceURLName SystemSettingName = "instance-url"
)
@ -244,14 +242,6 @@ func (upsert UpsertSystemSettingRequest) Validate() error {
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return errors.Errorf(systemSettingUnmarshalError, settingName)
}
case SystemSettingAutoBackupIntervalName:
var value int
if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil {
return errors.Errorf(systemSettingUnmarshalError, settingName)
}
if value < 0 {
return errors.New("must be positive")
}
case SystemSettingTelegramBotTokenName:
if upsert.Value == "" {
return nil

View File

@ -17,8 +17,6 @@
- [InboxMessage.Type](#memos-store-InboxMessage-Type)
- [store/system_setting.proto](#store_system_setting-proto)
- [BackupConfig](#memos-store-BackupConfig)
- [SystemSettingKey](#memos-store-SystemSettingKey)
- [store/user_setting.proto](#store_user_setting-proto)
@ -178,23 +176,6 @@
## store/system_setting.proto
<a name="memos-store-BackupConfig"></a>
### BackupConfig
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| enabled | [bool](#bool) | | enabled indicates whether backup is enabled. |
| cron | [string](#string) | | cron is the cron expression for backup. See https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format |
| max_keep | [int32](#int32) | | max_keep is the maximum number of backups to keep. |
@ -206,7 +187,6 @@
| Name | Number | Description |
| ---- | ------ | ----------- |
| SYSTEM_SETTING_KEY_UNSPECIFIED | 0 | |
| BACKUP_CONFIG | 1 | BackupConfig is the key for auto-backup configuration. |

View File

@ -24,19 +24,15 @@ type SystemSettingKey int32
const (
SystemSettingKey_SYSTEM_SETTING_KEY_UNSPECIFIED SystemSettingKey = 0
// BackupConfig is the key for auto-backup configuration.
SystemSettingKey_BACKUP_CONFIG SystemSettingKey = 1
)
// Enum value maps for SystemSettingKey.
var (
SystemSettingKey_name = map[int32]string{
0: "SYSTEM_SETTING_KEY_UNSPECIFIED",
1: "BACKUP_CONFIG",
}
SystemSettingKey_value = map[string]int32{
"SYSTEM_SETTING_KEY_UNSPECIFIED": 0,
"BACKUP_CONFIG": 1,
}
)
@ -67,99 +63,26 @@ func (SystemSettingKey) EnumDescriptor() ([]byte, []int) {
return file_store_system_setting_proto_rawDescGZIP(), []int{0}
}
type BackupConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// enabled indicates whether backup is enabled.
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// cron is the cron expression for backup. See https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format
Cron string `protobuf:"bytes,2,opt,name=cron,proto3" json:"cron,omitempty"`
// max_keep is the maximum number of backups to keep.
MaxKeep int32 `protobuf:"varint,3,opt,name=max_keep,json=maxKeep,proto3" json:"max_keep,omitempty"`
}
func (x *BackupConfig) Reset() {
*x = BackupConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_store_system_setting_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BackupConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BackupConfig) ProtoMessage() {}
func (x *BackupConfig) ProtoReflect() protoreflect.Message {
mi := &file_store_system_setting_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BackupConfig.ProtoReflect.Descriptor instead.
func (*BackupConfig) Descriptor() ([]byte, []int) {
return file_store_system_setting_proto_rawDescGZIP(), []int{0}
}
func (x *BackupConfig) GetEnabled() bool {
if x != nil {
return x.Enabled
}
return false
}
func (x *BackupConfig) GetCron() string {
if x != nil {
return x.Cron
}
return ""
}
func (x *BackupConfig) GetMaxKeep() int32 {
if x != nil {
return x.MaxKeep
}
return 0
}
var File_store_system_setting_proto protoreflect.FileDescriptor
var file_store_system_setting_proto_rawDesc = []byte{
0x0a, 0x1a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x6d, 0x65,
0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x57, 0x0a, 0x0c, 0x42, 0x61, 0x63,
0x6b, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61,
0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x6b,
0x65, 0x65, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x4b, 0x65,
0x65, 0x70, 0x2a, 0x49, 0x0a, 0x10, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x65, 0x74, 0x74,
0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d,
0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x53,
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x42, 0x41,
0x43, 0x4b, 0x55, 0x50, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x42, 0x9d, 0x01,
0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72,
0x65, 0x42, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d,
0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f,
0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73,
0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53,
0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f,
0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2a, 0x36, 0x0a, 0x10, 0x53, 0x79, 0x73,
0x74, 0x65, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a,
0x1e, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f,
0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
0x00, 0x42, 0x9d, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73,
0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e,
0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d,
0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d,
0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73,
0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0xea, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72,
0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -175,10 +98,8 @@ func file_store_system_setting_proto_rawDescGZIP() []byte {
}
var file_store_system_setting_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_store_system_setting_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_store_system_setting_proto_goTypes = []interface{}{
(SystemSettingKey)(0), // 0: memos.store.SystemSettingKey
(*BackupConfig)(nil), // 1: memos.store.BackupConfig
}
var file_store_system_setting_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
@ -193,34 +114,19 @@ func file_store_system_setting_proto_init() {
if File_store_system_setting_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_store_system_setting_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BackupConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_store_system_setting_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_store_system_setting_proto_goTypes,
DependencyIndexes: file_store_system_setting_proto_depIdxs,
EnumInfos: file_store_system_setting_proto_enumTypes,
MessageInfos: file_store_system_setting_proto_msgTypes,
}.Build()
File_store_system_setting_proto = out.File
file_store_system_setting_proto_rawDesc = nil

View File

@ -6,16 +6,4 @@ option go_package = "gen/store";
enum SystemSettingKey {
SYSTEM_SETTING_KEY_UNSPECIFIED = 0;
// BackupConfig is the key for auto-backup configuration.
BACKUP_CONFIG = 1;
}
message BackupConfig {
// enabled indicates whether backup is enabled.
bool enabled = 1;
// cron is the cron expression for backup. See https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format
string cron = 2;
// max_keep is the maximum number of backups to keep.
int32 max_keep = 3;
}

View File

@ -19,7 +19,6 @@ import (
"github.com/usememos/memos/server/frontend"
"github.com/usememos/memos/server/integration"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/server/service/backup"
"github.com/usememos/memos/server/service/metric"
versionchecker "github.com/usememos/memos/server/service/version_checker"
"github.com/usememos/memos/store"
@ -34,8 +33,7 @@ type Server struct {
Store *store.Store
// Asynchronous runners.
backupRunner *backup.BackupRunner
telegramBot *telegram.Bot
telegramBot *telegram.Bot
}
func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
@ -53,10 +51,6 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
telegramBot: telegram.NewBotWithHandler(integration.NewTelegramHandler(store)),
}
if profile.Driver == "sqlite" {
s.backupRunner = backup.NewBackupRunner(store)
}
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: `{"time":"${time_rfc3339}","latency":"${latency_human}",` +
`"method":"${method}","uri":"${uri}",` +
@ -121,10 +115,6 @@ func (s *Server) Start(ctx context.Context) error {
go versionchecker.NewVersionChecker(s.Store, s.Profile).Start(ctx)
go s.telegramBot.Start(ctx)
if s.backupRunner != nil {
go s.backupRunner.Run(ctx)
}
metric.Enqueue("server start")
return s.e.Start(fmt.Sprintf("%s:%d", s.Profile.Addr, s.Profile.Port))
}

View File

@ -1,94 +0,0 @@
package backup
import (
"context"
"fmt"
"os"
"strconv"
"time"
"go.uber.org/zap"
apiv1 "github.com/usememos/memos/api/v1"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/store"
)
// nolint
type BackupRunner struct {
Store *store.Store
}
func NewBackupRunner(store *store.Store) *BackupRunner {
return &BackupRunner{
Store: store,
}
}
const MaxBackupFiles = 5
func (r *BackupRunner) Run(ctx context.Context) {
intervalStr := r.Store.GetSystemSettingValueWithDefault(ctx, apiv1.SystemSettingAutoBackupIntervalName.String(), "")
if intervalStr == "" {
log.Debug("no SystemSettingAutoBackupIntervalName setting, disable auto backup")
return
}
interval, err := strconv.Atoi(intervalStr)
if err != nil || interval < 0 {
log.Error(fmt.Sprintf("invalid SystemSettingAutoBackupIntervalName value %s, disable auto backup", intervalStr), zap.Error(err))
return
}
if interval == 0 {
println("AutoBackupIntervalName value is 0, disable auto backup")
return
}
log.Info("enable auto backup every " + intervalStr + " seconds")
ticker := time.NewTicker(time.Duration(interval) * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
log.Info("stop auto backup graceful.")
return
case <-ticker.C:
}
filename := r.Store.Profile.DSN + ".bak"
if err := rotateFiles(filename, MaxBackupFiles); err != nil {
log.Error("fail to rotate backup files", zap.Error(err))
continue
}
log.Info(fmt.Sprintf("create backup to %s", filename))
if err := r.Store.BackupTo(ctx, filename); err != nil {
log.Error("fail to create backup", zap.Error(err))
}
}
}
func rotateFiles(filename string, cnt int) error {
// Generate suffix slices of history files like "",".1",".2",".3"...
ss := make([]string, cnt-1)
for i := 1; i < len(ss); i++ {
ss[i] = fmt.Sprintf(".%d", i)
}
// Iterate through the suffix slices and rename the files
for i := len(ss) - 1; i >= 0; i-- {
from := filename + ss[i]
to := filename + "." + strconv.Itoa(i+1)
log.Info("rotate file", zap.String("from", from), zap.String("to", to))
err := os.Rename(from, to)
if err != nil && !os.IsNotExist(err) {
return err
}
}
return nil
}

View File

@ -75,10 +75,6 @@ func (d *DB) Vacuum(ctx context.Context) error {
return tx.Commit()
}
func (*DB) BackupTo(context.Context, string) error {
return errors.New("Please use mysqldump to backup")
}
func (d *DB) GetCurrentDBSize(ctx context.Context) (int64, error) {
query := "SELECT SUM(`data_length` + `index_length`) AS `size` " +
" FROM information_schema.TABLES" +

View File

@ -74,10 +74,6 @@ func (d *DB) Vacuum(ctx context.Context) error {
return tx.Commit()
}
func (*DB) BackupTo(context.Context, string) error {
return errors.New("Please use postgresdump to backup")
}
func (*DB) GetCurrentDBSize(context.Context) (int64, error) {
return 0, errors.New("unimplemented")
}

View File

@ -72,7 +72,7 @@ func (d *DB) Migrate(ctx context.Context) error {
if version.IsVersionGreaterThan(version.GetSchemaVersion(currentVersion), latestMigrationHistoryVersion) {
minorVersionList := getMinorVersionList()
// backup the raw database file before migration
// Backup the raw database file before migration.
rawBytes, err := os.ReadFile(d.profile.DSN)
if err != nil {
return errors.Wrap(err, "failed to read raw database file")
@ -94,7 +94,7 @@ func (d *DB) Migrate(ctx context.Context) error {
}
println("end migrate")
// remove the created backup db file after migrate succeed
// Remove the created backup db file after migrate succeed.
if err := os.Remove(backupDBFilePath); err != nil {
println(fmt.Sprintf("Failed to remove temp database file, err %v", err))
}

View File

@ -8,7 +8,9 @@ import (
"github.com/pkg/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"modernc.org/sqlite"
// Import the SQLite driver.
_ "modernc.org/sqlite"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
@ -103,43 +105,6 @@ func vacuumImpl(ctx context.Context, tx *sql.Tx) error {
return nil
}
func (d *DB) BackupTo(ctx context.Context, filename string) error {
conn, err := d.db.Conn(ctx)
if err != nil {
return errors.Wrap(err, "fail to open new connection")
}
defer conn.Close()
err = conn.Raw(func(driverConn any) error {
type backuper interface {
NewBackup(string) (*sqlite.Backup, error)
}
backupConn, ok := driverConn.(backuper)
if !ok {
return errors.New("db connection is not a sqlite backuper")
}
bck, err := backupConn.NewBackup(filename)
if err != nil {
return errors.Wrap(err, "fail to create sqlite backup")
}
for more := true; more; {
more, err = bck.Step(-1)
if err != nil {
return errors.Wrap(err, "fail to execute sqlite backup")
}
}
return bck.Finish()
})
if err != nil {
return errors.Wrap(err, "fail to backup")
}
return nil
}
func (d *DB) GetCurrentDBSize(context.Context) (int64, error) {
fi, err := os.Stat(d.profile.DSN)
if err != nil {

View File

@ -15,7 +15,6 @@ type Driver interface {
Migrate(ctx context.Context) error
Vacuum(ctx context.Context) error
BackupTo(ctx context.Context, filename string) error
// current file is driver
GetCurrentDBSize(ctx context.Context) (int64, error)

View File

@ -25,10 +25,6 @@ func New(driver Driver, profile *profile.Profile) *Store {
}
}
func (s *Store) BackupTo(ctx context.Context, filename string) error {
return s.driver.BackupTo(ctx, filename)
}
func (s *Store) Vacuum(ctx context.Context) error {
return s.driver.Vacuum(ctx)
}

View File

@ -5,8 +5,6 @@ import (
"fmt"
"testing"
// mysql driver.
_ "github.com/go-sql-driver/mysql"
// sqlite driver.
_ "modernc.org/sqlite"

View File

@ -20,7 +20,6 @@ interface State {
additionalStyle: string;
additionalScript: string;
maxUploadSizeMiB: number;
autoBackupInterval: number;
memoDisplayWithUpdatedTs: boolean;
}
@ -36,7 +35,6 @@ const SystemSection = () => {
additionalScript: systemStatus.additionalScript,
disablePublicMemos: systemStatus.disablePublicMemos,
maxUploadSizeMiB: systemStatus.maxUploadSizeMiB,
autoBackupInterval: systemStatus.autoBackupInterval,
memoDisplayWithUpdatedTs: systemStatus.memoDisplayWithUpdatedTs,
});
const [telegramBotToken, setTelegramBotToken] = useState<string>("");
@ -69,7 +67,6 @@ const SystemSection = () => {
additionalScript: systemStatus.additionalScript,
disablePublicMemos: systemStatus.disablePublicMemos,
maxUploadSizeMiB: systemStatus.maxUploadSizeMiB,
autoBackupInterval: systemStatus.autoBackupInterval,
memoDisplayWithUpdatedTs: systemStatus.memoDisplayWithUpdatedTs,
});
}, [systemStatus]);
@ -246,30 +243,6 @@ const SystemSection = () => {
event.target.select();
};
const handleAutoBackupIntervalChanged = async (event: React.FocusEvent<HTMLInputElement>) => {
// fixes cursor skipping position on mobile
event.target.selectionEnd = event.target.value.length;
let num = parseInt(event.target.value);
if (Number.isNaN(num)) {
num = 0;
}
setState({
...state,
autoBackupInterval: num,
});
event.target.value = num.toString();
globalStore.setSystemStatus({ autoBackupInterval: num });
await api.upsertSystemSetting({
name: "auto-backup-interval",
value: JSON.stringify(num),
});
};
const handleAutoBackupIntervalFocus = (event: React.FocusEvent<HTMLInputElement>) => {
event.target.select();
};
return (
<div className="section-container system-section-container">
<p className="title-text">{t("common.basic")}</p>
@ -319,23 +292,6 @@ const SystemSection = () => {
onChange={handleMaxUploadSizeChanged}
/>
</div>
<div className="form-label">
<div className="flex flex-row items-center">
<span className="text-sm mr-1">{t("setting.system-section.auto-backup-interval")}</span>
<Tooltip title={t("setting.system-section.auto-backup-interval-hint")} placement="top">
<Icon.HelpCircle className="w-4 h-auto" />
</Tooltip>
</div>
<Input
className="w-16"
sx={{
fontFamily: "monospace",
}}
defaultValue={state.autoBackupInterval}
onFocus={handleAutoBackupIntervalFocus}
onChange={handleAutoBackupIntervalChanged}
/>
</div>
<Divider className="!mt-3 !my-4" />
<div className="form-label">
<div className="flex flex-row items-center">

View File

@ -2,7 +2,7 @@
@apply relative flex flex-col justify-start items-start w-full p-4 pt-3 mb-2 bg-white dark:bg-zinc-700 rounded-lg border border-white dark:border-zinc-600 hover:border-gray-200 dark:hover:border-zinc-600;
&.pinned {
@apply border-gray-200 border-2 dark:border-zinc-600;
@apply border-gray-200 border dark:border-zinc-600;
}
> .memo-top-wrapper {

View File

@ -327,8 +327,6 @@
"additional-style": "Zusätzlicher Stil",
"additional-style-placeholder": "Zusätzliches CSS",
"allow-user-signup": "Erlaube Registrierung neuer Mitglieder",
"auto-backup-interval": "Intervall für automatische Sicherung (Sekunden)",
"auto-backup-interval-hint": "Setze den Wert auf 0, um die automatische Sicherung zu deaktivieren. Nach Änderung dieses Wertes ist ein Neustart erforderlich.",
"customize-server": {
"appearance": "Erscheinungsbild",
"default": "Standard: memos",

View File

@ -255,8 +255,6 @@
"disable-public-memos": "Disable public memos",
"max-upload-size": "Maximum upload size (MiB)",
"max-upload-size-hint": "Recommended value is 32 MiB.",
"auto-backup-interval": "Auto backup interval (seconds)",
"auto-backup-interval-hint": "Set 0 to disable auto backup. Reboot is required after changing this value.",
"additional-style": "Additional style",
"additional-script": "Additional script",
"additional-style-placeholder": "Additional CSS code",

View File

@ -335,8 +335,6 @@
"additional-style": "Style supplémentaire",
"additional-style-placeholder": "Codes CSS supplémentaires",
"allow-user-signup": "Autoriser l'inscription des utilisateurs",
"auto-backup-interval": "Intervalle de sauvegarde automatique (secondes)",
"auto-backup-interval-hint": "La valeur 0 désactive la sauvegarde automatique. Un redémarrage est nécessaire après avoir modifié cette valeur.",
"customize-server": {
"appearance": "Apparence du Serveur",
"default": "Par défaut memos",

View File

@ -335,8 +335,6 @@
"additional-style": "Dodatni stil",
"additional-style-placeholder": "Dodatni CSS kod",
"allow-user-signup": "Dopusti registraciju drugih korisnika",
"auto-backup-interval": "Interval u kojem će se izvršavati automatski backup (u sekundama)",
"auto-backup-interval-hint": "Unesi 0 kako bi onemogućio automatski backup. Nakon mijenjanja ove vrijednosti potreban je reboot.",
"customize-server": {
"appearance": "Izgled Servera",
"default": "Osnovno je memoi",

View File

@ -320,8 +320,6 @@
"additional-style": "Stile aggiuntivo",
"additional-style-placeholder": "Codice CSS aggiuntivo",
"allow-user-signup": "Consenti registrazione utente",
"auto-backup-interval": "Intervallo auto backup (secondi)",
"auto-backup-interval-hint": "Inserire 0 per disattivare backup automatici. È richiesto il riavvio per salvare l'impostazione.",
"customize-server": {
"appearance": "Aspetto server",
"default": "Preferinito è Memos",

View File

@ -318,8 +318,6 @@
"additional-style": "追加CSS",
"additional-style-placeholder": "CSSのコードを追加してください。",
"allow-user-signup": "ユーザー登録を有効にする",
"auto-backup-interval": "自動バックアップの間隔(秒)",
"auto-backup-interval-hint": "自動バックアップを無効にするには0を設定してください。この値を変更した後、再起動が必要です。",
"customize-server": {
"appearance": "サーバーの外観",
"default": "デフォルトではmemosです",

View File

@ -331,8 +331,6 @@
"additional-style": "추가적인 스타일",
"additional-style-placeholder": "추가적인 CSS 코드",
"allow-user-signup": "회원등록 허용",
"auto-backup-interval": "자동 백업 주기 (초)",
"auto-backup-interval-hint": "0으로 설정하면 자동 백업을 비활성화합니다. 이 설정을 바꾼 뒤에는 재시작이 필요합니다.",
"customize-server": {
"appearance": "서버 테마",
"default": "기본값은 memos",

View File

@ -182,8 +182,6 @@
"disable-public-memos": "Openbare memos uitzetten",
"max-upload-size": "Maximum uploadgrootte (MiB)",
"max-upload-size-hint": "32 MiB wordt aangeraden.",
"auto-backup-interval": "Automatische backupinterval (seconden)",
"auto-backup-interval-hint": "Kies 0 om de automatische backup uit te zetten. Herstart van memos is nodig na deze aanpassing.",
"display-with-updated-time": "Laten zien met bewerkte tijd",
"telegram-bot-token": "Telegram bot token",
"telegram-bot-token-description": "Telegram bot token of API proxy zoals `http://.../bot<token>`",

View File

@ -335,8 +335,6 @@
"additional-style": "Estilo adicional",
"additional-style-placeholder": "Código CSS adicional",
"allow-user-signup": "Permitir registro de usuário",
"auto-backup-interval": "Intervalo para backup automático (segundos)",
"auto-backup-interval-hint": "Defina como 0 para desabilitar o backup automático. É necessário reiniciar após alterar esse valor.",
"customize-server": {
"appearance": "Aparência do servidor",
"default": "O padrão é memos",

View File

@ -331,8 +331,6 @@
"additional-style": "自定义样式",
"additional-style-placeholder": "自定义 CSS 代码",
"allow-user-signup": "允许用户注册",
"auto-backup-interval": "自动备份间隔(单位:秒)",
"auto-backup-interval-hint": "设置为 0 禁止自动备份,重启后生效。",
"customize-server": {
"appearance": "服务器外观",
"default": "默认为 memos",

View File

@ -335,8 +335,6 @@
"additional-style": "自訂樣式",
"additional-style-placeholder": "自訂 CSS 代碼",
"allow-user-signup": "允許使用者註冊",
"auto-backup-interval": "自動備份間隔(單位:秒)",
"auto-backup-interval-hint": "設定為 0 則禁止自動備份,需重新啟動後生效。",
"customize-server": {
"appearance": "伺服器外觀",
"default": "預設為 memos",

View File

@ -16,7 +16,6 @@ export const initialGlobalState = async () => {
disablePasswordLogin: false,
disablePublicMemos: false,
maxUploadSizeMiB: 0,
autoBackupInterval: 0,
additionalStyle: "",
additionalScript: "",
memoDisplayWithUpdatedTs: false,

View File

@ -21,7 +21,6 @@ interface SystemStatus {
disablePasswordLogin: boolean;
disablePublicMemos: boolean;
maxUploadSizeMiB: number;
autoBackupInterval: number;
additionalStyle: string;
additionalScript: string;
customizedProfile: CustomizedProfile;