mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-22 17:40:13 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
9e1fc704c9
32 changed files with 390 additions and 243 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -24,6 +24,7 @@ electron/dist
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.idea/
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
# Log
|
# Log
|
||||||
logs
|
logs
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@
|
||||||
"goToEditTabPrev": "Go to previous edited tab",
|
"goToEditTabPrev": "Go to previous edited tab",
|
||||||
"createdTime": "Created time",
|
"createdTime": "Created time",
|
||||||
"updatedTime": "Updated time",
|
"updatedTime": "Updated time",
|
||||||
|
"lineNumber": "Line number",
|
||||||
"removeBookmark": "Remove bookmark from ${x}?",
|
"removeBookmark": "Remove bookmark from ${x}?",
|
||||||
"defaultMargin": "Default",
|
"defaultMargin": "Default",
|
||||||
"noneMargin": "None",
|
"noneMargin": "None",
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@
|
||||||
"goToEditTabPrev": "Ir a la pestaña editada anteriormente",
|
"goToEditTabPrev": "Ir a la pestaña editada anteriormente",
|
||||||
"createdTime": "Hora de creación",
|
"createdTime": "Hora de creación",
|
||||||
"updatedTime": "Hora actualizada",
|
"updatedTime": "Hora actualizada",
|
||||||
|
"lineNumber": "Número de línea",
|
||||||
"removeBookmark": "¿Eliminar marcador de ${x}?",
|
"removeBookmark": "¿Eliminar marcador de ${x}?",
|
||||||
"lockEdit": "Hacer que el documento sea de sólo lectura",
|
"lockEdit": "Hacer que el documento sea de sólo lectura",
|
||||||
"unlockEdit": "Hacer que el documento sea escribible",
|
"unlockEdit": "Hacer que el documento sea escribible",
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@
|
||||||
"goToEditTabPrev": "Aller à l'onglet modifié précédent",
|
"goToEditTabPrev": "Aller à l'onglet modifié précédent",
|
||||||
"createdTime": "Heure de création",
|
"createdTime": "Heure de création",
|
||||||
"updatedTime": "Heure mise à jour",
|
"updatedTime": "Heure mise à jour",
|
||||||
|
"lineNumber": "Numéro de ligne",
|
||||||
"removeBookmark": "Supprimer le signet de ${x} ?",
|
"removeBookmark": "Supprimer le signet de ${x} ?",
|
||||||
"lockEdit": "Rendre le document en lecture seule",
|
"lockEdit": "Rendre le document en lecture seule",
|
||||||
"unlockEdit": "Rendre le document accessible en écriture",
|
"unlockEdit": "Rendre le document accessible en écriture",
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@
|
||||||
"goToEditTabPrev": "跳到上一個編輯頁籤",
|
"goToEditTabPrev": "跳到上一個編輯頁籤",
|
||||||
"createdTime": "建立時間",
|
"createdTime": "建立時間",
|
||||||
"updatedTime": "更新時間",
|
"updatedTime": "更新時間",
|
||||||
|
"lineNumber": "行號",
|
||||||
"removeBookmark": "移除 ${x} 中的書籤?",
|
"removeBookmark": "移除 ${x} 中的書籤?",
|
||||||
"lockEdit": "鎖定編輯",
|
"lockEdit": "鎖定編輯",
|
||||||
"unlockEdit": "解除鎖定",
|
"unlockEdit": "解除鎖定",
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@
|
||||||
"goToEditTabPrev": "跳转到上一个编辑页签",
|
"goToEditTabPrev": "跳转到上一个编辑页签",
|
||||||
"createdTime": "创建时间",
|
"createdTime": "创建时间",
|
||||||
"updatedTime": "更新时间",
|
"updatedTime": "更新时间",
|
||||||
|
"lineNumber": "行号",
|
||||||
"removeBookmark": "移除 ${x} 中的书签?",
|
"removeBookmark": "移除 ${x} 中的书签?",
|
||||||
"lockEdit": "锁定编辑",
|
"lockEdit": "锁定编辑",
|
||||||
"unlockEdit": "解除锁定",
|
"unlockEdit": "解除锁定",
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,8 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const type = getTypeByCellElement(target);
|
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");
|
selectRow(rowElement.querySelector(".av__firstcol"), "toggle");
|
||||||
} else {
|
} else {
|
||||||
scrollElement.querySelectorAll(".av__row--select").forEach(item => {
|
scrollElement.querySelectorAll(".av__row--select").forEach(item => {
|
||||||
|
|
|
||||||
|
|
@ -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 = "";
|
let text = "";
|
||||||
if (["text", "template"].includes(cellValue.type)) {
|
if (["text", "template"].includes(cellValue.type)) {
|
||||||
text = `<span class="av__celltext">${cellValue ? (cellValue[cellValue.type as "text"].content || "") : ""}</span>`;
|
text = `<span class="av__celltext">${cellValue ? (cellValue[cellValue.type as "text"].content || "") : ""}</span>`;
|
||||||
|
|
@ -683,6 +683,9 @@ export const renderCell = (cellValue: IAVCellValue) => {
|
||||||
text += dayjs(dataValue.content).format("YYYY-MM-DD HH:mm");
|
text += dayjs(dataValue.content).format("YYYY-MM-DD HH:mm");
|
||||||
}
|
}
|
||||||
text += "</span>";
|
text += "</span>";
|
||||||
|
} else if (["lineNumber"].includes(cellValue.type)) {
|
||||||
|
// 渲染行号
|
||||||
|
text = `<span class="av__celltext" data-value='${rowIndex + 1}'>${rowIndex + 1}</span>`;
|
||||||
} else if (cellValue.type === "mAsset") {
|
} else if (cellValue.type === "mAsset") {
|
||||||
cellValue?.mAsset?.forEach((item) => {
|
cellValue?.mAsset?.forEach((item) => {
|
||||||
if (item.type === "image") {
|
if (item.type === "image") {
|
||||||
|
|
@ -713,8 +716,9 @@ export const renderCell = (cellValue: IAVCellValue) => {
|
||||||
text = text.substring(0, text.length - 2);
|
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 += `<span ${cellValue.type !== "number" ? "" : 'style="right:auto;left:5px"'} data-type="copy" class="block__icon"><svg><use xlink:href="#iconCopy"></use></svg></span>`;
|
text += `<span ${cellValue.type !== "number" ? "" : 'style="right:auto;left:5px"'} data-type="copy" class="block__icon"><svg><use xlink:href="#iconCopy"></use></svg></span>`;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,7 @@ export const getEditHTML = (options: {
|
||||||
${genUpdateColItem("template", colData.type)}
|
${genUpdateColItem("template", colData.type)}
|
||||||
${genUpdateColItem("relation", colData.type)}
|
${genUpdateColItem("relation", colData.type)}
|
||||||
${genUpdateColItem("rollup", colData.type)}
|
${genUpdateColItem("rollup", colData.type)}
|
||||||
|
${genUpdateColItem("lineNumber", colData.type)}
|
||||||
${genUpdateColItem("created", colData.type)}
|
${genUpdateColItem("created", colData.type)}
|
||||||
${genUpdateColItem("updated", colData.type)}
|
${genUpdateColItem("updated", colData.type)}
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
@ -482,6 +483,8 @@ export const getColNameByType = (type: TAVCol) => {
|
||||||
return window.siyuan.languages.checkbox;
|
return window.siyuan.languages.checkbox;
|
||||||
case "block":
|
case "block":
|
||||||
return window.siyuan.languages["_attrView"].key;
|
return window.siyuan.languages["_attrView"].key;
|
||||||
|
case "lineNumber":
|
||||||
|
return window.siyuan.languages.lineNumber;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -518,6 +521,8 @@ export const getColIconByType = (type: TAVCol) => {
|
||||||
return "iconMath";
|
return "iconMath";
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
return "iconCheck";
|
return "iconCheck";
|
||||||
|
case "lineNumber":
|
||||||
|
return "iconSpreadOdd";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -694,90 +699,94 @@ export const showColMenu = (protyle: IProtyle, blockElement: Element, cellElemen
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
menu.addItem({
|
|
||||||
icon: "iconUp",
|
// 行号 类型不参与 排序和筛选
|
||||||
label: window.siyuan.languages.asc,
|
if (type !== "lineNumber") {
|
||||||
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") {
|
|
||||||
menu.addItem({
|
menu.addItem({
|
||||||
icon: "iconFilter",
|
icon: "iconUp",
|
||||||
label: window.siyuan.languages.filter,
|
label: window.siyuan.languages.asc,
|
||||||
click() {
|
click() {
|
||||||
fetchPost("/api/av/renderAttributeView", {
|
fetchPost("/api/av/renderAttributeView", {
|
||||||
id: avID,
|
id: avID,
|
||||||
}, (response) => {
|
}, (response) => {
|
||||||
const avData = response.data as IAV;
|
transaction(protyle, [{
|
||||||
let filter: IAVFilter;
|
action: "setAttrViewSorts",
|
||||||
avData.view.filters.find((item) => {
|
avID: response.data.id,
|
||||||
if (item.column === colId && item.value.type === type) {
|
data: [{
|
||||||
filter = item;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!filter) {
|
|
||||||
filter = {
|
|
||||||
column: colId,
|
column: colId,
|
||||||
operator: getDefaultOperatorByType(type),
|
order: "ASC"
|
||||||
value: genCellValue(type, ""),
|
}],
|
||||||
};
|
blockID
|
||||||
avData.view.filters.push(filter);
|
}], [{
|
||||||
}
|
action: "setAttrViewSorts",
|
||||||
setFilter({
|
avID: response.data.id,
|
||||||
filter,
|
data: response.data.view.sorts,
|
||||||
protyle,
|
blockID
|
||||||
data: avData,
|
}]);
|
||||||
blockElement: blockElement,
|
|
||||||
target: blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
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({
|
menu.addItem({
|
||||||
icon: "iconInsertLeft",
|
icon: "iconInsertLeft",
|
||||||
|
|
@ -1429,6 +1438,44 @@ export const addCol = (protyle: IProtyle, blockElement: Element, previousID?: st
|
||||||
blockElement.setAttribute("updated", newUpdated);
|
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({
|
menu.addItem({
|
||||||
icon: "iconClock",
|
icon: "iconClock",
|
||||||
label: window.siyuan.languages.createdTime,
|
label: window.siyuan.languages.createdTime,
|
||||||
|
|
|
||||||
|
|
@ -566,7 +566,8 @@ export const addFilter = (options: {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!filter && column.type !== "mAsset") {
|
// 该列是行号类型列,则不允许添加到过滤器
|
||||||
|
if (!filter && column.type !== "mAsset" && column.type !== "lineNumber") {
|
||||||
menu.addItem({
|
menu.addItem({
|
||||||
label: column.name,
|
label: column.name,
|
||||||
iconHTML: column.icon ? unicode2Emoji(column.icon, "b3-menu__icon", true) : `<svg class="b3-menu__icon"><use xlink:href="#${getColIconByType(column.type)}"></use></svg>`,
|
iconHTML: column.icon ? unicode2Emoji(column.icon, "b3-menu__icon", true) : `<svg class="b3-menu__icon"><use xlink:href="#${getColIconByType(column.type)}"></use></svg>`,
|
||||||
|
|
|
||||||
|
|
@ -854,6 +854,46 @@ export const openMenuPanel = (options: {
|
||||||
name,
|
name,
|
||||||
type: target.dataset.oldType as TAVCol,
|
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();
|
avPanelElement.remove();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,16 @@ style="width: ${column.width || "200px"};">
|
||||||
if (pinIndex === index) {
|
if (pinIndex === index) {
|
||||||
tableHTML += "</div>";
|
tableHTML += "</div>";
|
||||||
}
|
}
|
||||||
calcHTML += `<div class="av__calc${column.calc && column.calc.operator !== "" ? " av__calc--ashow" : ""}" data-col-id="${column.id}" data-dtype="${column.type}" data-operator="${column.calc?.operator || ""}"
|
|
||||||
style="width: ${index === 0 ? ((parseInt(column.width || "200") + 24) + "px") : (column.width || "200px")}">${getCalcValue(column) || '<svg><use xlink:href="#iconDown"></use></svg>' + window.siyuan.languages.calc}</div>`;
|
// lineNumber type 不参与计算操作
|
||||||
|
if (column.type === "lineNumber") {
|
||||||
|
calcHTML += `<div data-col-id="${column.id}" data-dtype="${column.type}"
|
||||||
|
style="display: flex; width: ${index === 0 ? ((parseInt(column.width || "200") + 24) + "px") : (column.width || "200px")}"> </div>`;
|
||||||
|
} else {
|
||||||
|
calcHTML += `<div class="av__calc${column.calc && column.calc.operator !== "" ? " av__calc--ashow" : ""}" data-col-id="${column.id}" data-dtype="${column.type}" data-operator="${column.calc?.operator || ""}"
|
||||||
|
style="width: ${index === 0 ? ((parseInt(column.width || "200") + 24) + "px") : (column.width || "200px")}">${getCalcValue(column) || '<svg><use xlink:href="#iconDown"></use></svg>' + window.siyuan.languages.calc}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
if (pinIndex === index) {
|
if (pinIndex === index) {
|
||||||
calcHTML += "</div>";
|
calcHTML += "</div>";
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +150,7 @@ style="width: ${index === 0 ? ((parseInt(column.width || "200") + 24) + "px") :
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
// body
|
// body
|
||||||
data.rows.forEach((row: IAVRow) => {
|
data.rows.forEach((row: IAVRow, rowIndex: number) => {
|
||||||
tableHTML += `<div class="av__row" data-id="${row.id}">`;
|
tableHTML += `<div class="av__row" data-id="${row.id}">`;
|
||||||
if (pinIndex > -1) {
|
if (pinIndex > -1) {
|
||||||
tableHTML += '<div class="av__colsticky"><div class="av__firstcol"><svg><use xlink:href="#iconUncheck"></use></svg></div>';
|
tableHTML += '<div class="av__colsticky"><div class="av__firstcol"><svg><use xlink:href="#iconUncheck"></use></svg></div>';
|
||||||
|
|
@ -165,7 +173,7 @@ ${cell.value?.isDetached ? ' data-detached="true"' : ""}
|
||||||
style="width: ${data.columns[index].width || "200px"};
|
style="width: ${data.columns[index].width || "200px"};
|
||||||
${cell.valueType === "number" ? "text-align: right;" : ""}
|
${cell.valueType === "number" ? "text-align: right;" : ""}
|
||||||
${cell.bgColor ? `background-color:${cell.bgColor};` : ""}
|
${cell.bgColor ? `background-color:${cell.bgColor};` : ""}
|
||||||
${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value)}</div>`;
|
${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value, rowIndex)}</div>`;
|
||||||
|
|
||||||
if (pinIndex === index) {
|
if (pinIndex === index) {
|
||||||
tableHTML += "</div>";
|
tableHTML += "</div>";
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,19 @@ export const addSort = (options: {
|
||||||
const menu = new Menu("av-add-sort");
|
const menu = new Menu("av-add-sort");
|
||||||
options.data.view.columns.forEach((column) => {
|
options.data.view.columns.forEach((column) => {
|
||||||
let hasSort = false;
|
let hasSort = false;
|
||||||
options.data.view.sorts.find((sort) => {
|
|
||||||
if (sort.column === column.id) {
|
// 如果该列是行号类型列,不允许添加排序
|
||||||
hasSort = true;
|
if (column.type === "lineNumber") {
|
||||||
return true;
|
hasSort = true;
|
||||||
}
|
} else {
|
||||||
});
|
options.data.view.sorts.find((sort) => {
|
||||||
|
if (sort.column === column.id) {
|
||||||
|
hasSort = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasSort) {
|
if (!hasSort) {
|
||||||
menu.addItem({
|
menu.addItem({
|
||||||
label: column.name,
|
label: column.name,
|
||||||
|
|
|
||||||
1
app/src/types/index.d.ts
vendored
1
app/src/types/index.d.ts
vendored
|
|
@ -82,6 +82,7 @@ type TAVCol =
|
||||||
| "created"
|
| "created"
|
||||||
| "updated"
|
| "updated"
|
||||||
| "checkbox"
|
| "checkbox"
|
||||||
|
| "lineNumber"
|
||||||
type THintSource = "search" | "av" | "hint";
|
type THintSource = "search" | "av" | "hint";
|
||||||
type TAVFilterOperator =
|
type TAVFilterOperator =
|
||||||
"="
|
"="
|
||||||
|
|
|
||||||
|
|
@ -64,22 +64,23 @@ func (kValues *KeyValues) GetValue(blockID string) (ret *Value) {
|
||||||
type KeyType string
|
type KeyType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KeyTypeBlock KeyType = "block"
|
KeyTypeBlock KeyType = "block"
|
||||||
KeyTypeText KeyType = "text"
|
KeyTypeText KeyType = "text"
|
||||||
KeyTypeNumber KeyType = "number"
|
KeyTypeNumber KeyType = "number"
|
||||||
KeyTypeDate KeyType = "date"
|
KeyTypeDate KeyType = "date"
|
||||||
KeyTypeSelect KeyType = "select"
|
KeyTypeSelect KeyType = "select"
|
||||||
KeyTypeMSelect KeyType = "mSelect"
|
KeyTypeMSelect KeyType = "mSelect"
|
||||||
KeyTypeURL KeyType = "url"
|
KeyTypeURL KeyType = "url"
|
||||||
KeyTypeEmail KeyType = "email"
|
KeyTypeEmail KeyType = "email"
|
||||||
KeyTypePhone KeyType = "phone"
|
KeyTypePhone KeyType = "phone"
|
||||||
KeyTypeMAsset KeyType = "mAsset"
|
KeyTypeMAsset KeyType = "mAsset"
|
||||||
KeyTypeTemplate KeyType = "template"
|
KeyTypeTemplate KeyType = "template"
|
||||||
KeyTypeCreated KeyType = "created"
|
KeyTypeCreated KeyType = "created"
|
||||||
KeyTypeUpdated KeyType = "updated"
|
KeyTypeUpdated KeyType = "updated"
|
||||||
KeyTypeCheckbox KeyType = "checkbox"
|
KeyTypeCheckbox KeyType = "checkbox"
|
||||||
KeyTypeRelation KeyType = "relation"
|
KeyTypeRelation KeyType = "relation"
|
||||||
KeyTypeRollup KeyType = "rollup"
|
KeyTypeRollup KeyType = "rollup"
|
||||||
|
KeyTypeLineNumber KeyType = "lineNumber"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Key 描述了属性视图属性列的基础结构。
|
// Key 描述了属性视图属性列的基础结构。
|
||||||
|
|
|
||||||
|
|
@ -220,59 +220,62 @@ func (value *Value) Compare(other *Value, attrView *AttributeView) int {
|
||||||
}
|
}
|
||||||
case KeyTypeRelation:
|
case KeyTypeRelation:
|
||||||
if nil != value.Relation && nil != other.Relation {
|
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{}
|
vContentBuf := bytes.Buffer{}
|
||||||
for _, c := range value.Relation.Contents {
|
for _, c := range value.Relation.Contents {
|
||||||
vContentBuf.WriteString(c.String())
|
vContentBuf.WriteString(c.String(true))
|
||||||
vContentBuf.WriteByte(' ')
|
vContentBuf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
vContent := strings.TrimSpace(vContentBuf.String())
|
vContent := strings.TrimSpace(vContentBuf.String())
|
||||||
oContentBuf := bytes.Buffer{}
|
oContentBuf := bytes.Buffer{}
|
||||||
for _, c := range other.Relation.Contents {
|
for _, c := range other.Relation.Contents {
|
||||||
oContentBuf.WriteString(c.String())
|
oContentBuf.WriteString(c.String(true))
|
||||||
oContentBuf.WriteByte(' ')
|
oContentBuf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
oContent := strings.TrimSpace(oContentBuf.String())
|
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)
|
return strings.Compare(vContent, oContent)
|
||||||
}
|
}
|
||||||
case KeyTypeRollup:
|
case KeyTypeRollup:
|
||||||
if nil != value.Rollup && nil != other.Rollup {
|
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{}
|
vContentBuf := bytes.Buffer{}
|
||||||
for _, c := range value.Rollup.Contents {
|
for _, c := range value.Rollup.Contents {
|
||||||
vContentBuf.WriteString(c.String())
|
vContentBuf.WriteString(c.String(true))
|
||||||
vContentBuf.WriteByte(' ')
|
vContentBuf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
vContent := strings.TrimSpace(vContentBuf.String())
|
vContent := strings.TrimSpace(vContentBuf.String())
|
||||||
oContentBuf := bytes.Buffer{}
|
oContentBuf := bytes.Buffer{}
|
||||||
for _, c := range other.Rollup.Contents {
|
for _, c := range other.Rollup.Contents {
|
||||||
oContentBuf.WriteString(c.String())
|
oContentBuf.WriteString(c.String(true))
|
||||||
oContentBuf.WriteByte(' ')
|
oContentBuf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
oContent := strings.TrimSpace(oContentBuf.String())
|
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)
|
return strings.Compare(vContent, oContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1586,8 +1586,8 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
for _, row := range table.Rows {
|
||||||
if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
if !uniqueValues[content.String()] {
|
if !uniqueValues[content.String(true)] {
|
||||||
uniqueValues[content.String()] = true
|
uniqueValues[content.String(true)] = true
|
||||||
countUniqueValues++
|
countUniqueValues++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1635,7 +1635,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
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) {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
val, _ := util.Convert2Float(content.String())
|
val, _ := util.Convert2Float(content.String(false))
|
||||||
sum += val
|
sum += val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1647,7 +1647,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
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) {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
val, _ := util.Convert2Float(content.String())
|
val, _ := util.Convert2Float(content.String(false))
|
||||||
sum += val
|
sum += val
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
|
@ -1661,7 +1661,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
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) {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
val, _ := util.Convert2Float(content.String())
|
val, _ := util.Convert2Float(content.String(false))
|
||||||
values = append(values, val)
|
values = append(values, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1679,7 +1679,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
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) {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
val, _ := util.Convert2Float(content.String())
|
val, _ := util.Convert2Float(content.String(false))
|
||||||
if val < minVal {
|
if val < minVal {
|
||||||
minVal = val
|
minVal = val
|
||||||
}
|
}
|
||||||
|
|
@ -1694,7 +1694,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
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) {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
val, _ := util.Convert2Float(content.String())
|
val, _ := util.Convert2Float(content.String(false))
|
||||||
if val > maxVal {
|
if val > maxVal {
|
||||||
maxVal = val
|
maxVal = val
|
||||||
}
|
}
|
||||||
|
|
@ -1710,7 +1710,7 @@ func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
|
||||||
for _, row := range table.Rows {
|
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) {
|
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 {
|
for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
|
||||||
val, _ := util.Convert2Float(content.String())
|
val, _ := util.Convert2Float(content.String(false))
|
||||||
if val < minVal {
|
if val < minVal {
|
||||||
minVal = val
|
minVal = val
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
if nil == value {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +84,10 @@ func (value *Value) String() string {
|
||||||
if nil == value.Number {
|
if nil == value.Number {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return value.Number.FormattedContent
|
if format {
|
||||||
|
return value.Number.FormattedContent
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%f", value.Number.Content)
|
||||||
case KeyTypeDate:
|
case KeyTypeDate:
|
||||||
if nil == value.Date {
|
if nil == value.Date {
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -158,7 +161,7 @@ func (value *Value) String() string {
|
||||||
}
|
}
|
||||||
var ret []string
|
var ret []string
|
||||||
for _, v := range value.Relation.Contents {
|
for _, v := range value.Relation.Contents {
|
||||||
ret = append(ret, v.String())
|
ret = append(ret, v.String(format))
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(strings.Join(ret, ", "))
|
return strings.TrimSpace(strings.Join(ret, ", "))
|
||||||
case KeyTypeRollup:
|
case KeyTypeRollup:
|
||||||
|
|
@ -167,7 +170,7 @@ func (value *Value) String() string {
|
||||||
}
|
}
|
||||||
var ret []string
|
var ret []string
|
||||||
for _, v := range value.Rollup.Contents {
|
for _, v := range value.Rollup.Contents {
|
||||||
ret = append(ret, v.String())
|
ret = append(ret, v.String(format))
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(strings.Join(ret, ", "))
|
return strings.TrimSpace(strings.Join(ret, ", "))
|
||||||
default:
|
default:
|
||||||
|
|
@ -679,8 +682,8 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
|
||||||
countUniqueValues := 0
|
countUniqueValues := 0
|
||||||
uniqueValues := map[string]bool{}
|
uniqueValues := map[string]bool{}
|
||||||
for _, v := range r.Contents {
|
for _, v := range r.Contents {
|
||||||
if _, ok := uniqueValues[v.String()]; !ok {
|
if _, ok := uniqueValues[v.String(true)]; !ok {
|
||||||
uniqueValues[v.String()] = true
|
uniqueValues[v.String(true)] = true
|
||||||
countUniqueValues++
|
countUniqueValues++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -688,7 +691,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
|
||||||
case CalcOperatorCountEmpty:
|
case CalcOperatorCountEmpty:
|
||||||
countEmpty := 0
|
countEmpty := 0
|
||||||
for _, v := range r.Contents {
|
for _, v := range r.Contents {
|
||||||
if "" == v.String() {
|
if "" == v.String(true) {
|
||||||
countEmpty++
|
countEmpty++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -696,7 +699,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
|
||||||
case CalcOperatorCountNotEmpty:
|
case CalcOperatorCountNotEmpty:
|
||||||
countNonEmpty := 0
|
countNonEmpty := 0
|
||||||
for _, v := range r.Contents {
|
for _, v := range r.Contents {
|
||||||
if "" != v.String() {
|
if "" != v.String(true) {
|
||||||
countNonEmpty++
|
countNonEmpty++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -704,7 +707,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
|
||||||
case CalcOperatorPercentEmpty:
|
case CalcOperatorPercentEmpty:
|
||||||
countEmpty := 0
|
countEmpty := 0
|
||||||
for _, v := range r.Contents {
|
for _, v := range r.Contents {
|
||||||
if "" == v.String() {
|
if "" == v.String(true) {
|
||||||
countEmpty++
|
countEmpty++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -714,7 +717,7 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
|
||||||
case CalcOperatorPercentNotEmpty:
|
case CalcOperatorPercentNotEmpty:
|
||||||
countNonEmpty := 0
|
countNonEmpty := 0
|
||||||
for _, v := range r.Contents {
|
for _, v := range r.Contents {
|
||||||
if "" != v.String() {
|
if "" != v.String(true) {
|
||||||
countNonEmpty++
|
countNonEmpty++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package bazaar
|
package bazaar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -184,14 +183,9 @@ func InstallIcon(repoURL, repoHash, installPath string, systemID string) error {
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return installPackage(data, installPath)
|
return installPackage(data, installPath, repoURLHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UninstallIcon(installPath string) error {
|
func UninstallIcon(installPath string) error {
|
||||||
if err := os.RemoveAll(installPath); nil != err {
|
return uninstallPackage(installPath)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package bazaar
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -588,7 +589,26 @@ func incPackageDownloads(repoURLHash, systemID string) {
|
||||||
}).Post(u)
|
}).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")
|
tmpPackage := filepath.Join(util.TempDir, "bazaar", "package")
|
||||||
if err = os.MkdirAll(tmpPackage, 0755); nil != err {
|
if err = os.MkdirAll(tmpPackage, 0755); nil != err {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package bazaar
|
package bazaar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -27,7 +26,6 @@ import (
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
ants "github.com/panjf2000/ants/v2"
|
ants "github.com/panjf2000/ants/v2"
|
||||||
"github.com/siyuan-note/filelock"
|
|
||||||
"github.com/siyuan-note/httpclient"
|
"github.com/siyuan-note/httpclient"
|
||||||
"github.com/siyuan-note/logging"
|
"github.com/siyuan-note/logging"
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
|
|
@ -220,16 +218,11 @@ func InstallPlugin(repoURL, repoHash, installPath string, systemID string) error
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return installPackage(data, installPath)
|
return installPackage(data, installPath, repoURLHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UninstallPlugin(installPath string) error {
|
func UninstallPlugin(installPath string) error {
|
||||||
if err := filelock.Remove(installPath); nil != err {
|
return uninstallPackage(installPath)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIncompatiblePlugin(plugin *Plugin, currentFrontend string) bool {
|
func isIncompatiblePlugin(plugin *Plugin, currentFrontend string) bool {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package bazaar
|
package bazaar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -27,7 +26,6 @@ import (
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"github.com/siyuan-note/filelock"
|
|
||||||
"github.com/siyuan-note/httpclient"
|
"github.com/siyuan-note/httpclient"
|
||||||
"github.com/siyuan-note/logging"
|
"github.com/siyuan-note/logging"
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
|
|
@ -182,15 +180,11 @@ func InstallTemplate(repoURL, repoHash, installPath string, systemID string) err
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return installPackage(data, installPath)
|
return installPackage(data, installPath, repoURLHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UninstallTemplate(installPath string) error {
|
func UninstallTemplate(installPath string) error {
|
||||||
if err := filelock.Remove(installPath); nil != err {
|
return uninstallPackage(installPath)
|
||||||
logging.LogErrorf("remove template [%s] failed: %s", installPath, err)
|
|
||||||
return errors.New("remove community template failed")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterLegacyTemplates(templates []*Template) (ret []*Template) {
|
func filterLegacyTemplates(templates []*Template) (ret []*Template) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package bazaar
|
package bazaar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -186,14 +185,9 @@ func InstallTheme(repoURL, repoHash, installPath string, systemID string) error
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return installPackage(data, installPath)
|
return installPackage(data, installPath, repoURLHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UninstallTheme(installPath string) error {
|
func UninstallTheme(installPath string) error {
|
||||||
if err := os.RemoveAll(installPath); nil != err {
|
return uninstallPackage(installPath)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package bazaar
|
package bazaar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -26,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
ants "github.com/panjf2000/ants/v2"
|
ants "github.com/panjf2000/ants/v2"
|
||||||
"github.com/siyuan-note/filelock"
|
|
||||||
"github.com/siyuan-note/httpclient"
|
"github.com/siyuan-note/httpclient"
|
||||||
"github.com/siyuan-note/logging"
|
"github.com/siyuan-note/logging"
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
|
|
@ -180,14 +178,9 @@ func InstallWidget(repoURL, repoHash, installPath string, systemID string) error
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return installPackage(data, installPath)
|
return installPackage(data, installPath, repoURLHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UninstallWidget(installPath string) error {
|
func UninstallWidget(installPath string) error {
|
||||||
if err := filelock.Remove(installPath); nil != err {
|
return uninstallPackage(installPath)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func GetAttributeViewPrimaryKeyValues(avID, keyword string, page, pageSize int)
|
||||||
}
|
}
|
||||||
keyValues.Values = []*av.Value{}
|
keyValues.Values = []*av.Value{}
|
||||||
for _, v := range tmp {
|
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)
|
keyValues.Values = append(keyValues.Values, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +145,7 @@ func SearchAttributeViewNonRelationKey(avID, keyword string) (ret []*av.Key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, keyValues := range attrView.KeyValues {
|
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)) {
|
if strings.Contains(strings.ToLower(keyValues.Key.Name), strings.ToLower(keyword)) {
|
||||||
ret = append(ret, keyValues.Key)
|
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)
|
dataModel[rowValue.Key.Name] = time.UnixMilli(v.Date.Content)
|
||||||
}
|
}
|
||||||
} else if av.KeyTypeRollup == v.Type {
|
} else if av.KeyTypeRollup == v.Type {
|
||||||
if 0 < len(v.Rollup.Contents) && av.KeyTypeNumber == v.Rollup.Contents[0].Type {
|
if 0 < len(v.Rollup.Contents) {
|
||||||
// 模板使用汇总时支持数字计算
|
var numbers []float64
|
||||||
// Template supports numerical calculations when using rollup https://github.com/siyuan-note/siyuan/issues/10810
|
var contents []string
|
||||||
// 汇总数字时仅取第一个数字填充模板
|
for _, content := range v.Rollup.Contents {
|
||||||
dataModel[rowValue.Key.Name] = v.Rollup.Contents[0].Number.Content
|
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 {
|
} 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
|
hit := false
|
||||||
for _, cell := range row.Cells {
|
for _, cell := range row.Cells {
|
||||||
for _, keyword := range keywords {
|
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
|
hit = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -2635,7 +2654,7 @@ func AddAttributeViewKey(avID, keyID, keyName, keyType, keyIcon, previousKeyID s
|
||||||
switch keyTyp {
|
switch keyTyp {
|
||||||
case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL, av.KeyTypeEmail,
|
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.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)
|
key := av.NewKey(keyID, keyName, keyIcon, keyTyp)
|
||||||
if av.KeyTypeRollup == keyTyp {
|
if av.KeyTypeRollup == keyTyp {
|
||||||
|
|
@ -2747,7 +2766,7 @@ func updateAttributeViewColumn(operation *Operation) (err error) {
|
||||||
switch colType {
|
switch colType {
|
||||||
case av.KeyTypeBlock, av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL, av.KeyTypeEmail,
|
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.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 {
|
for _, keyValues := range attrView.KeyValues {
|
||||||
if keyValues.Key.ID == operation.ID {
|
if keyValues.Key.ID == operation.ID {
|
||||||
keyValues.Key.Name = strings.TrimSpace(operation.Name)
|
keyValues.Key.Name = strings.TrimSpace(operation.Name)
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,17 @@ package model
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/88250/gulu"
|
|
||||||
"github.com/siyuan-note/logging"
|
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/88250/gulu"
|
||||||
|
"github.com/siyuan-note/logging"
|
||||||
"github.com/siyuan-note/siyuan/kernel/bazaar"
|
"github.com/siyuan-note/siyuan/kernel/bazaar"
|
||||||
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BatchUpdateBazaarPackages(frontend string) {
|
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))
|
plugin.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "plugins", plugin.Name))
|
||||||
if plugin.Installed {
|
if plugin.Installed {
|
||||||
if pluginConf, err := bazaar.PluginJSON(plugin.Name); nil == err && nil != plugin {
|
if pluginConf, err := bazaar.PluginJSON(plugin.Name); nil == err && nil != plugin {
|
||||||
if plugin.Version != pluginConf.Version {
|
plugin.Outdated = 0 > semver.Compare("v"+pluginConf.Version, "v"+plugin.Version)
|
||||||
plugin.Outdated = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -273,9 +272,7 @@ func BazaarWidgets(keyword string) (widgets []*bazaar.Widget) {
|
||||||
widget.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "widgets", widget.Name))
|
widget.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "widgets", widget.Name))
|
||||||
if widget.Installed {
|
if widget.Installed {
|
||||||
if widgetConf, err := bazaar.WidgetJSON(widget.Name); nil == err && nil != widget {
|
if widgetConf, err := bazaar.WidgetJSON(widget.Name); nil == err && nil != widget {
|
||||||
if widget.Version != widgetConf.Version {
|
widget.Outdated = 0 > semver.Compare("v"+widgetConf.Version, "v"+widget.Version)
|
||||||
widget.Outdated = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,10 +321,8 @@ func BazaarIcons(keyword string) (icons []*bazaar.Icon) {
|
||||||
for _, icon := range icons {
|
for _, icon := range icons {
|
||||||
if installed == icon.Name {
|
if installed == icon.Name {
|
||||||
icon.Installed = true
|
icon.Installed = true
|
||||||
if themeConf, err := bazaar.IconJSON(icon.Name); nil == err {
|
if iconConf, err := bazaar.IconJSON(icon.Name); nil == err {
|
||||||
if icon.Version != themeConf.Version {
|
icon.Outdated = 0 > semver.Compare("v"+iconConf.Version, "v"+icon.Version)
|
||||||
icon.Outdated = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
icon.Current = icon.Name == Conf.Appearance.Icon
|
icon.Current = icon.Name == Conf.Appearance.Icon
|
||||||
|
|
@ -389,7 +384,7 @@ func BazaarThemes(keyword string) (ret []*bazaar.Theme) {
|
||||||
if installed == theme.Name {
|
if installed == theme.Name {
|
||||||
theme.Installed = true
|
theme.Installed = true
|
||||||
if themeConf, err := bazaar.ThemeJSON(theme.Name); nil == err {
|
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
|
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 {
|
for _, template := range templates {
|
||||||
template.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "templates", template.Name))
|
template.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "templates", template.Name))
|
||||||
if template.Installed {
|
if template.Installed {
|
||||||
if themeConf, err := bazaar.TemplateJSON(template.Name); nil == err && nil != themeConf {
|
if templateConf, err := bazaar.TemplateJSON(template.Name); nil == err && nil != templateConf {
|
||||||
if template.Version != themeConf.Version {
|
template.Outdated = 0 > semver.Compare("v"+templateConf.Version, "v"+template.Version)
|
||||||
template.Outdated = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -506,14 +506,15 @@ func FullReindex() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullReindex() {
|
func fullReindex() {
|
||||||
util.PushMsg(Conf.Language(35), 7*1000)
|
util.PushEndlessProgress(Conf.language(35))
|
||||||
|
defer util.PushClearProgress()
|
||||||
|
|
||||||
WaitForWritingFiles()
|
WaitForWritingFiles()
|
||||||
|
|
||||||
if err := sql.InitDatabase(true); nil != err {
|
if err := sql.InitDatabase(true); nil != err {
|
||||||
os.Exit(logging.ExitCodeReadOnlyDatabase)
|
os.Exit(logging.ExitCodeReadOnlyDatabase)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
treenode.InitBlockTree(true)
|
|
||||||
|
|
||||||
sql.IndexIgnoreCached = false
|
sql.IndexIgnoreCached = false
|
||||||
openedBoxes := Conf.GetOpenedBoxes()
|
openedBoxes := Conf.GetOpenedBoxes()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
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)})
|
mdTableCell.AppendChild(&ast.Node{Type: ast.NodeText, Tokens: []byte(val)})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {
|
||||||
|
|
||||||
bt := treenode.GetBlockTree(id)
|
bt := treenode.GetBlockTree(id)
|
||||||
if nil == bt {
|
if nil == bt {
|
||||||
if task.Contain(task.DatabaseIndex, task.DatabaseIndexFull) {
|
if task.ContainIndexTask() {
|
||||||
err = ErrIndexing
|
err = ErrIndexing
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +187,7 @@ func LoadTreeByBlockID(id string) (ret *parse.Tree, err error) {
|
||||||
|
|
||||||
bt := treenode.GetBlockTree(id)
|
bt := treenode.GetBlockTree(id)
|
||||||
if nil == bt {
|
if nil == bt {
|
||||||
if task.Contain(task.DatabaseIndex, task.DatabaseIndexFull) {
|
if task.ContainIndexTask() {
|
||||||
err = ErrIndexing
|
err = ErrIndexing
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,17 +115,13 @@ var uniqueActions = []string{
|
||||||
AssetContentDatabaseIndexCommit,
|
AssetContentDatabaseIndexCommit,
|
||||||
}
|
}
|
||||||
|
|
||||||
func Contain(action string, moreActions ...string) bool {
|
func ContainIndexTask() bool {
|
||||||
actions := append(moreActions, action)
|
actions := getCurrentActions()
|
||||||
actions = gulu.Str.RemoveDuplicatedElem(actions)
|
for _, action := range actions {
|
||||||
|
if gulu.Str.Contains(action, []string{DatabaseIndexFull, DatabaseIndex}) {
|
||||||
queueLock.Lock()
|
|
||||||
for _, task := range taskQueue {
|
|
||||||
if gulu.Str.Contains(task.Action, actions) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queueLock.Unlock()
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
util2 "github.com/siyuan-note/dejavu/util"
|
util2 "github.com/siyuan-note/dejavu/util"
|
||||||
"github.com/siyuan-note/logging"
|
"github.com/siyuan-note/logging"
|
||||||
|
"github.com/siyuan-note/siyuan/kernel/task"
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
"github.com/vmihailenco/msgpack/v5"
|
"github.com/vmihailenco/msgpack/v5"
|
||||||
)
|
)
|
||||||
|
|
@ -504,6 +505,12 @@ func SaveBlockTree(force bool) {
|
||||||
blockTreeLock.Lock()
|
blockTreeLock.Lock()
|
||||||
defer blockTreeLock.Unlock()
|
defer blockTreeLock.Unlock()
|
||||||
|
|
||||||
|
if task.ContainIndexTask() {
|
||||||
|
//logging.LogInfof("skip saving block tree because indexing")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//logging.LogInfof("saving block tree")
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := os.MkdirAll(util.BlockTreePath, 0755); nil != err {
|
if err := os.MkdirAll(util.BlockTreePath, 0755); nil != err {
|
||||||
logging.LogErrorf("create block tree dir [%s] failed: %s", util.BlockTreePath, err)
|
logging.LogErrorf("create block tree dir [%s] failed: %s", util.BlockTreePath, err)
|
||||||
|
|
|
||||||
|
|
@ -598,7 +598,7 @@ func getAttributeViewContent(avID string) (content string) {
|
||||||
if nil == cell.Value {
|
if nil == cell.Value {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.WriteString(cell.Value.String())
|
buf.WriteString(cell.Value.String(true))
|
||||||
buf.WriteByte(' ')
|
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)
|
dataModel[rowValue.Key.Name] = time.UnixMilli(v.Date.Content)
|
||||||
}
|
}
|
||||||
} else if av.KeyTypeRollup == v.Type {
|
} else if av.KeyTypeRollup == v.Type {
|
||||||
if 0 < len(v.Rollup.Contents) && av.KeyTypeNumber == v.Rollup.Contents[0].Type {
|
if 0 < len(v.Rollup.Contents) {
|
||||||
// 汇总数字时仅取第一个数字填充模板
|
var numbers []float64
|
||||||
dataModel[rowValue.Key.Name] = v.Rollup.Contents[0].Number.Content
|
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 {
|
} else {
|
||||||
dataModel[rowValue.Key.Name] = v.String()
|
dataModel[rowValue.Key.Name] = v.String(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue