diff --git a/.gitignore b/.gitignore
index 4cdcb33b3..beff8f1d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ electron/dist
# IDE
.idea/
+.vscode/
# Log
logs
diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json
index fa5a50889..62612e2ec 100644
--- a/app/appearance/langs/en_US.json
+++ b/app/appearance/langs/en_US.json
@@ -119,6 +119,7 @@
"goToEditTabPrev": "Go to previous edited tab",
"createdTime": "Created time",
"updatedTime": "Updated time",
+ "lineNumber": "Line number",
"removeBookmark": "Remove bookmark from ${x}?",
"defaultMargin": "Default",
"noneMargin": "None",
diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json
index 620fa4b3c..703991e49 100644
--- a/app/appearance/langs/es_ES.json
+++ b/app/appearance/langs/es_ES.json
@@ -119,6 +119,7 @@
"goToEditTabPrev": "Ir a la pestaña editada anteriormente",
"createdTime": "Hora de creación",
"updatedTime": "Hora actualizada",
+ "lineNumber": "Número de línea",
"removeBookmark": "¿Eliminar marcador de ${x}?",
"lockEdit": "Hacer que el documento sea de sólo lectura",
"unlockEdit": "Hacer que el documento sea escribible",
diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json
index adbf84220..dd28a4723 100644
--- a/app/appearance/langs/fr_FR.json
+++ b/app/appearance/langs/fr_FR.json
@@ -119,6 +119,7 @@
"goToEditTabPrev": "Aller à l'onglet modifié précédent",
"createdTime": "Heure de création",
"updatedTime": "Heure mise à jour",
+ "lineNumber": "Numéro de ligne",
"removeBookmark": "Supprimer le signet de ${x} ?",
"lockEdit": "Rendre le document en lecture seule",
"unlockEdit": "Rendre le document accessible en écriture",
diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json
index d21ac9f4c..d88415cfb 100644
--- a/app/appearance/langs/zh_CHT.json
+++ b/app/appearance/langs/zh_CHT.json
@@ -119,6 +119,7 @@
"goToEditTabPrev": "跳到上一個編輯頁籤",
"createdTime": "建立時間",
"updatedTime": "更新時間",
+ "lineNumber": "行號",
"removeBookmark": "移除 ${x} 中的書籤?",
"lockEdit": "鎖定編輯",
"unlockEdit": "解除鎖定",
diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json
index 5325449e4..c418a93b2 100644
--- a/app/appearance/langs/zh_CN.json
+++ b/app/appearance/langs/zh_CN.json
@@ -119,6 +119,7 @@
"goToEditTabPrev": "跳转到上一个编辑页签",
"createdTime": "创建时间",
"updatedTime": "更新时间",
+ "lineNumber": "行号",
"removeBookmark": "移除 ${x} 中的书签?",
"lockEdit": "锁定编辑",
"unlockEdit": "解除锁定",
diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts
index 073614c62..595784b50 100644
--- a/app/src/protyle/render/av/action.ts
+++ b/app/src/protyle/render/av/action.ts
@@ -251,7 +251,8 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
return;
}
const type = getTypeByCellElement(target);
- if (type === "updated" || type === "created" || (type === "block" && !target.getAttribute("data-detached"))) {
+ // TODO 点击单元格的时候, lineNumber 选中整行
+ if (type === "updated" || type === "created" || type === "lineNumber" || (type === "block" && !target.getAttribute("data-detached"))) {
selectRow(rowElement.querySelector(".av__firstcol"), "toggle");
} else {
scrollElement.querySelectorAll(".av__row--select").forEach(item => {
diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts
index c909c551e..18e1f5317 100644
--- a/app/src/protyle/render/av/cell.ts
+++ b/app/src/protyle/render/av/cell.ts
@@ -644,7 +644,7 @@ export const renderCellAttr = (cellElement: Element, value: IAVCellValue) => {
}
};
-export const renderCell = (cellValue: IAVCellValue) => {
+export const renderCell = (cellValue: IAVCellValue, rowIndex = 0) => {
let text = "";
if (["text", "template"].includes(cellValue.type)) {
text = `${cellValue ? (cellValue[cellValue.type as "text"].content || "") : ""}`;
@@ -683,6 +683,9 @@ export const renderCell = (cellValue: IAVCellValue) => {
text += dayjs(dataValue.content).format("YYYY-MM-DD HH:mm");
}
text += "";
+ } else if (["lineNumber"].includes(cellValue.type)) {
+ // 渲染行号
+ text = `${rowIndex + 1}`;
} else if (cellValue.type === "mAsset") {
cellValue?.mAsset?.forEach((item) => {
if (item.type === "image") {
@@ -713,8 +716,9 @@ export const renderCell = (cellValue: IAVCellValue) => {
text = text.substring(0, text.length - 2);
}
}
- if (["text", "template", "url", "email", "phone", "number", "date", "created", "updated"].includes(cellValue.type) &&
- cellValue && cellValue[cellValue.type as "url"].content) {
+
+ if (["text", "template", "url", "email", "phone", "number", "date", "created", "updated", "lineNumber"].includes(cellValue.type) &&
+ ( cellValue.type === "lineNumber" || (cellValue && cellValue[cellValue.type as "url"].content))) {
text += ``;
}
return text;
diff --git a/app/src/protyle/render/av/col.ts b/app/src/protyle/render/av/col.ts
index 86bbae70b..2dd6e6b9d 100644
--- a/app/src/protyle/render/av/col.ts
+++ b/app/src/protyle/render/av/col.ts
@@ -252,6 +252,7 @@ export const getEditHTML = (options: {
${genUpdateColItem("template", colData.type)}
${genUpdateColItem("relation", colData.type)}
${genUpdateColItem("rollup", colData.type)}
+ ${genUpdateColItem("lineNumber", colData.type)}
${genUpdateColItem("created", colData.type)}
${genUpdateColItem("updated", colData.type)}
`;
@@ -482,6 +483,8 @@ export const getColNameByType = (type: TAVCol) => {
return window.siyuan.languages.checkbox;
case "block":
return window.siyuan.languages["_attrView"].key;
+ case "lineNumber":
+ return window.siyuan.languages.lineNumber;
}
};
@@ -518,6 +521,8 @@ export const getColIconByType = (type: TAVCol) => {
return "iconMath";
case "checkbox":
return "iconCheck";
+ case "lineNumber":
+ return "iconSpreadOdd";
}
};
@@ -694,90 +699,94 @@ export const showColMenu = (protyle: IProtyle, blockElement: Element, cellElemen
}
});
menu.addSeparator();
- menu.addItem({
- icon: "iconUp",
- label: window.siyuan.languages.asc,
- click() {
- fetchPost("/api/av/renderAttributeView", {
- id: avID,
- }, (response) => {
- transaction(protyle, [{
- action: "setAttrViewSorts",
- avID: response.data.id,
- data: [{
- column: colId,
- order: "ASC"
- }],
- blockID
- }], [{
- action: "setAttrViewSorts",
- avID: response.data.id,
- data: response.data.view.sorts,
- blockID
- }]);
- });
- }
- });
- menu.addItem({
- icon: "iconDown",
- label: window.siyuan.languages.desc,
- click() {
- fetchPost("/api/av/renderAttributeView", {
- id: avID,
- }, (response) => {
- transaction(protyle, [{
- action: "setAttrViewSorts",
- avID: response.data.id,
- data: [{
- column: colId,
- order: "DESC"
- }],
- blockID
- }], [{
- action: "setAttrViewSorts",
- avID: response.data.id,
- data: response.data.view.sorts,
- blockID
- }]);
- });
- }
- });
- if (type !== "mAsset") {
+
+ // 行号 类型不参与 排序和筛选
+ if (type !== "lineNumber") {
menu.addItem({
- icon: "iconFilter",
- label: window.siyuan.languages.filter,
+ icon: "iconUp",
+ label: window.siyuan.languages.asc,
click() {
fetchPost("/api/av/renderAttributeView", {
id: avID,
}, (response) => {
- const avData = response.data as IAV;
- let filter: IAVFilter;
- avData.view.filters.find((item) => {
- if (item.column === colId && item.value.type === type) {
- filter = item;
- return true;
- }
- });
- if (!filter) {
- filter = {
+ transaction(protyle, [{
+ action: "setAttrViewSorts",
+ avID: response.data.id,
+ data: [{
column: colId,
- operator: getDefaultOperatorByType(type),
- value: genCellValue(type, ""),
- };
- avData.view.filters.push(filter);
- }
- setFilter({
- filter,
- protyle,
- data: avData,
- blockElement: blockElement,
- target: blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`),
- });
+ order: "ASC"
+ }],
+ blockID
+ }], [{
+ action: "setAttrViewSorts",
+ avID: response.data.id,
+ data: response.data.view.sorts,
+ blockID
+ }]);
});
}
});
+ menu.addItem({
+ icon: "iconDown",
+ label: window.siyuan.languages.desc,
+ click() {
+ fetchPost("/api/av/renderAttributeView", {
+ id: avID,
+ }, (response) => {
+ transaction(protyle, [{
+ action: "setAttrViewSorts",
+ avID: response.data.id,
+ data: [{
+ column: colId,
+ order: "DESC"
+ }],
+ blockID
+ }], [{
+ action: "setAttrViewSorts",
+ avID: response.data.id,
+ data: response.data.view.sorts,
+ blockID
+ }]);
+ });
+ }
+ });
+ if (type !== "mAsset") {
+ menu.addItem({
+ icon: "iconFilter",
+ label: window.siyuan.languages.filter,
+ click() {
+ fetchPost("/api/av/renderAttributeView", {
+ id: avID,
+ }, (response) => {
+ const avData = response.data as IAV;
+ let filter: IAVFilter;
+ avData.view.filters.find((item) => {
+ if (item.column === colId && item.value.type === type) {
+ filter = item;
+ return true;
+ }
+ });
+ if (!filter) {
+ filter = {
+ column: colId,
+ operator: getDefaultOperatorByType(type),
+ value: genCellValue(type, ""),
+ };
+ avData.view.filters.push(filter);
+ }
+ setFilter({
+ filter,
+ protyle,
+ data: avData,
+ blockElement: blockElement,
+ target: blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`),
+ });
+ });
+ }
+ });
+ }
+ menu.addSeparator();
}
- menu.addSeparator();
menu.addItem({
icon: "iconInsertLeft",
@@ -1429,6 +1438,44 @@ export const addCol = (protyle: IProtyle, blockElement: Element, previousID?: st
blockElement.setAttribute("updated", newUpdated);
}
});
+ // 在创建时间前插入 lineNumber
+ menu.addItem({
+ icon: "iconSpreadOdd",
+ label: window.siyuan.languages.lineNumber,
+ click() {
+ const id = Lute.NewNodeID();
+ const newUpdated = dayjs().format("YYYYMMDDHHmmss");
+ transaction(protyle, [{
+ action: "addAttrViewCol",
+ name: window.siyuan.languages.lineNumber,
+ avID,
+ type: "lineNumber",
+ id,
+ previousID
+ }, {
+ action: "doUpdateUpdated",
+ id: blockId,
+ data: newUpdated,
+ }], [{
+ action: "removeAttrViewCol",
+ id,
+ avID,
+ }, {
+ action: "doUpdateUpdated",
+ id: blockId,
+ data: blockElement.getAttribute("updated")
+ }]);
+ addAttrViewColAnimation({
+ blockElement: blockElement,
+ protyle: protyle,
+ type: "lineNumber",
+ name: window.siyuan.languages.lineNumber,
+ id,
+ previousID
+ });
+ blockElement.setAttribute("updated", newUpdated);
+ }
+ });
menu.addItem({
icon: "iconClock",
label: window.siyuan.languages.createdTime,
diff --git a/app/src/protyle/render/av/filter.ts b/app/src/protyle/render/av/filter.ts
index 929cfad73..520e04c04 100644
--- a/app/src/protyle/render/av/filter.ts
+++ b/app/src/protyle/render/av/filter.ts
@@ -566,7 +566,8 @@ export const addFilter = (options: {
return true;
}
});
- if (!filter && column.type !== "mAsset") {
+ // 该列是行号类型列,则不允许添加到过滤器
+ if (!filter && column.type !== "mAsset" && column.type !== "lineNumber") {
menu.addItem({
label: column.name,
iconHTML: column.icon ? unicode2Emoji(column.icon, "b3-menu__icon", true) : ``,
diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts
index b6c7a640c..a2f4432ef 100644
--- a/app/src/protyle/render/av/openMenuPanel.ts
+++ b/app/src/protyle/render/av/openMenuPanel.ts
@@ -854,6 +854,46 @@ export const openMenuPanel = (options: {
name,
type: target.dataset.oldType as TAVCol,
}]);
+
+ // 需要取消 lineNumber 列的排序和过滤
+ if (target.dataset.newType === "lineNumber") {
+ const sortExist = data.view.sorts.find((sort) => sort.column === options.colId);
+ if (sortExist) {
+ const oldSorts = Object.assign([], data.view.sorts);
+ const newSorts = data.view.sorts.filter((sort) => sort.column !== options.colId);
+
+ transaction(options.protyle, [{
+ action: "setAttrViewSorts",
+ avID: data.id,
+ data: newSorts,
+ blockID,
+ }], [{
+ action: "setAttrViewSorts",
+ avID: data.id,
+ data: oldSorts,
+ blockID,
+ }]);
+ }
+
+ const filterExist = data.view.filters.find((filter) => filter.column === options.colId);
+ if (filterExist) {
+ const oldFilters = JSON.parse(JSON.stringify(data.view.filters));
+ const newFilters = data.view.filters.filter((filter) => filter.column !== options.colId);
+
+ transaction(options.protyle, [{
+ action: "setAttrViewFilters",
+ avID: data.id,
+ data: newFilters,
+ blockID
+ }], [{
+ action: "setAttrViewFilters",
+ avID: data.id,
+ data: oldFilters,
+ blockID
+ }]);
+ }
+
+ }
}
avPanelElement.remove();
event.preventDefault();
diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts
index 7b826f530..4d6dbe36d 100644
--- a/app/src/protyle/render/av/render.ts
+++ b/app/src/protyle/render/av/render.ts
@@ -129,8 +129,16 @@ style="width: ${column.width || "200px"};">
if (pinIndex === index) {
tableHTML += "";
}
- calcHTML += `
${getCalcValue(column) || '' + window.siyuan.languages.calc}
`;
+
+ // lineNumber type 不参与计算操作
+ if (column.type === "lineNumber") {
+ calcHTML += `
`;
+ } else {
+ calcHTML += `${getCalcValue(column) || '' + window.siyuan.languages.calc}
`;
+ }
+
if (pinIndex === index) {
calcHTML += "";
}
@@ -142,7 +150,7 @@ style="width: ${index === 0 ? ((parseInt(column.width || "200") + 24) + "px") :
`;
// body
- data.rows.forEach((row: IAVRow) => {
+ data.rows.forEach((row: IAVRow, rowIndex: number) => {
tableHTML += ``;
if (pinIndex > -1) {
tableHTML += '
';
@@ -165,7 +173,7 @@ ${cell.value?.isDetached ? ' data-detached="true"' : ""}
style="width: ${data.columns[index].width || "200px"};
${cell.valueType === "number" ? "text-align: right;" : ""}
${cell.bgColor ? `background-color:${cell.bgColor};` : ""}
-${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value)}
`;
+${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value, rowIndex)}
`;
if (pinIndex === index) {
tableHTML += "";
diff --git a/app/src/protyle/render/av/sort.ts b/app/src/protyle/render/av/sort.ts
index af727019b..e56936c11 100644
--- a/app/src/protyle/render/av/sort.ts
+++ b/app/src/protyle/render/av/sort.ts
@@ -16,12 +16,19 @@ export const addSort = (options: {
const menu = new Menu("av-add-sort");
options.data.view.columns.forEach((column) => {
let hasSort = false;
- options.data.view.sorts.find((sort) => {
- if (sort.column === column.id) {
- hasSort = true;
- return true;
- }
- });
+
+ // 如果该列是行号类型列,不允许添加排序
+ if (column.type === "lineNumber") {
+ hasSort = true;
+ } else {
+ options.data.view.sorts.find((sort) => {
+ if (sort.column === column.id) {
+ hasSort = true;
+ return true;
+ }
+ });
+ }
+
if (!hasSort) {
menu.addItem({
label: column.name,
diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts
index f927350c2..b06ba0815 100644
--- a/app/src/types/index.d.ts
+++ b/app/src/types/index.d.ts
@@ -82,6 +82,7 @@ type TAVCol =
| "created"
| "updated"
| "checkbox"
+ | "lineNumber"
type THintSource = "search" | "av" | "hint";
type TAVFilterOperator =
"="
diff --git a/kernel/av/av.go b/kernel/av/av.go
index 9713035d4..a9242f4f6 100644
--- a/kernel/av/av.go
+++ b/kernel/av/av.go
@@ -64,22 +64,23 @@ func (kValues *KeyValues) GetValue(blockID string) (ret *Value) {
type KeyType string
const (
- KeyTypeBlock KeyType = "block"
- KeyTypeText KeyType = "text"
- KeyTypeNumber KeyType = "number"
- KeyTypeDate KeyType = "date"
- KeyTypeSelect KeyType = "select"
- KeyTypeMSelect KeyType = "mSelect"
- KeyTypeURL KeyType = "url"
- KeyTypeEmail KeyType = "email"
- KeyTypePhone KeyType = "phone"
- KeyTypeMAsset KeyType = "mAsset"
- KeyTypeTemplate KeyType = "template"
- KeyTypeCreated KeyType = "created"
- KeyTypeUpdated KeyType = "updated"
- KeyTypeCheckbox KeyType = "checkbox"
- KeyTypeRelation KeyType = "relation"
- KeyTypeRollup KeyType = "rollup"
+ KeyTypeBlock KeyType = "block"
+ KeyTypeText KeyType = "text"
+ KeyTypeNumber KeyType = "number"
+ KeyTypeDate KeyType = "date"
+ KeyTypeSelect KeyType = "select"
+ KeyTypeMSelect KeyType = "mSelect"
+ KeyTypeURL KeyType = "url"
+ KeyTypeEmail KeyType = "email"
+ KeyTypePhone KeyType = "phone"
+ KeyTypeMAsset KeyType = "mAsset"
+ KeyTypeTemplate KeyType = "template"
+ KeyTypeCreated KeyType = "created"
+ KeyTypeUpdated KeyType = "updated"
+ KeyTypeCheckbox KeyType = "checkbox"
+ KeyTypeRelation KeyType = "relation"
+ KeyTypeRollup KeyType = "rollup"
+ KeyTypeLineNumber KeyType = "lineNumber"
)
// Key 描述了属性视图属性列的基础结构。
diff --git a/kernel/av/sort.go b/kernel/av/sort.go
index 37c36aea8..bef537865 100644
--- a/kernel/av/sort.go
+++ b/kernel/av/sort.go
@@ -220,59 +220,62 @@ func (value *Value) Compare(other *Value, attrView *AttributeView) int {
}
case KeyTypeRelation:
if nil != value.Relation && nil != other.Relation {
+ if 1 < len(value.Relation.Contents) && 1 < len(other.Relation.Contents) && KeyTypeNumber == value.Relation.Contents[0].Type && KeyTypeNumber == other.Relation.Contents[0].Type {
+ v1, ok1 := util.Convert2Float(value.Relation.Contents[0].String(false))
+ v2, ok2 := util.Convert2Float(other.Relation.Contents[0].String(false))
+ if ok1 && ok2 {
+ if v1 > v2 {
+ return 1
+ }
+ if v1 < v2 {
+ return -1
+ }
+ return 0
+ }
+ }
+
vContentBuf := bytes.Buffer{}
for _, c := range value.Relation.Contents {
- vContentBuf.WriteString(c.String())
+ vContentBuf.WriteString(c.String(true))
vContentBuf.WriteByte(' ')
}
vContent := strings.TrimSpace(vContentBuf.String())
oContentBuf := bytes.Buffer{}
for _, c := range other.Relation.Contents {
- oContentBuf.WriteString(c.String())
+ oContentBuf.WriteString(c.String(true))
oContentBuf.WriteByte(' ')
}
oContent := strings.TrimSpace(oContentBuf.String())
-
- v1, ok1 := util.Convert2Float(vContent)
- v2, ok2 := util.Convert2Float(oContent)
- if ok1 && ok2 {
- if v1 > v2 {
- return 1
- }
-
- if v1 < v2 {
- return -1
- }
- return 0
- }
return strings.Compare(vContent, oContent)
}
case KeyTypeRollup:
if nil != value.Rollup && nil != other.Rollup {
+ if 1 < len(value.Rollup.Contents) && 1 < len(other.Rollup.Contents) && KeyTypeNumber == value.Rollup.Contents[0].Type && KeyTypeNumber == other.Rollup.Contents[0].Type {
+ v1, ok1 := util.Convert2Float(value.Rollup.Contents[0].String(false))
+ v2, ok2 := util.Convert2Float(other.Rollup.Contents[0].String(false))
+ if ok1 && ok2 {
+ if v1 > v2 {
+ return 1
+ }
+ if v1 < v2 {
+ return -1
+ }
+ return 0
+ }
+ }
+
vContentBuf := bytes.Buffer{}
for _, c := range value.Rollup.Contents {
- vContentBuf.WriteString(c.String())
+ vContentBuf.WriteString(c.String(true))
vContentBuf.WriteByte(' ')
}
vContent := strings.TrimSpace(vContentBuf.String())
oContentBuf := bytes.Buffer{}
for _, c := range other.Rollup.Contents {
- oContentBuf.WriteString(c.String())
+ oContentBuf.WriteString(c.String(true))
oContentBuf.WriteByte(' ')
}
oContent := strings.TrimSpace(oContentBuf.String())
-
- v1, ok1 := util.Convert2Float(vContent)
- v2, ok2 := util.Convert2Float(oContent)
- if ok1 && ok2 {
- if v1 > v2 {
- return 1
- }
- if v1 < v2 {
- return -1
- }
- return 0
- }
return strings.Compare(vContent, oContent)
}
}
diff --git a/kernel/av/table.go b/kernel/av/table.go
index ec7264fcb..fb7afc849 100644
--- a/kernel/av/table.go
+++ b/kernel/av/table.go
@@ -1586,8 +1586,8 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- if !uniqueValues[content.String()] {
- uniqueValues[content.String()] = true
+ if !uniqueValues[content.String(true)] {
+ uniqueValues[content.String(true)] = true
countUniqueValues++
}
}
@@ -1635,7 +1635,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String())
+ val, _ := util.Convert2Float(content.String(false))
sum += val
}
}
@@ -1647,7 +1647,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String())
+ val, _ := util.Convert2Float(content.String(false))
sum += val
count++
}
@@ -1661,7 +1661,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String())
+ val, _ := util.Convert2Float(content.String(false))
values = append(values, val)
}
}
@@ -1679,7 +1679,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String())
+ val, _ := util.Convert2Float(content.String(false))
if val < minVal {
minVal = val
}
@@ -1694,7 +1694,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String())
+ val, _ := util.Convert2Float(content.String(false))
if val > maxVal {
maxVal = val
}
@@ -1710,7 +1710,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
for _, row := range table.Rows {
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String())
+ val, _ := util.Convert2Float(content.String(false))
if val < minVal {
minVal = val
}
diff --git a/kernel/av/value.go b/kernel/av/value.go
index 0a2728d5c..5b188eedd 100644
--- a/kernel/av/value.go
+++ b/kernel/av/value.go
@@ -64,7 +64,7 @@ func (value *Value) SetUpdatedAt(mills int64) {
}
}
-func (value *Value) String() string {
+func (value *Value) String(format bool) string {
if nil == value {
return ""
}
@@ -84,7 +84,10 @@ func (value *Value) String() string {
if nil == value.Number {
return ""
}
- return value.Number.FormattedContent
+ if format {
+ return value.Number.FormattedContent
+ }
+ return fmt.Sprintf("%f", value.Number.Content)
case KeyTypeDate:
if nil == value.Date {
return ""
@@ -158,7 +161,7 @@ func (value *Value) String() string {
}
var ret []string
for _, v := range value.Relation.Contents {
- ret = append(ret, v.String())
+ ret = append(ret, v.String(format))
}
return strings.TrimSpace(strings.Join(ret, ", "))
case KeyTypeRollup:
@@ -167,7 +170,7 @@ func (value *Value) String() string {
}
var ret []string
for _, v := range value.Rollup.Contents {
- ret = append(ret, v.String())
+ ret = append(ret, v.String(format))
}
return strings.TrimSpace(strings.Join(ret, ", "))
default:
@@ -679,8 +682,8 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, v := range r.Contents {
- if _, ok := uniqueValues[v.String()]; !ok {
- uniqueValues[v.String()] = true
+ if _, ok := uniqueValues[v.String(true)]; !ok {
+ uniqueValues[v.String(true)] = true
countUniqueValues++
}
}
@@ -688,7 +691,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
case CalcOperatorCountEmpty:
countEmpty := 0
for _, v := range r.Contents {
- if "" == v.String() {
+ if "" == v.String(true) {
countEmpty++
}
}
@@ -696,7 +699,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
case CalcOperatorCountNotEmpty:
countNonEmpty := 0
for _, v := range r.Contents {
- if "" != v.String() {
+ if "" != v.String(true) {
countNonEmpty++
}
}
@@ -704,7 +707,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, v := range r.Contents {
- if "" == v.String() {
+ if "" == v.String(true) {
countEmpty++
}
}
@@ -714,7 +717,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
case CalcOperatorPercentNotEmpty:
countNonEmpty := 0
for _, v := range r.Contents {
- if "" != v.String() {
+ if "" != v.String(true) {
countNonEmpty++
}
}
diff --git a/kernel/bazaar/icon.go b/kernel/bazaar/icon.go
index 94c669d51..3e1cab908 100644
--- a/kernel/bazaar/icon.go
+++ b/kernel/bazaar/icon.go
@@ -17,7 +17,6 @@
package bazaar
import (
- "errors"
"os"
"path/filepath"
"sort"
@@ -184,14 +183,9 @@ func InstallIcon(repoURL, repoHash, installPath string, systemID string) error {
if nil != err {
return err
}
- return installPackage(data, installPath)
+ return installPackage(data, installPath, repoURLHash)
}
func UninstallIcon(installPath string) error {
- if err := os.RemoveAll(installPath); nil != err {
- logging.LogErrorf("remove icon [%s] failed: %s", installPath, err)
- return errors.New("remove community icon failed")
- }
- //logging.Logger.Infof("uninstalled icon [%s]", installPath)
- return nil
+ return uninstallPackage(installPath)
}
diff --git a/kernel/bazaar/package.go b/kernel/bazaar/package.go
index f96161d4b..dafd7b889 100644
--- a/kernel/bazaar/package.go
+++ b/kernel/bazaar/package.go
@@ -19,6 +19,7 @@ package bazaar
import (
"bytes"
"errors"
+ "fmt"
"os"
"path/filepath"
"strings"
@@ -588,7 +589,26 @@ func incPackageDownloads(repoURLHash, systemID string) {
}).Post(u)
}
-func installPackage(data []byte, installPath string) (err error) {
+func uninstallPackage(installPath string) (err error) {
+ if err = os.RemoveAll(installPath); nil != err {
+ logging.LogErrorf("remove [%s] failed: %s", installPath, err)
+ return fmt.Errorf("remove community package [%s] failed", filepath.Base(installPath))
+ }
+ packageCache.Flush()
+ return
+}
+
+func installPackage(data []byte, installPath, repoURLHash string) (err error) {
+ err = installPackage0(data, installPath)
+ if nil != err {
+ return
+ }
+
+ packageCache.Delete(strings.TrimPrefix(repoURLHash, "https://github.com/"))
+ return
+}
+
+func installPackage0(data []byte, installPath string) (err error) {
tmpPackage := filepath.Join(util.TempDir, "bazaar", "package")
if err = os.MkdirAll(tmpPackage, 0755); nil != err {
return
diff --git a/kernel/bazaar/plugin.go b/kernel/bazaar/plugin.go
index 0b70157ef..0b460e518 100644
--- a/kernel/bazaar/plugin.go
+++ b/kernel/bazaar/plugin.go
@@ -17,7 +17,6 @@
package bazaar
import (
- "errors"
"os"
"path/filepath"
"runtime"
@@ -27,7 +26,6 @@ import (
"github.com/dustin/go-humanize"
ants "github.com/panjf2000/ants/v2"
- "github.com/siyuan-note/filelock"
"github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
@@ -220,16 +218,11 @@ func InstallPlugin(repoURL, repoHash, installPath string, systemID string) error
if nil != err {
return err
}
- return installPackage(data, installPath)
+ return installPackage(data, installPath, repoURLHash)
}
func UninstallPlugin(installPath string) error {
- if err := filelock.Remove(installPath); nil != err {
- logging.LogErrorf("remove plugin [%s] failed: %s", installPath, err)
- return errors.New("remove community plugin failed")
- }
- //logging.Logger.Infof("uninstalled plugin [%s]", installPath)
- return nil
+ return uninstallPackage(installPath)
}
func isIncompatiblePlugin(plugin *Plugin, currentFrontend string) bool {
diff --git a/kernel/bazaar/template.go b/kernel/bazaar/template.go
index ec5b130d8..e08f260d3 100644
--- a/kernel/bazaar/template.go
+++ b/kernel/bazaar/template.go
@@ -17,7 +17,6 @@
package bazaar
import (
- "errors"
"os"
"path/filepath"
"sort"
@@ -27,7 +26,6 @@ import (
"github.com/dustin/go-humanize"
"github.com/panjf2000/ants/v2"
- "github.com/siyuan-note/filelock"
"github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
@@ -182,15 +180,11 @@ func InstallTemplate(repoURL, repoHash, installPath string, systemID string) err
if nil != err {
return err
}
- return installPackage(data, installPath)
+ return installPackage(data, installPath, repoURLHash)
}
func UninstallTemplate(installPath string) error {
- if err := filelock.Remove(installPath); nil != err {
- logging.LogErrorf("remove template [%s] failed: %s", installPath, err)
- return errors.New("remove community template failed")
- }
- return nil
+ return uninstallPackage(installPath)
}
func filterLegacyTemplates(templates []*Template) (ret []*Template) {
diff --git a/kernel/bazaar/theme.go b/kernel/bazaar/theme.go
index 1a32efdaa..af1ec06c0 100644
--- a/kernel/bazaar/theme.go
+++ b/kernel/bazaar/theme.go
@@ -17,7 +17,6 @@
package bazaar
import (
- "errors"
"os"
"path/filepath"
"sort"
@@ -186,14 +185,9 @@ func InstallTheme(repoURL, repoHash, installPath string, systemID string) error
if nil != err {
return err
}
- return installPackage(data, installPath)
+ return installPackage(data, installPath, repoURLHash)
}
func UninstallTheme(installPath string) error {
- if err := os.RemoveAll(installPath); nil != err {
- logging.LogErrorf("remove theme [%s] failed: %s", installPath, err)
- return errors.New("remove community theme failed")
- }
- //logging.Logger.Infof("uninstalled theme [%s]", installPath)
- return nil
+ return uninstallPackage(installPath)
}
diff --git a/kernel/bazaar/widget.go b/kernel/bazaar/widget.go
index 1d6d64e5d..901f9c739 100644
--- a/kernel/bazaar/widget.go
+++ b/kernel/bazaar/widget.go
@@ -17,7 +17,6 @@
package bazaar
import (
- "errors"
"os"
"path/filepath"
"sort"
@@ -26,7 +25,6 @@ import (
"github.com/dustin/go-humanize"
ants "github.com/panjf2000/ants/v2"
- "github.com/siyuan-note/filelock"
"github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
@@ -180,14 +178,9 @@ func InstallWidget(repoURL, repoHash, installPath string, systemID string) error
if nil != err {
return err
}
- return installPackage(data, installPath)
+ return installPackage(data, installPath, repoURLHash)
}
func UninstallWidget(installPath string) error {
- if err := filelock.Remove(installPath); nil != err {
- logging.LogErrorf("remove widget [%s] failed: %s", installPath, err)
- return errors.New("remove community widget failed")
- }
- //logging.Logger.Infof("uninstalled widget [%s]", installPath)
- return nil
+ return uninstallPackage(installPath)
}
diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go
index d7bcd6918..4db2283f8 100644
--- a/kernel/model/attribute_view.go
+++ b/kernel/model/attribute_view.go
@@ -89,7 +89,7 @@ func GetAttributeViewPrimaryKeyValues(avID, keyword string, page, pageSize int)
}
keyValues.Values = []*av.Value{}
for _, v := range tmp {
- if strings.Contains(strings.ToLower(v.String()), strings.ToLower(keyword)) {
+ if strings.Contains(strings.ToLower(v.String(true)), strings.ToLower(keyword)) {
keyValues.Values = append(keyValues.Values, v)
}
}
@@ -145,7 +145,7 @@ func SearchAttributeViewNonRelationKey(avID, keyword string) (ret []*av.Key) {
}
for _, keyValues := range attrView.KeyValues {
- if av.KeyTypeRelation != keyValues.Key.Type && av.KeyTypeRollup != keyValues.Key.Type && av.KeyTypeTemplate != keyValues.Key.Type && av.KeyTypeCreated != keyValues.Key.Type && av.KeyTypeUpdated != keyValues.Key.Type {
+ if av.KeyTypeRelation != keyValues.Key.Type && av.KeyTypeRollup != keyValues.Key.Type && av.KeyTypeTemplate != keyValues.Key.Type && av.KeyTypeCreated != keyValues.Key.Type && av.KeyTypeUpdated != keyValues.Key.Type && av.KeyTypeLineNumber != keyValues.Key.Type {
if strings.Contains(strings.ToLower(keyValues.Key.Name), strings.ToLower(keyword)) {
ret = append(ret, keyValues.Key)
}
@@ -905,14 +905,33 @@ func renderTemplateCol(ial map[string]string, flashcard *Flashcard, rowValues []
dataModel[rowValue.Key.Name] = time.UnixMilli(v.Date.Content)
}
} else if av.KeyTypeRollup == v.Type {
- if 0 < len(v.Rollup.Contents) && av.KeyTypeNumber == v.Rollup.Contents[0].Type {
- // 模板使用汇总时支持数字计算
- // Template supports numerical calculations when using rollup https://github.com/siyuan-note/siyuan/issues/10810
- // 汇总数字时仅取第一个数字填充模板
- dataModel[rowValue.Key.Name] = v.Rollup.Contents[0].Number.Content
+ if 0 < len(v.Rollup.Contents) {
+ var numbers []float64
+ var contents []string
+ for _, content := range v.Rollup.Contents {
+ if av.KeyTypeNumber == content.Type {
+ numbers = append(numbers, content.Number.Content)
+ } else {
+ contents = append(contents, content.String(true))
+ }
+ }
+
+ if 0 < len(numbers) {
+ dataModel[rowValue.Key.Name] = numbers
+ } else {
+ dataModel[rowValue.Key.Name] = contents
+ }
+ }
+ } else if av.KeyTypeRelation == v.Type {
+ if 0 < len(v.Relation.Contents) {
+ var contents []string
+ for _, content := range v.Relation.Contents {
+ contents = append(contents, content.String(true))
+ }
+ dataModel[rowValue.Key.Name] = contents
}
} else {
- dataModel[rowValue.Key.Name] = v.String()
+ dataModel[rowValue.Key.Name] = v.String(true)
}
}
}
@@ -1218,7 +1237,7 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s
hit := false
for _, cell := range row.Cells {
for _, keyword := range keywords {
- if strings.Contains(strings.ToLower(cell.Value.String()), strings.ToLower(keyword)) {
+ if strings.Contains(strings.ToLower(cell.Value.String(true)), strings.ToLower(keyword)) {
hit = true
break
}
@@ -2635,7 +2654,7 @@ func AddAttributeViewKey(avID, keyID, keyName, keyType, keyIcon, previousKeyID s
switch keyTyp {
case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL, av.KeyTypeEmail,
av.KeyTypePhone, av.KeyTypeMAsset, av.KeyTypeTemplate, av.KeyTypeCreated, av.KeyTypeUpdated, av.KeyTypeCheckbox,
- av.KeyTypeRelation, av.KeyTypeRollup:
+ av.KeyTypeRelation, av.KeyTypeRollup, av.KeyTypeLineNumber:
key := av.NewKey(keyID, keyName, keyIcon, keyTyp)
if av.KeyTypeRollup == keyTyp {
@@ -2747,7 +2766,7 @@ func updateAttributeViewColumn(operation *Operation) (err error) {
switch colType {
case av.KeyTypeBlock, av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL, av.KeyTypeEmail,
av.KeyTypePhone, av.KeyTypeMAsset, av.KeyTypeTemplate, av.KeyTypeCreated, av.KeyTypeUpdated, av.KeyTypeCheckbox,
- av.KeyTypeRelation, av.KeyTypeRollup:
+ av.KeyTypeRelation, av.KeyTypeRollup, av.KeyTypeLineNumber:
for _, keyValues := range attrView.KeyValues {
if keyValues.Key.ID == operation.ID {
keyValues.Key.Name = strings.TrimSpace(operation.Name)
diff --git a/kernel/model/bazzar.go b/kernel/model/bazzar.go
index 432369ca2..dd77cdc42 100644
--- a/kernel/model/bazzar.go
+++ b/kernel/model/bazzar.go
@@ -19,16 +19,17 @@ package model
import (
"errors"
"fmt"
- "github.com/88250/gulu"
- "github.com/siyuan-note/logging"
- "github.com/siyuan-note/siyuan/kernel/util"
"path"
"path/filepath"
"strings"
"sync"
"time"
+ "github.com/88250/gulu"
+ "github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/bazaar"
+ "github.com/siyuan-note/siyuan/kernel/util"
+ "golang.org/x/mod/semver"
)
func BatchUpdateBazaarPackages(frontend string) {
@@ -202,9 +203,7 @@ func BazaarPlugins(frontend, keyword string) (plugins []*bazaar.Plugin) {
plugin.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "plugins", plugin.Name))
if plugin.Installed {
if pluginConf, err := bazaar.PluginJSON(plugin.Name); nil == err && nil != plugin {
- if plugin.Version != pluginConf.Version {
- plugin.Outdated = true
- }
+ plugin.Outdated = 0 > semver.Compare("v"+pluginConf.Version, "v"+plugin.Version)
}
}
}
@@ -273,9 +272,7 @@ func BazaarWidgets(keyword string) (widgets []*bazaar.Widget) {
widget.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "widgets", widget.Name))
if widget.Installed {
if widgetConf, err := bazaar.WidgetJSON(widget.Name); nil == err && nil != widget {
- if widget.Version != widgetConf.Version {
- widget.Outdated = true
- }
+ widget.Outdated = 0 > semver.Compare("v"+widgetConf.Version, "v"+widget.Version)
}
}
}
@@ -324,10 +321,8 @@ func BazaarIcons(keyword string) (icons []*bazaar.Icon) {
for _, icon := range icons {
if installed == icon.Name {
icon.Installed = true
- if themeConf, err := bazaar.IconJSON(icon.Name); nil == err {
- if icon.Version != themeConf.Version {
- icon.Outdated = true
- }
+ if iconConf, err := bazaar.IconJSON(icon.Name); nil == err {
+ icon.Outdated = 0 > semver.Compare("v"+iconConf.Version, "v"+icon.Version)
}
}
icon.Current = icon.Name == Conf.Appearance.Icon
@@ -389,7 +384,7 @@ func BazaarThemes(keyword string) (ret []*bazaar.Theme) {
if installed == theme.Name {
theme.Installed = true
if themeConf, err := bazaar.ThemeJSON(theme.Name); nil == err {
- theme.Outdated = theme.Version != themeConf.Version
+ theme.Outdated = 0 > semver.Compare("v"+themeConf.Version, "v"+theme.Version)
}
theme.Current = theme.Name == Conf.Appearance.ThemeDark || theme.Name == Conf.Appearance.ThemeLight
}
@@ -462,10 +457,8 @@ func BazaarTemplates(keyword string) (templates []*bazaar.Template) {
for _, template := range templates {
template.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "templates", template.Name))
if template.Installed {
- if themeConf, err := bazaar.TemplateJSON(template.Name); nil == err && nil != themeConf {
- if template.Version != themeConf.Version {
- template.Outdated = true
- }
+ if templateConf, err := bazaar.TemplateJSON(template.Name); nil == err && nil != templateConf {
+ template.Outdated = 0 > semver.Compare("v"+templateConf.Version, "v"+template.Version)
}
}
}
diff --git a/kernel/model/box.go b/kernel/model/box.go
index 450d9014b..8b2ad4d45 100644
--- a/kernel/model/box.go
+++ b/kernel/model/box.go
@@ -506,14 +506,15 @@ func FullReindex() {
}
func fullReindex() {
- util.PushMsg(Conf.Language(35), 7*1000)
+ util.PushEndlessProgress(Conf.language(35))
+ defer util.PushClearProgress()
+
WaitForWritingFiles()
if err := sql.InitDatabase(true); nil != err {
os.Exit(logging.ExitCodeReadOnlyDatabase)
return
}
- treenode.InitBlockTree(true)
sql.IndexIgnoreCached = false
openedBoxes := Conf.GetOpenedBoxes()
diff --git a/kernel/model/export.go b/kernel/model/export.go
index f3012adfe..c86f9165b 100644
--- a/kernel/model/export.go
+++ b/kernel/model/export.go
@@ -148,7 +148,7 @@ func ExportAv2CSV(avID, blockID string) (zipPath string, err error) {
}
}
- val = cell.Value.String()
+ val = cell.Value.String(true)
}
rowVal = append(rowVal, val)
@@ -2335,7 +2335,7 @@ func exportTree(tree *parse.Tree, wysiwyg, expandKaTexMacros, keepFold bool,
}
}
- val = cell.Value.String()
+ val = cell.Value.String(true)
}
mdTableCell.AppendChild(&ast.Node{Type: ast.NodeText, Tokens: []byte(val)})
}
diff --git a/kernel/model/tree.go b/kernel/model/tree.go
index db9d62d1d..a83e09a06 100644
--- a/kernel/model/tree.go
+++ b/kernel/model/tree.go
@@ -162,7 +162,7 @@ func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {
bt := treenode.GetBlockTree(id)
if nil == bt {
- if task.Contain(task.DatabaseIndex, task.DatabaseIndexFull) {
+ if task.ContainIndexTask() {
err = ErrIndexing
return
}
@@ -187,7 +187,7 @@ func LoadTreeByBlockID(id string) (ret *parse.Tree, err error) {
bt := treenode.GetBlockTree(id)
if nil == bt {
- if task.Contain(task.DatabaseIndex, task.DatabaseIndexFull) {
+ if task.ContainIndexTask() {
err = ErrIndexing
return
}
diff --git a/kernel/task/queue.go b/kernel/task/queue.go
index 4eba696ba..2baf64609 100644
--- a/kernel/task/queue.go
+++ b/kernel/task/queue.go
@@ -115,17 +115,13 @@ var uniqueActions = []string{
AssetContentDatabaseIndexCommit,
}
-func Contain(action string, moreActions ...string) bool {
- actions := append(moreActions, action)
- actions = gulu.Str.RemoveDuplicatedElem(actions)
-
- queueLock.Lock()
- for _, task := range taskQueue {
- if gulu.Str.Contains(task.Action, actions) {
+func ContainIndexTask() bool {
+ actions := getCurrentActions()
+ for _, action := range actions {
+ if gulu.Str.Contains(action, []string{DatabaseIndexFull, DatabaseIndex}) {
return true
}
}
- queueLock.Unlock()
return false
}
diff --git a/kernel/treenode/blocktree.go b/kernel/treenode/blocktree.go
index 536a141c5..823036acc 100644
--- a/kernel/treenode/blocktree.go
+++ b/kernel/treenode/blocktree.go
@@ -31,6 +31,7 @@ import (
"github.com/panjf2000/ants/v2"
util2 "github.com/siyuan-note/dejavu/util"
"github.com/siyuan-note/logging"
+ "github.com/siyuan-note/siyuan/kernel/task"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/vmihailenco/msgpack/v5"
)
@@ -504,6 +505,12 @@ func SaveBlockTree(force bool) {
blockTreeLock.Lock()
defer blockTreeLock.Unlock()
+ if task.ContainIndexTask() {
+ //logging.LogInfof("skip saving block tree because indexing")
+ return
+ }
+ //logging.LogInfof("saving block tree")
+
start := time.Now()
if err := os.MkdirAll(util.BlockTreePath, 0755); nil != err {
logging.LogErrorf("create block tree dir [%s] failed: %s", util.BlockTreePath, err)
diff --git a/kernel/treenode/node.go b/kernel/treenode/node.go
index 91b31af85..db65da824 100644
--- a/kernel/treenode/node.go
+++ b/kernel/treenode/node.go
@@ -598,7 +598,7 @@ func getAttributeViewContent(avID string) (content string) {
if nil == cell.Value {
continue
}
- buf.WriteString(cell.Value.String())
+ buf.WriteString(cell.Value.String(true))
buf.WriteByte(' ')
}
}
@@ -1050,12 +1050,33 @@ func renderTemplateCol(ial map[string]string, rowValues []*av.KeyValues, tplCont
dataModel[rowValue.Key.Name] = time.UnixMilli(v.Date.Content)
}
} else if av.KeyTypeRollup == v.Type {
- if 0 < len(v.Rollup.Contents) && av.KeyTypeNumber == v.Rollup.Contents[0].Type {
- // 汇总数字时仅取第一个数字填充模板
- dataModel[rowValue.Key.Name] = v.Rollup.Contents[0].Number.Content
+ if 0 < len(v.Rollup.Contents) {
+ var numbers []float64
+ var contents []string
+ for _, content := range v.Rollup.Contents {
+ if av.KeyTypeNumber == content.Type {
+ numbers = append(numbers, content.Number.Content)
+ } else {
+ contents = append(contents, content.String(true))
+ }
+ }
+
+ if 0 < len(numbers) {
+ dataModel[rowValue.Key.Name] = numbers
+ } else {
+ dataModel[rowValue.Key.Name] = contents
+ }
+ }
+ } else if av.KeyTypeRelation == v.Type {
+ if 0 < len(v.Relation.Contents) {
+ var contents []string
+ for _, content := range v.Relation.Contents {
+ contents = append(contents, content.String(true))
+ }
+ dataModel[rowValue.Key.Name] = contents
}
} else {
- dataModel[rowValue.Key.Name] = v.String()
+ dataModel[rowValue.Key.Name] = v.String(true)
}
}
}