diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/dockerimage.yml
index fe51bc720..dd654fac9 100644
--- a/.github/workflows/dockerimage.yml
+++ b/.github/workflows/dockerimage.yml
@@ -16,6 +16,22 @@ jobs:
contents: read
steps:
+ - name: Free Disk Space (Ubuntu)
+ uses: jlumbroso/free-disk-space@main
+ with:
+ # this might remove tools that are actually needed,
+ # if set to "true" but frees about 6 GB
+ tool-cache: false
+
+ # all of these default to true, but feel free to set to
+ # "false" if necessary for your workflow
+ android: true
+ dotnet: true
+ haskell: true
+ large-packages: true
+ docker-images: true
+ swap-storage: true
+
- name: Check out the repo
uses: actions/checkout@v3
diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json
index 019895b81..930fbaaa6 100644
--- a/app/appearance/langs/en_US.json
+++ b/app/appearance/langs/en_US.json
@@ -162,11 +162,11 @@
"flashcardMark": "Mark Carding",
"flashcardMarkTip": "After enabling, the mark is recognized as fill in the blank",
"flashcardList": "List Carding",
- "flashcardListTip": "After enabling, the first list item of a list is recognized as a question, and the rest of the lite items are recognized as answers",
+ "flashcardListTip": "After enabling, the first list item of a list is recognized as a question, and the rest of the list items are recognized as answers",
"flashcardSuperBlock": "Super Block Carding",
"flashcardSuperBlockTip": "After enabling, the first child block of a super block is recognized as a question, and the rest of the child blocks are recognized as answers",
"flashcardHeading": "Heading Block Carding",
- "flashcardHeadingTip": "After enabling, the heading block is recognized as a question, and the rest of the child blocks are recognized as answers",
+ "flashcardHeadingTip": "After enabling, the heading block is recognized as a question, and the blocks below are recognized as answers",
"flashcardDeck": "Deck",
"flashcardDeckTip": "After enabling, the card deck classification is supported. This is a historical compatibility option, it is not recommended to enable it unless necessary, and it is recommended to use Quick make card",
"flashcardFSRSParamRequestRetention": "FSRS Request Retention",
diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json
index d5dad7418..fbbedc9c3 100644
--- a/app/appearance/langs/es_ES.json
+++ b/app/appearance/langs/es_ES.json
@@ -166,7 +166,7 @@
"flashcardSuperBlock": "Carda de súper bloque",
"flashcardSuperBlockTip": "Después de habilitar, el primer bloque secundario de un súper bloque se reconoce como una pregunta y el resto de los bloques secundarios se reconocen como respuestas",
"flashcardHeading": "Tarjeta de bloque de encabezado",
- "flashcardHeadingTip": "Después de habilitarlo, el bloque de encabezado se reconoce como una pregunta y el resto de los bloques secundarios se reconocen como respuestas",
+ "flashcardHeadingTip": "Después de habilitarlo, el bloque de encabezado se reconoce como una pregunta y los bloques siguientes se reconocen como respuestas.",
"flashcardDeck": "Mazo",
"flashcardDeckTip": "Después de habilitar, se admite la clasificación del mazo de cartas. Esta es una opción de compatibilidad histórica, no se recomienda habilitarla a menos que sea necesario, y se recomienda usar Quick make card",
"flashcardFSRSParamRequestRetention": "Retención de solicitud FSRS",
diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json
index 8158167d9..99b1e538f 100644
--- a/app/appearance/langs/fr_FR.json
+++ b/app/appearance/langs/fr_FR.json
@@ -166,7 +166,7 @@
"flashcardSuperBlock": "Carte Super Block",
"flashcardSuperBlockTip": "Après l'activation, le premier bloc enfant d'un super bloc est reconnu comme une question, et les autres blocs enfants sont reconnus comme des réponses",
"flashcardHeading": "Carte de bloc d'en-tête",
- "flashcardHeadingTip": "Après activation, le bloc d'en-tête est reconnu comme une question et le reste des blocs enfants sont reconnus comme des réponses",
+ "flashcardHeadingTip": "Après activation, le bloc d'en-tête est reconnu comme une question et les blocs ci-dessous sont reconnus comme des réponses",
"flashcardDeck": "Deck",
"flashcardDeckTip": "Après l'activation, la classification du jeu de cartes est prise en charge. Il s'agit d'une option de compatibilité historique, il n'est pas recommandé de l'activer sauf si nécessaire, et il est recommandé d'utiliser Quick make card",
"flashcardFSRSParamRequestRetention": "Rétention des requêtes FSRS",
diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json
index c795dfb99..d3fd0a0d4 100644
--- a/app/appearance/langs/zh_CHT.json
+++ b/app/appearance/langs/zh_CHT.json
@@ -166,7 +166,7 @@
"flashcardSuperBlock": "超級塊制卡",
"flashcardSuperBlockTip": "啟用後支持超級塊制卡,超級塊的第一個子塊被識別為問題,其餘子塊識別為答案",
"flashcardHeading": "標題塊製卡",
- "flashcardHeadingTip": "啟用後支援標題區塊製卡,標題區塊被識別為問題,其餘子區塊識別為答案",
+ "flashcardHeadingTip": "啟用後支援標題塊製卡,標題塊被識別為問題,下方塊識別為答案",
"flashcardDeck": "卡包",
"flashcardDeckTip": "啟用後支持卡包分類。這是一個歷史兼容選項,如無必要建議不要啟用,推薦使用 快速制卡",
"flashcardFSRSParamRequestRetention": "FSRS Request Retention",
diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json
index aa0feaa90..a30d8b6af 100644
--- a/app/appearance/langs/zh_CN.json
+++ b/app/appearance/langs/zh_CN.json
@@ -166,7 +166,7 @@
"flashcardSuperBlock": "超级块制卡",
"flashcardSuperBlockTip": "启用后支持超级块制卡,超级块的第一个子块被识别为问题,其余子块识别为答案",
"flashcardHeading": "标题块制卡",
- "flashcardHeadingTip": "启用后支持标题块制卡,标题块被识别为问题,其余子块识别为答案",
+ "flashcardHeadingTip": "启用后支持标题块制卡,标题块被识别为问题,下方块识别为答案",
"flashcardDeck": "卡包",
"flashcardDeckTip": "启用后支持卡包分类。这是一个历史兼容选项,如无必要建议不要启用,推荐使用 快速制卡",
"flashcardFSRSParamRequestRetention": "FSRS Request Retention",
diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml
index 8f6a9e85d..70048e3b0 100644
--- a/app/pnpm-lock.yaml
+++ b/app/pnpm-lock.yaml
@@ -1423,12 +1423,12 @@ packages:
peerDependencies:
webpack: ^5.0.0
dependencies:
- icss-utils: 5.1.0(postcss@8.4.14)
- postcss: 8.4.14
- postcss-modules-extract-imports: 3.0.0(postcss@8.4.14)
- postcss-modules-local-by-default: 4.0.0(postcss@8.4.14)
- postcss-modules-scope: 3.0.0(postcss@8.4.14)
- postcss-modules-values: 4.0.0(postcss@8.4.14)
+ icss-utils: 5.1.0(postcss@8.4.31)
+ postcss: 8.4.31
+ postcss-modules-extract-imports: 3.0.0(postcss@8.4.31)
+ postcss-modules-local-by-default: 4.0.0(postcss@8.4.31)
+ postcss-modules-scope: 3.0.0(postcss@8.4.31)
+ postcss-modules-values: 4.0.0(postcss@8.4.31)
postcss-value-parser: 4.2.0
semver: 7.3.8
webpack: 5.76.0(webpack-cli@4.10.0)
@@ -2356,13 +2356,13 @@ packages:
safer-buffer: 2.1.2
dev: true
- /icss-utils@5.1.0(postcss@8.4.14):
+ /icss-utils@5.1.0(postcss@8.4.31):
resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
dependencies:
- postcss: 8.4.14
+ postcss: 8.4.31
dev: true
/ieee754@1.2.1:
@@ -2782,8 +2782,8 @@ packages:
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
- /nanoid@3.3.4:
- resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
+ /nanoid@3.3.6:
+ resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: true
@@ -2995,45 +2995,45 @@ packages:
xmlbuilder: 15.1.1
dev: true
- /postcss-modules-extract-imports@3.0.0(postcss@8.4.14):
+ /postcss-modules-extract-imports@3.0.0(postcss@8.4.31):
resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
dependencies:
- postcss: 8.4.14
+ postcss: 8.4.31
dev: true
- /postcss-modules-local-by-default@4.0.0(postcss@8.4.14):
+ /postcss-modules-local-by-default@4.0.0(postcss@8.4.31):
resolution: {integrity: sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
dependencies:
- icss-utils: 5.1.0(postcss@8.4.14)
- postcss: 8.4.14
+ icss-utils: 5.1.0(postcss@8.4.31)
+ postcss: 8.4.31
postcss-selector-parser: 6.0.10
postcss-value-parser: 4.2.0
dev: true
- /postcss-modules-scope@3.0.0(postcss@8.4.14):
+ /postcss-modules-scope@3.0.0(postcss@8.4.31):
resolution: {integrity: sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
dependencies:
- postcss: 8.4.14
+ postcss: 8.4.31
postcss-selector-parser: 6.0.10
dev: true
- /postcss-modules-values@4.0.0(postcss@8.4.14):
+ /postcss-modules-values@4.0.0(postcss@8.4.31):
resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
dependencies:
- icss-utils: 5.1.0(postcss@8.4.14)
- postcss: 8.4.14
+ icss-utils: 5.1.0(postcss@8.4.31)
+ postcss: 8.4.31
dev: true
/postcss-selector-parser@6.0.10:
@@ -3048,11 +3048,11 @@ packages:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
dev: true
- /postcss@8.4.14:
- resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==}
+ /postcss@8.4.31:
+ resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
- nanoid: 3.3.4
+ nanoid: 3.3.6
picocolors: 1.0.0
source-map-js: 1.0.2
dev: true
diff --git a/kernel/job/cron.go b/kernel/job/cron.go
index 7026d92be..ea377c158 100644
--- a/kernel/job/cron.go
+++ b/kernel/job/cron.go
@@ -35,7 +35,6 @@ func StartCron() {
go every(2*time.Hour, model.StatJob)
go every(2*time.Hour, model.RefreshCheckJob)
go every(3*time.Second, model.FlushUpdateRefTextRenameDocJob)
- go every(50*time.Millisecond, model.FlushTxJob)
go every(util.SQLFlushInterval, sql.FlushTxJob)
go every(util.SQLFlushInterval, sql.FlushHistoryTxJob)
go every(util.SQLFlushInterval, sql.FlushAssetContentTxJob)
diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go
index f41007698..be2ad78d5 100644
--- a/kernel/model/attribute_view.go
+++ b/kernel/model/attribute_view.go
@@ -967,6 +967,7 @@ func updateAttributeViewColumn(operation *Operation) (err error) {
for _, keyValues := range attrView.KeyValues {
if keyValues.Key.ID == operation.ID {
keyValues.Key.Name = operation.Name
+ keyValues.Key.Icon = operation.Data.(string)
keyValues.Key.Type = colType
break
}
diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go
index 4e2713d77..51917baaf 100644
--- a/kernel/model/transaction.go
+++ b/kernel/model/transaction.go
@@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"path/filepath"
- "sort"
"strings"
"sync"
"time"
@@ -65,11 +64,6 @@ func IsUnfoldHeading(transactions *[]*Transaction) bool {
return false
}
-var (
- txQueue []*Transaction
- txQueueLock = sync.Mutex{}
-)
-
func WaitForWritingFiles() {
var printLog bool
var lastPrintLog bool
@@ -86,25 +80,34 @@ func WaitForWritingFiles() {
}
}
+var (
+ txQueue = make(chan *Transaction, 7)
+ flushLock = sync.Mutex{}
+)
+
func isWritingFiles() bool {
time.Sleep(time.Duration(20) * time.Millisecond)
- return 0 < len(txQueue) || util.IsMutexLocked(&txQueueLock) || util.IsMutexLocked(&flushLock)
+ return 0 < len(txQueue) || util.IsMutexLocked(&flushLock)
}
-func FlushTxJob() {
- flushTx()
+func init() {
+ go func() {
+ for {
+ select {
+ case tx := <-txQueue:
+ flushTx(tx)
+ }
+ }
+ }()
}
-var flushLock = sync.Mutex{}
-
-func flushTx() {
+func flushTx(tx *Transaction) {
defer logging.Recover()
flushLock.Lock()
defer flushLock.Unlock()
- currentTx := mergeTx()
start := time.Now()
- if txErr := performTx(currentTx); nil != txErr {
+ if txErr := performTx(tx); nil != txErr {
switch txErr.code {
case TxErrCodeBlockNotFound:
util.PushTxErr("Transaction failed", txErr.code, nil)
@@ -116,48 +119,17 @@ func flushTx() {
}
}
elapsed := time.Now().Sub(start).Milliseconds()
- if 0 < len(currentTx.DoOperations) {
+ if 0 < len(tx.DoOperations) {
if 2000 < elapsed {
logging.LogWarnf("op tx [%dms]", elapsed)
}
}
}
-func mergeTx() (ret *Transaction) {
- txQueueLock.Lock()
- defer txQueueLock.Unlock()
-
- ret = &Transaction{}
- var doOps []*Operation
- for _, tx := range txQueue {
- for _, op := range tx.DoOperations {
- if l := len(doOps); 0 < l {
- lastOp := doOps[l-1]
- if "update" == lastOp.Action && "update" == op.Action && lastOp.ID == op.ID { // 连续相同的更新操作
- lastOp.discard = true
- }
- }
- doOps = append(doOps, op)
- }
- }
-
- for _, op := range doOps {
- if !op.discard {
- ret.DoOperations = append(ret.DoOperations, op)
- }
- }
-
- txQueue = nil
- return
-}
-
func PerformTransactions(transactions *[]*Transaction) {
- txQueueLock.Lock()
- txQueue = append(txQueue, *transactions...)
- sort.Slice(txQueue, func(i, j int) bool {
- return txQueue[i].Timestamp < txQueue[j].Timestamp
- })
- txQueueLock.Unlock()
+ for _, tx := range *transactions {
+ txQueue <- tx
+ }
return
}