diff --git a/kernel/api/filetree.go b/kernel/api/filetree.go index a8bb81b8a..cd02b1c94 100644 --- a/kernel/api/filetree.go +++ b/kernel/api/filetree.go @@ -114,11 +114,11 @@ func listDocTree(c *gin.Context) { ids := map[string]bool{} for _, entry := range dir { - if entry.IsDir() { - if strings.HasPrefix(entry.Name(), ".") { - continue - } + if strings.HasPrefix(entry.Name(), ".") { + continue + } + if entry.IsDir() { if !ast.IsNodeIDPattern(entry.Name()) { continue } @@ -134,7 +134,12 @@ func listDocTree(c *gin.Context) { return } } else { - doc := &DocFile{ID: strings.TrimSuffix(entry.Name(), ".sy")} + id := strings.TrimSuffix(entry.Name(), ".sy") + if !ast.IsNodeIDPattern(id) { + continue + } + + doc := &DocFile{ID: id} if !ids[doc.ID] { doctree = append(doctree, doc) } diff --git a/kernel/av/filter.go b/kernel/av/filter.go index 9acb813ce..31f2834ef 100644 --- a/kernel/av/filter.go +++ b/kernel/av/filter.go @@ -146,11 +146,13 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, itemID s return true } - switch filter.Operator { - case FilterOperatorIsEmpty: - return value.IsEmpty() - case FilterOperatorIsNotEmpty: - return !value.IsEmpty() + if "" == filter.Qualifier { + switch filter.Operator { + case FilterOperatorIsEmpty: + return value.IsEmpty() + case FilterOperatorIsNotEmpty: + return !value.IsEmpty() + } } // 单独处理汇总 @@ -194,12 +196,30 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, itemID s switch filter.Qualifier { case FilterQuantifierUndefined, FilterQuantifierAny: + if len(value.Rollup.Contents) < len(relVal.Relation.Contents) { // 说明汇总的目标字段存在空值 + if FilterOperatorIsEmpty == filter.Operator { + return true + } else if FilterOperatorIsNotEmpty == filter.Operator { + return false + } + } + for _, content := range value.Rollup.Contents { if content.filter(filter.Value.Rollup.Contents[0], filter.RelativeDate, filter.RelativeDate2, filter.Operator) { return true } } case FilterQuantifierAll: + if len(value.Rollup.Contents) < len(relVal.Relation.Contents) { + if FilterOperatorIsEmpty == filter.Operator { + if 1 > len(value.Rollup.Contents) { + return true + } + } else if FilterOperatorIsNotEmpty == filter.Operator { + return false + } + } + for _, content := range value.Rollup.Contents { if !content.filter(filter.Value.Rollup.Contents[0], filter.RelativeDate, filter.RelativeDate2, filter.Operator) { return false @@ -207,6 +227,14 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, itemID s } return true case FilterQuantifierNone: + if len(value.Rollup.Contents) < len(relVal.Relation.Contents) { + if FilterOperatorIsEmpty == filter.Operator { + return false + } else if FilterOperatorIsNotEmpty == filter.Operator { + return true + } + } + for _, content := range value.Rollup.Contents { if content.filter(filter.Value.Rollup.Contents[0], filter.RelativeDate, filter.RelativeDate2, filter.Operator) { return false @@ -265,6 +293,14 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, itemID s switch filter.Qualifier { case FilterQuantifierUndefined, FilterQuantifierAny: + if 1 > len(value.MAsset) { // 说明资源字段为空 + if FilterOperatorIsEmpty == filter.Operator { + return true + } else if FilterOperatorIsNotEmpty == filter.Operator { + return false + } + } + for _, asset := range value.MAsset { switch asset.Type { case AssetTypeFile: @@ -279,6 +315,14 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, itemID s } } case FilterQuantifierAll: + if 1 > len(value.MAsset) { + if FilterOperatorIsEmpty == filter.Operator { + return true + } else if FilterOperatorIsNotEmpty == filter.Operator { + return false + } + } + for _, asset := range value.MAsset { switch asset.Type { case AssetTypeFile: @@ -294,6 +338,14 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, itemID s } return true case FilterQuantifierNone: + if 1 > len(value.MAsset) { + if FilterOperatorIsEmpty == filter.Operator { + return false + } else if FilterOperatorIsNotEmpty == filter.Operator { + return true + } + } + for _, asset := range value.MAsset { switch asset.Type { case AssetTypeFile: diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 2795fb0c9..6901ed88b 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1959,7 +1959,7 @@ func genAttrViewGroups(view *av.View, attrView *av.AttributeView) { // 过去 30 天、过去 7 天、昨天、今天、明天、未来 7 天、未来 30 天 // 未来 30 天之后的按月分组 if contentTime.Before(todayStart.AddDate(0, 0, -30)) { - groupVal = contentTime.Format("2006-01") // 开头的数字用于排序,下同 + groupVal = contentTime.Format("2006-01") // 开头的数字用于排序 } else if contentTime.Before(todayStart.AddDate(0, 0, -7)) { groupVal = groupValueLast30Days } else if contentTime.Before(todayStart.AddDate(0, 0, -1)) { diff --git a/kernel/model/block.go b/kernel/model/block.go index 248b13797..97a4f0ebf 100644 --- a/kernel/model/block.go +++ b/kernel/model/block.go @@ -786,6 +786,11 @@ func GetBlockDOMs(ids []string) (ret map[string]string) { if nil == node { continue } + + if parentFoldedHeading := treenode.GetParentFoldedHeading(node); nil != parentFoldedHeading { + node.SetIALAttr("parent-heading", parentFoldedHeading.ID) + } + ret[id] = luteEngine.RenderNodeBlockDOM(node) } return diff --git a/kernel/model/box.go b/kernel/model/box.go index 16768373c..ffcf8bdcb 100644 --- a/kernel/model/box.go +++ b/kernel/model/box.go @@ -102,17 +102,22 @@ func ListNotebooks() (ret []*Box, err error) { continue } - if !ast.IsNodeIDPattern(dir.Name()) { + id := dir.Name() + if !ast.IsNodeIDPattern(id) { continue } boxConf := conf.NewBoxConf() - boxDirPath := filepath.Join(util.DataDir, dir.Name()) + boxDirPath := filepath.Join(util.DataDir, id) boxConfPath := filepath.Join(boxDirPath, ".siyuan", "conf.json") isExistConf := filelock.IsExist(boxConfPath) if !isExistConf { - // 数据同步时展开文档树操作可能导致数据丢失 https://github.com/siyuan-note/siyuan/issues/7129 - logging.LogWarnf("found a corrupted box [%s]", boxDirPath) + if !IsUserGuide(id) { + // 数据同步时展开文档树操作可能导致数据丢失 https://github.com/siyuan-note/siyuan/issues/7129 + logging.LogWarnf("found a corrupted box [%s]", boxDirPath) + } else { + continue + } } else { data, readErr := filelock.ReadFile(boxConfPath) if nil != readErr { @@ -126,7 +131,6 @@ func ListNotebooks() (ret []*Box, err error) { } } - id := dir.Name() icon := boxConf.Icon if strings.Contains(icon, ".") { // 说明是自定义图标 // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 diff --git a/kernel/model/conf.go b/kernel/model/conf.go index 89930c322..76897e7e7 100644 --- a/kernel/model/conf.go +++ b/kernel/model/conf.go @@ -1131,6 +1131,7 @@ func closeUserGuide() { unindex(boxID) + sql.FlushQueue() if removeErr := filelock.Remove(boxDirPath); nil != removeErr { logging.LogErrorf("remove corrupted user guide box [%s] failed: %s", boxDirPath, removeErr) } diff --git a/kernel/model/export.go b/kernel/model/export.go index d5e2f87c1..6fa0c2a0d 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -2162,9 +2162,11 @@ func exportMarkdownContent0(id string, tree *parse.Tree, cloudAssetsBase string, href = "#" + defID } } - href = strings.TrimPrefix(href, currentDocDir) + newHref := strings.TrimPrefix(href, currentDocDir) + if !strings.HasPrefix(newHref, ".md") { + href = newHref + } href = util.FilterFilePath(href) - href = strings.TrimPrefix(href, "/") blockRefLink := &ast.Node{Type: ast.NodeTextMark, TextMarkType: "a", TextMarkTextContent: linkText, TextMarkAHref: href} blockRefLink.KramdownIAL = n.KramdownIAL n.InsertBefore(blockRefLink) diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index f768c045d..0e0a1ea76 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -912,8 +912,12 @@ func (tx *Transaction) doDelete(operation *Operation) (ret *TxErr) { node.Next.Unlink() } + next := node.Next node.Unlink() + parentFoldedHeading := treenode.GetParentFoldedHeading(next) + unfoldHeading(parentFoldedHeading) + if nil != parent && ast.NodeListItem == parent.Type && nil == parent.FirstChild { needAppendEmptyListItem := true for _, op := range tx.DoOperations {