Compare commits

...
3 Commits
Author SHA1 Message Date
fyears 272bc7a543 bump to 0.5.7
Release A New Version / build (16.x) (push) Failing after 52s
2024-06-17 00:15:59 +08:00
fyears 35f5355c8e optimize sync status bar 2024-06-17 00:15:33 +08:00
fyears 57493f57cf polish doc 2024-06-16 20:07:49 +08:00
13 changed files with 219 additions and 82 deletions
+17 -4
View File
@@ -22,7 +22,7 @@ This is yet another unofficial sync plugin for Obsidian. If you like it or find
- OneDrive for personal - OneDrive for personal
- Webdav (NextCloud / InfiniCloud / Synology webdav server / ...) - Webdav (NextCloud / InfiniCloud / Synology webdav server / ...)
- Webdis - Webdis
- Google Drive (PRO feature) - Google Drive (GDrive) (PRO feature)
- Box (PRO feature) - Box (PRO feature)
- pCloud (PRO feature) - pCloud (PRO feature)
- Yandex Disk (PRO feature) - Yandex Disk (PRO feature)
@@ -34,7 +34,7 @@ This is yet another unofficial sync plugin for Obsidian. If you like it or find
- **[Minimal Intrusive](./docs/minimal_intrusive_design.md).** - **[Minimal Intrusive](./docs/minimal_intrusive_design.md).**
- **Skip Large files** and **skip paths** by custom regex conditions! - **Skip Large files** and **skip paths** by custom regex conditions!
- **[Sync Algorithm](./docs/sync_algorithm/v3/intro.md) is provided for discussion.** - **[Sync Algorithm](./docs/sync_algorithm/v3/intro.md) is provided for discussion.**
- **[Basic Conflict Detection And Handling](./docs/sync_algorithm/v3/intro.md)** for free version. **[Advanced Conflict Handling](./pro/README.md)** for PRO version. - **[Basic Conflict Detection And Handling](./docs/sync_algorithm/v3/intro.md)** for free version. **[Advanced Smart Conflict Handling](./pro/README.md)** for PRO version.
- Source Available. See [License](./LICENSE) for details. - Source Available. See [License](./LICENSE) for details.
## Limitations ## Limitations
@@ -127,7 +127,7 @@ Additionally, the plugin author may occasionally visit Obsidian official forum a
- Mostly experimental. - Mostly experimental.
- You have to setup and protect your web server by yourself. - You have to setup and protect your web server by yourself.
### Google Drive (PRO feature) ### Google Drive (GDrive) (PRO feature)
PRO (paid) feature "sync with Google Drive" allows users to to sync with Google Drive. Tutorials and limitations are documented [here](./docs/remote_services/googledrive/README.md). PRO (paid) feature "sync with Google Drive" allows users to to sync with Google Drive. Tutorials and limitations are documented [here](./docs/remote_services/googledrive/README.md).
@@ -143,16 +143,29 @@ PRO (paid) feature "sync with pCloud" allows users to to sync with pCloud (using
PRO (paid) feature "sync with Yandex Disk" allows users to to sync with Yandex Disk (using its native API instead of webdav). Tutorials and limitations are documented [here](./docs/remote_services/yandexdisk/README.md). PRO (paid) feature "sync with Yandex Disk" allows users to to sync with Yandex Disk (using its native API instead of webdav). Tutorials and limitations are documented [here](./docs/remote_services/yandexdisk/README.md).
### Yandex Disk (PRO feature) ### Koofr (PRO feature)
PRO (paid) feature "sync with Koofr" allows users to to sync with Koofr (using its native API instead of webdav). Tutorials and limitations are documented [here](./docs/remote_services/koofr/README.md). PRO (paid) feature "sync with Koofr" allows users to to sync with Koofr (using its native API instead of webdav). Tutorials and limitations are documented [here](./docs/remote_services/koofr/README.md).
## Smart Conflict (PRO feature)
Basic (free) version can detect conflicts, but users have to choose to keep newer version or larger version of the files.
PRO (paid) feature "Smart Conflict" gives users one more option: merge small markdown files, or duplicate large markdown files or non-markdown files.
See documents [here](./docs/pro/README.md)
## Scheduled Auto Sync ## Scheduled Auto Sync
- You can configure auto syncing every N minutes in settings. - You can configure auto syncing every N minutes in settings.
- In auto sync mode, if any error occurs, the plugin would **fail silently**. - In auto sync mode, if any error occurs, the plugin would **fail silently**.
- Auto sync only works when Obsidian is being opened. It's **technically impossible** to auto sync while Obsidian is in background, because the plugin just works in the browser environment provided by Obsidian. - Auto sync only works when Obsidian is being opened. It's **technically impossible** to auto sync while Obsidian is in background, because the plugin just works in the browser environment provided by Obsidian.
## Sync On Save
- You can configure sync on save in settings.
- In sync on save mode, if any error occurs, the plugin would **fail silently**.
## How To Deal With Hidden Files Or Folders ## How To Deal With Hidden Files Or Folders
**By default, all files or folder starting with `.` (dot) or `_` (underscore) are treated as hidden files, and would NOT be synced.** It's useful if you have some files just staying locally. But this strategy also means that themes / other plugins / settings of this plugin would neither be synced. **By default, all files or folder starting with `.` (dot) or `_` (underscore) are treated as hidden files, and would NOT be synced.** It's useful if you have some files just staying locally. But this strategy also means that themes / other plugins / settings of this plugin would neither be synced.
+1 -1
View File
@@ -1,4 +1,4 @@
# Google Drive (PRO) # Google Drive (GDrive) (PRO)
# Intro # Intro
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "remotely-save", "id": "remotely-save",
"name": "Remotely Save", "name": "Remotely Save",
"version": "0.5.6", "version": "0.5.7",
"minAppVersion": "0.13.21", "minAppVersion": "0.13.21",
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.", "description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
"author": "fyears", "author": "fyears",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "remotely-save", "id": "remotely-save",
"name": "Remotely Save", "name": "Remotely Save",
"version": "0.5.6", "version": "0.5.7",
"minAppVersion": "0.13.21", "minAppVersion": "0.13.21",
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.", "description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
"author": "fyears", "author": "fyears",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "remotely-save", "name": "remotely-save",
"version": "0.5.6", "version": "0.5.7",
"description": "This is yet another sync plugin for Obsidian app.", "description": "This is yet another sync plugin for Obsidian app.",
"scripts": { "scripts": {
"dev2": "node esbuild.config.mjs --watch", "dev2": "node esbuild.config.mjs --watch",
+19 -3
View File
@@ -6,18 +6,34 @@ Remotely Save has some "pro features", which users have to pay for using them.
## Sign Up / Sign In And Connect ## Sign Up / Sign In And Connect
See the tutorial about your PRO account [here](../docs/pro/README.md). See the tutorial about your PRO account [here](.../docs/pro/README.md).
## Smart Conflict ## Smart Conflict (PRO feature)
Basic (free) version can detect conflicts, but users have to choose to keep newer version or larger version of the files. Basic (free) version can detect conflicts, but users have to choose to keep newer version or larger version of the files.
PRO (paid) feature "Smart Conflict" gives users one more option: merge small markdown files, or duplicate large markdown files or non-markdown files. PRO (paid) feature "Smart Conflict" gives users one more option: merge small markdown files, or duplicate large markdown files or non-markdown files.
## Sync With Google Drive ## Google Drive (GDrive) (PRO feature)
PRO (paid) feature "sync with Google Drive" allows users to to sync with Google Drive. Tutorials and limitations are documented [here](../docs/remote_services/googledrive/README.md). PRO (paid) feature "sync with Google Drive" allows users to to sync with Google Drive. Tutorials and limitations are documented [here](../docs/remote_services/googledrive/README.md).
## Box (PRO feature)
PRO (paid) feature "sync with Box" allows users to to sync with Box. Tutorials and limitations are documented [here](../docs/remote_services/box/README.md).
## pCloud (PRO feature)
PRO (paid) feature "sync with pCloud" allows users to to sync with pCloud (using its native API instead of webdav). Tutorials and limitations are documented [here](../docs/remote_services/pcloud/README.md).
## Yandex Disk (PRO feature)
PRO (paid) feature "sync with Yandex Disk" allows users to to sync with Yandex Disk (using its native API instead of webdav). Tutorials and limitations are documented [here](../docs/remote_services/yandexdisk/README.md).
## Koofr (PRO feature)
PRO (paid) feature "sync with Koofr" allows users to to sync with Koofr (using its native API instead of webdav). Tutorials and limitations are documented [here](../docs/remote_services/koofr/README.md).
## License ## License
The codes or files or subfolders inside the current folder (`pro` in the repo), are released under "source available" license: "PolyForm Strict License 1.0.0". The codes or files or subfolders inside the current folder (`pro` in the repo), are released under "source available" license: "PolyForm Strict License 1.0.0".
+5
View File
@@ -1417,6 +1417,7 @@ export const doActualSync = async (
db: InternalDBs, db: InternalDBs,
profiler: Profiler | undefined, profiler: Profiler | undefined,
conflictAction: ConflictActionType, conflictAction: ConflictActionType,
triggerSource: SyncTriggerSourceType,
callbackSyncProcess?: any callbackSyncProcess?: any
) => { ) => {
profiler?.addIndent(); profiler?.addIndent();
@@ -1524,13 +1525,16 @@ export const doActualSync = async (
// ); // );
await callbackSyncProcess?.( await callbackSyncProcess?.(
triggerSource,
realCounter, realCounter,
realTotalCount, realTotalCount,
key, key,
val.decision val.decision
); );
if (val.change === undefined || val.change) {
realCounter += 1; realCounter += 1;
}
await dispatchOperationToActualV3( await dispatchOperationToActualV3(
key, key,
@@ -1743,6 +1747,7 @@ export async function syncer(
db, db,
profiler, profiler,
settings.conflictAction ?? "keep_newer", settings.conflictAction ?? "keep_newer",
triggerSource,
callbackSyncProcess callbackSyncProcess
); );
profiler?.insert(`finish step${step} (actual sync)`); profiler?.insert(`finish step${step} (actual sync)`);
+17 -11
View File
@@ -45,20 +45,26 @@
"command_exportlogsindb": "export logs saved in db", "command_exportlogsindb": "export logs saved in db",
"statusbar_time_years": "Synced {{time}} years ago", "statusbar_sync_source_manual": "Manual: ",
"statusbar_time_months": "Synced {{time}} months ago", "statusbar_sync_source_dry": "Dry: ",
"statusbar_time_weeks": "Synced {{time}} weeks ago", "statusbar_sync_source_auto": "Auto: ",
"statusbar_time_days": "Synced {{time}} days ago", "statusbar_sync_source_auto_once_init": "Auto (init): ",
"statusbar_time_hours": "Synced {{time}} hours ago", "statusbar_sync_source_auto_sync_on_save": "Auto (save): ",
"statusbar_time_minutes": "Synced {{time}} minutes ago", "statusbar_sync_status_prefix_success": "Successfully synced ",
"statusbar_time_lessminute": "Synced last minute ago", "statusbar_sync_status_prefix_failed": "Failed to sync ",
"statusbar_lastsync": "Synced {{time}} ago", "statusbar_time_years": "{{time}} years ago",
"statusbar_time_months": "{{time}} months ago",
"statusbar_time_weeks": "{{time}} weeks ago",
"statusbar_time_days": "{{time}} days ago",
"statusbar_time_hours": "{{time}} hours ago",
"statusbar_time_minutes": "{{time}} minutes ago",
"statusbar_time_lessminute": "last minute ago",
"statusbar_time_now": "just now",
"statusbar_syncing": "Syncing...", "statusbar_syncing": "Syncing...",
"statusbar_failed": "Last sync failed", "statusbar_lastsync_label": "on {{date}}",
"statusbar_now": "Synced just now",
"statusbar_lastsync_label": "Last successful Sync on {{date}}",
"statusbar_lastsync_never": "Never Synced", "statusbar_lastsync_never": "Never Synced",
"statusbar_lastsync_never_label": "Never Synced before", "statusbar_lastsync_never_label": "Never Synced before",
"modal_password_title": "Hold on and PLEASE READ ON...", "modal_password_title": "Hold on and PLEASE READ ON...",
"modal_password_shortdesc": "If the field is not empty, files would be encrypted locally before being uploaded.\nIf the field is empty, then files would be uploaded without encryption.", "modal_password_shortdesc": "If the field is not empty, files would be encrypted locally before being uploaded.\nIf the field is empty, then files would be uploaded without encryption.",
"modal_password_attn1": "Attention 1/5: The vault name is NOT encrypted. The plugin creates a folder with the vault name on some remote services.", "modal_password_attn1": "Attention 1/5: The vault name is NOT encrypted. The plugin creates a folder with the vault name on some remote services.",
+17 -11
View File
@@ -45,20 +45,26 @@
"command_exportsyncplans_all": "导出同步计划(所有)(export sync plans (all)", "command_exportsyncplans_all": "导出同步计划(所有)(export sync plans (all)",
"command_exportlogsindb": "从数据库导出终端日志(export logs saved in db", "command_exportlogsindb": "从数据库导出终端日志(export logs saved in db",
"statusbar_time_years": "{{time}} 年前同步", "statusbar_sync_source_manual": "手动:",
"statusbar_time_months": "{{time}} 月前同步", "statusbar_sync_source_dry": "空跑:",
"statusbar_time_weeks": "{{time}} 周前同步", "statusbar_sync_source_auto": "自动:",
"statusbar_time_days": "{{time}} 天前同步", "statusbar_sync_source_auto_once_init": "启动时自动:",
"statusbar_time_hours": "{{time}} 小时前同步", "statusbar_sync_source_auto_sync_on_save": "保存时自动:",
"statusbar_time_minutes": "{{time}} 分钟前同步", "statusbar_sync_status_prefix_success": "同步成功:",
"statusbar_time_lessminute": "一分钟之内同步", "statusbar_sync_status_prefix_failed": "同步失败:",
"statusbar_lastsync": "上一次同步于:{{time}}", "statusbar_time_years": "{{time}} 年前",
"statusbar_time_months": "{{time}} 月前",
"statusbar_time_weeks": "{{time}} 周前",
"statusbar_time_days": "{{time}} 天前",
"statusbar_time_hours": "{{time}} 小时前",
"statusbar_time_minutes": "{{time}} 分钟前",
"statusbar_time_lessminute": "一分钟之内",
"statusbar_time_now": "刚刚",
"statusbar_syncing": "正在同步", "statusbar_syncing": "正在同步",
"statusbar_failed": "上次同步失败了", "statusbar_lastsync_label": "日期:{{date}}",
"statusbar_now": "刚同步完",
"statusbar_lastsync_label": "上一次同步于:{{date}}",
"statusbar_lastsync_never": "没触发过同步", "statusbar_lastsync_never": "没触发过同步",
"statusbar_lastsync_never_label": "没触发过同步", "statusbar_lastsync_never_label": "没触发过同步",
"modal_password_title": "稍等一下,请阅读下文:", "modal_password_title": "稍等一下,请阅读下文:",
"modal_password_shortdesc": "如果密码不是空的,那么文件会在上传之前,在本地先用此密码加密。\n如果密码是空的,那么文件会被非加密地上传。", "modal_password_shortdesc": "如果密码不是空的,那么文件会在上传之前,在本地先用此密码加密。\n如果密码是空的,那么文件会被非加密地上传。",
"modal_password_attn1": "注意 1/5:库(Vault)名字是不会加密的!本插件会在一些远程存储里创建一个和库名字有着同名的文件夹。", "modal_password_attn1": "注意 1/5:库(Vault)名字是不会加密的!本插件会在一些远程存储里创建一个和库名字有着同名的文件夹。",
+17 -11
View File
@@ -44,20 +44,26 @@
"command_exportsyncplans_all": "匯出同步計劃(所有)(export sync plans (all)", "command_exportsyncplans_all": "匯出同步計劃(所有)(export sync plans (all)",
"command_exportlogsindb": "從資料庫匯出終端日誌(export logs saved in db", "command_exportlogsindb": "從資料庫匯出終端日誌(export logs saved in db",
"statusbar_time_years": "{{time}} 年前同步", "statusbar_sync_source_manual": "手動:",
"statusbar_time_months": "{{time}} 月前同步", "statusbar_sync_source_dry": "空跑:",
"statusbar_time_weeks": "{{time}} 周前同步", "statusbar_sync_source_auto": "自動:",
"statusbar_time_days": "{{time}} 天前同步", "statusbar_sync_source_auto_once_init": "啟動時自動:",
"statusbar_time_hours": "{{time}} 小時前同步", "statusbar_sync_source_auto_sync_on_save": "儲存時自動:",
"statusbar_time_minutes": "{{time}} 分鐘前同步", "statusbar_sync_status_prefix_success": "同步成功:",
"statusbar_time_lessminute": "一分鐘之內同步", "statusbar_sync_status_prefix_failed": "同步失敗:",
"statusbar_lastsync": "上一次同步於:{{time}}", "statusbar_time_years": "{{time}} 年前",
"statusbar_time_months": "{{time}} 月前",
"statusbar_time_weeks": "{{time}} 周前",
"statusbar_time_days": "{{time}} 天前",
"statusbar_time_hours": "{{time}} 小時前",
"statusbar_time_minutes": "{{time}} 分鐘前",
"statusbar_time_lessminute": "一分鐘之內",
"statusbar_time_now": "剛剛",
"statusbar_syncing": "正在同步", "statusbar_syncing": "正在同步",
"statusbar_failed": "上次同步失敗了", "statusbar_lastsync_label": "日期:{{date}}",
"statusbar_now": "剛同步完",
"statusbar_lastsync_label": "上一次同步於:{{date}}",
"statusbar_lastsync_never": "沒觸發過同步", "statusbar_lastsync_never": "沒觸發過同步",
"statusbar_lastsync_never_label": "沒觸發過同步", "statusbar_lastsync_never_label": "沒觸發過同步",
"modal_password_title": "稍等一下,請閱讀下文:", "modal_password_title": "稍等一下,請閱讀下文:",
"modal_password_shortdesc": "如果密碼不是空的,那麼檔案會在上傳之前,在本地先用此密碼加密。\n如果密碼是空的,那麼檔案會被非加密地上傳。", "modal_password_shortdesc": "如果密碼不是空的,那麼檔案會在上傳之前,在本地先用此密碼加密。\n如果密碼是空的,那麼檔案會被非加密地上傳。",
"modal_password_attn1": "注意 1/5:儲存庫(Vault)名字是不會加密的!本外掛會在一些遠端儲存裡建立一個和庫名字有著同名的資料夾。", "modal_password_attn1": "注意 1/5:儲存庫(Vault)名字是不會加密的!本外掛會在一些遠端儲存裡建立一個和庫名字有著同名的資料夾。",
+21 -1
View File
@@ -519,7 +519,27 @@ export const getLastSuccessSyncTimeByVault = async (
) => { ) => {
return (await db.simpleKVForMiscTbl.getItem( return (await db.simpleKVForMiscTbl.getItem(
`${vaultRandomID}-lastSuccessSyncMillis` `${vaultRandomID}-lastSuccessSyncMillis`
)) as number; )) as number | null | undefined;
};
export const upsertLastFailedSyncTimeByVault = async (
db: InternalDBs,
vaultRandomID: string,
millis: number
) => {
await db.simpleKVForMiscTbl.setItem(
`${vaultRandomID}-lastFailedSyncMillis`,
millis
);
};
export const getLastFailedSyncTimeByVault = async (
db: InternalDBs,
vaultRandomID: string
) => {
return (await db.simpleKVForMiscTbl.getItem(
`${vaultRandomID}-lastFailedSyncMillis`
)) as number | null | undefined;
}; };
export const upsertPluginVersionByVault = async ( export const upsertPluginVersionByVault = async (
+93 -34
View File
@@ -92,8 +92,10 @@ import {
type InternalDBs, type InternalDBs,
clearAllLoggerOutputRecords, clearAllLoggerOutputRecords,
clearExpiredSyncPlanRecords, clearExpiredSyncPlanRecords,
getLastFailedSyncTimeByVault,
getLastSuccessSyncTimeByVault, getLastSuccessSyncTimeByVault,
prepareDBs, prepareDBs,
upsertLastFailedSyncTimeByVault,
upsertLastSuccessSyncTimeByVault, upsertLastSuccessSyncTimeByVault,
upsertPluginVersionByVault, upsertPluginVersionByVault,
} from "./localdb"; } from "./localdb";
@@ -176,6 +178,29 @@ const getIconSvg = () => {
return res; return res;
}; };
const getStatusBarShortMsgFromSyncSource = (
t: (x: TransItemType, vars?: any) => string,
s: SyncTriggerSourceType | undefined
) => {
if (s === undefined) {
return "";
}
switch (s) {
case "manual":
return t("statusbar_sync_source_manual");
case "dry":
return t("statusbar_sync_source_dry");
case "auto":
return t("statusbar_sync_source_auto");
case "auto_once_init":
return t("statusbar_sync_source_auto_once_init");
case "auto_sync_on_save":
return t("statusbar_sync_source_auto_sync_on_save");
default:
throw Error(`no translate for ${s}`);
}
};
export default class RemotelySavePlugin extends Plugin { export default class RemotelySavePlugin extends Plugin {
settings!: RemotelySavePluginSettings; settings!: RemotelySavePluginSettings;
db!: InternalDBs; db!: InternalDBs;
@@ -393,17 +418,15 @@ export default class RemotelySavePlugin extends Plugin {
) => { ) => {
if (step === 1) { if (step === 1) {
// change status to "syncing..." on statusbar // change status to "syncing..." on statusbar
this.updateLastSuccessSyncMsg(-1); this.updateLastSyncMsg(s, -1, -1);
} else if (step === 8 && everythingOk) { } else if (step === 8 && everythingOk) {
const lastSuccessSyncMillis = Date.now(); const ts = Date.now();
await upsertLastSuccessSyncTimeByVault( await upsertLastSuccessSyncTimeByVault(this.db, this.vaultRandomID, ts);
this.db, this.updateLastSyncMsg(s, ts, null);
this.vaultRandomID,
lastSuccessSyncMillis
);
this.updateLastSuccessSyncMsg(lastSuccessSyncMillis);
} else if (!everythingOk) { } else if (!everythingOk) {
this.updateLastSuccessSyncMsg(-2); // magic number const ts = Date.now();
await upsertLastFailedSyncTimeByVault(this.db, this.vaultRandomID, ts);
this.updateLastSyncMsg(s, null, ts); // magic number
} }
}; };
@@ -412,12 +435,15 @@ export default class RemotelySavePlugin extends Plugin {
}; };
const callbackSyncProcess = async ( const callbackSyncProcess = async (
s: SyncTriggerSourceType,
realCounter: number, realCounter: number,
realTotalCount: number, realTotalCount: number,
pathName: string, pathName: string,
decision: string decision: string
) => { ) => {
this.setCurrSyncMsg( this.setCurrSyncMsg(
t,
s,
realCounter, realCounter,
realTotalCount, realTotalCount,
pathName, pathName,
@@ -1060,15 +1086,21 @@ export default class RemotelySavePlugin extends Plugin {
this.statusBarElement = statusBarItem.createEl("span"); this.statusBarElement = statusBarItem.createEl("span");
this.statusBarElement.setAttribute("data-tooltip-position", "top"); this.statusBarElement.setAttribute("data-tooltip-position", "top");
this.updateLastSuccessSyncMsg( this.updateLastSyncMsg(
await getLastSuccessSyncTimeByVault(this.db, this.vaultRandomID) undefined,
await getLastSuccessSyncTimeByVault(this.db, this.vaultRandomID),
await getLastFailedSyncTimeByVault(this.db, this.vaultRandomID)
); );
// update statusbar text every 30 seconds // update statusbar text every 30 seconds
this.registerInterval( this.registerInterval(
window.setInterval(async () => { window.setInterval(async () => {
this.updateLastSuccessSyncMsg( if (!this.isSyncing) {
await getLastSuccessSyncTimeByVault(this.db, this.vaultRandomID) this.updateLastSyncMsg(
undefined,
await getLastSuccessSyncTimeByVault(this.db, this.vaultRandomID),
await getLastFailedSyncTimeByVault(this.db, this.vaultRandomID)
); );
}
}, 1000 * 30) }, 1000 * 30)
); );
} }
@@ -1618,7 +1650,8 @@ export default class RemotelySavePlugin extends Plugin {
if ( if (
caller === "SYNC" || caller === "SYNC" ||
(caller === "FILE_CHANGES" && lastModified > lastSuccessSyncMillis) (caller === "FILE_CHANGES" &&
lastModified > (lastSuccessSyncMillis ?? 1))
) { ) {
console.debug( console.debug(
`so lastModified > lastSuccessSyncMillis or it's called while syncing before` `so lastModified > lastSuccessSyncMillis or it's called while syncing before`
@@ -1734,17 +1767,34 @@ export default class RemotelySavePlugin extends Plugin {
} }
setCurrSyncMsg( setCurrSyncMsg(
t: (x: TransItemType, vars?: any) => string,
s: SyncTriggerSourceType,
i: number, i: number,
totalCount: number, totalCount: number,
pathName: string, pathName: string,
decision: string, decision: string,
triggerSource: SyncTriggerSourceType triggerSource: SyncTriggerSourceType
) { ) {
const msg = `syncing progress=${i}/${totalCount},decision=${decision},path=${pathName},source=${triggerSource}`; const L = `${totalCount}`.length;
this.currSyncMsg = msg; const iStr = `${i}`.padStart(L, "0");
const prefix = getStatusBarShortMsgFromSyncSource(t, s);
const shortMsg = prefix + `Syncing ${iStr}/${totalCount}`;
const longMsg =
prefix +
`Syncing progress=${iStr}/${totalCount},decision=${decision},path=${pathName},source=${triggerSource}`;
this.currSyncMsg = longMsg;
if (this.statusBarElement !== undefined) {
this.statusBarElement.setText(shortMsg);
this.statusBarElement.setAttribute("aria-label", longMsg);
}
} }
updateLastSuccessSyncMsg(lastSuccessSyncMillis?: number) { updateLastSyncMsg(
s: SyncTriggerSourceType | undefined,
lastSuccessSyncMillis: number | null | undefined,
lastFailedSyncMillis: number | null | undefined
) {
if (this.statusBarElement === undefined) return; if (this.statusBarElement === undefined) return;
const t = (x: TransItemType, vars?: any) => { const t = (x: TransItemType, vars?: any) => {
@@ -1754,18 +1804,27 @@ export default class RemotelySavePlugin extends Plugin {
let lastSyncMsg = t("statusbar_lastsync_never"); let lastSyncMsg = t("statusbar_lastsync_never");
let lastSyncLabelMsg = t("statusbar_lastsync_never_label"); let lastSyncLabelMsg = t("statusbar_lastsync_never_label");
if (lastSuccessSyncMillis !== undefined && lastSuccessSyncMillis === -1) { const inputTs = Math.max(
lastSyncMsg = t("statusbar_syncing"); lastSuccessSyncMillis ?? -999,
lastFailedSyncMillis ?? -999
);
const isSuccess =
(lastSuccessSyncMillis ?? -999) >= (lastFailedSyncMillis ?? -999);
if (lastSuccessSyncMillis === -1) {
// magic number
// otherwise how can we know we are syncing??
lastSyncMsg =
getStatusBarShortMsgFromSyncSource(t, s!) + t("statusbar_syncing");
} else if (inputTs > 0) {
let prefix = "";
if (isSuccess) {
prefix = t("statusbar_sync_status_prefix_success");
} else {
prefix = t("statusbar_sync_status_prefix_failed");
} }
if (lastSuccessSyncMillis !== undefined && lastSuccessSyncMillis === -2) { const deltaTime = Date.now() - inputTs;
lastSyncMsg = t("statusbar_failed");
lastSyncLabelMsg = t("statusbar_failed");
}
if (lastSuccessSyncMillis !== undefined && lastSuccessSyncMillis > 0) {
const deltaTime = Date.now() - lastSuccessSyncMillis;
// create human readable time // create human readable time
const years = Math.floor(deltaTime / 31556952000); const years = Math.floor(deltaTime / 31556952000);
const months = Math.floor(deltaTime / 2629746000); const months = Math.floor(deltaTime / 2629746000);
@@ -1774,9 +1833,7 @@ export default class RemotelySavePlugin extends Plugin {
const hours = Math.floor(deltaTime / 3600000); const hours = Math.floor(deltaTime / 3600000);
const minutes = Math.floor(deltaTime / 60000); const minutes = Math.floor(deltaTime / 60000);
const seconds = Math.floor(deltaTime / 1000); const seconds = Math.floor(deltaTime / 1000);
let timeText = ""; let timeText = "";
if (years > 0) { if (years > 0) {
timeText = t("statusbar_time_years", { time: years }); timeText = t("statusbar_time_years", { time: years });
} else if (months > 0) { } else if (months > 0) {
@@ -1792,10 +1849,9 @@ export default class RemotelySavePlugin extends Plugin {
} else if (seconds > 30) { } else if (seconds > 30) {
timeText = t("statusbar_time_lessminute"); timeText = t("statusbar_time_lessminute");
} else { } else {
timeText = t("statusbar_now"); timeText = t("statusbar_time_now");
} }
const dateText = new Date(inputTs).toLocaleTimeString(
const dateText = new Date(lastSuccessSyncMillis).toLocaleTimeString(
navigator.language, navigator.language,
{ {
weekday: "long", weekday: "long",
@@ -1805,8 +1861,11 @@ export default class RemotelySavePlugin extends Plugin {
} }
); );
lastSyncMsg = timeText; lastSyncMsg = prefix + timeText;
lastSyncLabelMsg = t("statusbar_lastsync_label", { date: dateText }); lastSyncLabelMsg =
prefix + t("statusbar_lastsync_label", { date: dateText });
} else {
// TODO: no idea what happened.
} }
this.statusBarElement.setText(lastSyncMsg); this.statusBarElement.setText(lastSyncMsg);
+7 -1
View File
@@ -55,6 +55,7 @@ import {
clearAllPrevSyncRecordByVault, clearAllPrevSyncRecordByVault,
clearAllSyncPlanRecords, clearAllSyncPlanRecords,
destroyDBs, destroyDBs,
upsertLastFailedSyncTimeByVault,
upsertLastSuccessSyncTimeByVault, upsertLastSuccessSyncTimeByVault,
} from "./localdb"; } from "./localdb";
import type RemotelySavePlugin from "./main"; // unavoidable import type RemotelySavePlugin from "./main"; // unavoidable
@@ -2134,7 +2135,12 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
this.plugin.vaultRandomID, this.plugin.vaultRandomID,
-1 -1
); );
this.plugin.updateLastSuccessSyncMsg(-1); await upsertLastFailedSyncTimeByVault(
this.plugin.db,
this.plugin.vaultRandomID,
-1
);
this.plugin.updateLastSyncMsg(undefined, null, null);
new Notice(t("settings_resetstatusbar_notice")); new Notice(t("settings_resetstatusbar_notice"));
}); });
}); });