Sync progress circle
This commit is contained in:
+29
-12
@@ -8,6 +8,7 @@ import type { ComponentChildren, FunctionalComponent } from "../deps.ts";
|
|||||||
import { Notification } from "../types.ts";
|
import { Notification } from "../types.ts";
|
||||||
import { FeatherProps } from "https://esm.sh/v99/preact-feather@4.2.1/dist/types";
|
import { FeatherProps } from "https://esm.sh/v99/preact-feather@4.2.1/dist/types";
|
||||||
import { MiniEditor } from "./mini_editor.tsx";
|
import { MiniEditor } from "./mini_editor.tsx";
|
||||||
|
import process from "https://deno.land/std@0.177.1/node/process.ts";
|
||||||
|
|
||||||
export type ActionButton = {
|
export type ActionButton = {
|
||||||
icon: FunctionalComponent<FeatherProps>;
|
icon: FunctionalComponent<FeatherProps>;
|
||||||
@@ -26,6 +27,7 @@ export function TopBar({
|
|||||||
actionButtons,
|
actionButtons,
|
||||||
darkMode,
|
darkMode,
|
||||||
vimMode,
|
vimMode,
|
||||||
|
progressPerc,
|
||||||
completer,
|
completer,
|
||||||
lhs,
|
lhs,
|
||||||
rhs,
|
rhs,
|
||||||
@@ -37,6 +39,7 @@ export function TopBar({
|
|||||||
notifications: Notification[];
|
notifications: Notification[];
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
vimMode: boolean;
|
vimMode: boolean;
|
||||||
|
progressPerc?: number;
|
||||||
onRename: (newName?: string) => Promise<void>;
|
onRename: (newName?: string) => Promise<void>;
|
||||||
completer: (context: CompletionContext) => Promise<CompletionResult | null>;
|
completer: (context: CompletionContext) => Promise<CompletionResult | null>;
|
||||||
actionButtons: ActionButton[];
|
actionButtons: ActionButton[];
|
||||||
@@ -119,20 +122,34 @@ export function TopBar({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="sb-actions">
|
<div className="sb-actions">
|
||||||
{actionButtons.map((actionButton) => {
|
{progressPerc !== undefined &&
|
||||||
const button =
|
(
|
||||||
<button
|
<div className="progress-wrapper" title={`${progressPerc}%`}>
|
||||||
onClick={(e) => {
|
<div
|
||||||
e.preventDefault();
|
className="progress-bar"
|
||||||
actionButton.callback();
|
style={`background: radial-gradient(closest-side, white 79%, transparent 80% 100%), conic-gradient(#282828 ${progressPerc}%, #adadad 0);`}
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
title={actionButton.description}
|
|
||||||
>
|
>
|
||||||
<actionButton.icon size={18} />
|
{progressPerc}%
|
||||||
</button>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{actionButtons.map((actionButton) => {
|
||||||
|
const button = (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
actionButton.callback();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
title={actionButton.description}
|
||||||
|
>
|
||||||
|
<actionButton.icon size={18} />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
return actionButton.href !== undefined ? (<a href={actionButton.href}>{button}</a>) : button;
|
return actionButton.href !== undefined
|
||||||
|
? <a href={actionButton.href}>{button}</a>
|
||||||
|
: button;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+26
-8
@@ -202,7 +202,7 @@ export class Editor {
|
|||||||
const runtimeConfig = window.silverBulletConfig;
|
const runtimeConfig = window.silverBulletConfig;
|
||||||
|
|
||||||
// Instantiate a PlugOS system
|
// Instantiate a PlugOS system
|
||||||
const system = new System<SilverBulletHooks>();
|
const system = new System<SilverBulletHooks>("client");
|
||||||
this.system = system;
|
this.system = system;
|
||||||
|
|
||||||
// Generate a semi-unique prefix for the database so not to reuse databases for different space paths
|
// Generate a semi-unique prefix for the database so not to reuse databases for different space paths
|
||||||
@@ -499,7 +499,8 @@ export class Editor {
|
|||||||
this.dispatchAppEvent("editor:pageLoaded", this.currentPage);
|
this.dispatchAppEvent("editor:pageLoaded", this.currentPage);
|
||||||
if (operations) {
|
if (operations) {
|
||||||
// Likely initial sync so let's show visually that we're synced now
|
// Likely initial sync so let's show visually that we're synced now
|
||||||
this.flashNotification(`Synced ${operations} files`, "info");
|
// this.flashNotification(`Synced ${operations} files`, "info");
|
||||||
|
this.showProgress(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reset for next sync cycle
|
// Reset for next sync cycle
|
||||||
@@ -517,12 +518,8 @@ export class Editor {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.eventHook.addLocalListener("sync:progress", (status: SyncStatus) => {
|
this.eventHook.addLocalListener("sync:progress", (status: SyncStatus) => {
|
||||||
this.flashNotification(
|
this.showProgress(
|
||||||
`Sync: ${
|
Math.round(status.filesProcessed / status.totalFiles * 100),
|
||||||
Math.round(status.filesProcessed / status.totalFiles * 10000) /
|
|
||||||
100
|
|
||||||
}% — processed ${status.filesProcessed} out of ${status.totalFiles}`,
|
|
||||||
"info",
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -616,6 +613,26 @@ export class Editor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progressTimeout?: number;
|
||||||
|
|
||||||
|
showProgress(progressPerc: number) {
|
||||||
|
this.viewDispatch({
|
||||||
|
type: "set-progress",
|
||||||
|
progressPerc,
|
||||||
|
});
|
||||||
|
if (this.progressTimeout) {
|
||||||
|
clearTimeout(this.progressTimeout);
|
||||||
|
}
|
||||||
|
this.progressTimeout = setTimeout(
|
||||||
|
() => {
|
||||||
|
this.viewDispatch({
|
||||||
|
type: "set-progress",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
10000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
filterBox(
|
filterBox(
|
||||||
label: string,
|
label: string,
|
||||||
options: FilterOption[],
|
options: FilterOption[],
|
||||||
@@ -1417,6 +1434,7 @@ export class Editor {
|
|||||||
isLoading={viewState.isLoading}
|
isLoading={viewState.isLoading}
|
||||||
vimMode={viewState.uiOptions.vimMode}
|
vimMode={viewState.uiOptions.vimMode}
|
||||||
darkMode={viewState.uiOptions.darkMode}
|
darkMode={viewState.uiOptions.darkMode}
|
||||||
|
progressPerc={viewState.progressPerc}
|
||||||
completer={editor.miniEditorComplete.bind(editor)}
|
completer={editor.miniEditorComplete.bind(editor)}
|
||||||
onRename={async (newName) => {
|
onRename={async (newName) => {
|
||||||
if (!newName) {
|
if (!newName) {
|
||||||
|
|||||||
@@ -176,6 +176,11 @@ export default function reducer(
|
|||||||
[action.key]: action.value,
|
[action.key]: action.value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
case "set-progress":
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
progressPerc: action.progressPerc,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,29 @@ body {
|
|||||||
right: 15px;
|
right: 15px;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -6px;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 6px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// .progress-bar::before {
|
||||||
|
// content: "66%";
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
.sb-panel {
|
.sb-panel {
|
||||||
|
|||||||
+2
-2
@@ -104,8 +104,8 @@ export class SyncService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async registerSyncProgress(status?: SyncStatus): Promise<void> {
|
async registerSyncProgress(status?: SyncStatus): Promise<void> {
|
||||||
// Emit a sync event at most every 10s
|
// Emit a sync event at most every 2s
|
||||||
if (status && this.lastReportedSyncStatus < Date.now() - 10000) {
|
if (status && this.lastReportedSyncStatus < Date.now() - 2000) {
|
||||||
this.eventHook.dispatchEvent("sync:progress", status);
|
this.eventHook.dispatchEvent("sync:progress", status);
|
||||||
this.lastReportedSyncStatus = Date.now();
|
this.lastReportedSyncStatus = Date.now();
|
||||||
await this.saveSnapshot(status.snapshot);
|
await this.saveSnapshot(status.snapshot);
|
||||||
|
|||||||
+3
-1
@@ -52,6 +52,7 @@ export type AppViewState = {
|
|||||||
showCommandPaletteContext?: string;
|
showCommandPaletteContext?: string;
|
||||||
unsavedChanges: boolean;
|
unsavedChanges: boolean;
|
||||||
synced: boolean;
|
synced: boolean;
|
||||||
|
progressPerc?: number;
|
||||||
panels: { [key: string]: PanelConfig };
|
panels: { [key: string]: PanelConfig };
|
||||||
allPages: PageMeta[];
|
allPages: PageMeta[];
|
||||||
commands: Map<string, AppCommand>;
|
commands: Map<string, AppCommand>;
|
||||||
@@ -162,4 +163,5 @@ export type Action =
|
|||||||
callback: (value: boolean) => void;
|
callback: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
| { type: "hide-confirm" }
|
| { type: "hide-confirm" }
|
||||||
| { type: "set-ui-option"; key: string; value: any };
|
| { type: "set-ui-option"; key: string; value: any }
|
||||||
|
| { type: "set-progress"; progressPerc?: number };
|
||||||
|
|||||||
Reference in New Issue
Block a user