Fix history view
This commit is contained in:
parent
58a61d036b
commit
468d0ac8cf
4 changed files with 77 additions and 45 deletions
|
|
@ -70,7 +70,7 @@
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
resize: none;
|
resize: none;
|
||||||
height: 60px;
|
height: 75px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,14 @@ export class HistoryView extends ItemView {
|
||||||
super(leaf);
|
super(leaf);
|
||||||
this.icon = HistoryView.ICON;
|
this.icon = HistoryView.ICON;
|
||||||
|
|
||||||
this.client.addSyncHistoryUpdateListener(() => {
|
this.client.addSyncHistoryUpdateListener(
|
||||||
this.updateView().catch((_error: unknown) => {
|
() =>
|
||||||
this.client.logger.error("Failed to update history view");
|
void this.updateView().catch((error: unknown) => {
|
||||||
});
|
this.client.logger.error(
|
||||||
});
|
`Failed to update history view: ${error}`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getSyncTypeIcon(type: SyncType | undefined): IconName {
|
private static getSyncTypeIcon(type: SyncType | undefined): IconName {
|
||||||
|
|
@ -58,6 +61,21 @@ export class HistoryView extends ItemView {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static updateTimeSince(
|
||||||
|
element: HTMLElement,
|
||||||
|
entry: HistoryEntry
|
||||||
|
): void {
|
||||||
|
const timestampElement = element.querySelector(
|
||||||
|
".history-card-timestamp"
|
||||||
|
);
|
||||||
|
if (timestampElement != null) {
|
||||||
|
timestampElement.textContent = intlFormatDistance(
|
||||||
|
entry.timestamp,
|
||||||
|
new Date()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getViewType(): string {
|
public getViewType(): string {
|
||||||
return HistoryView.TYPE;
|
return HistoryView.TYPE;
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +106,7 @@ export class HistoryView extends ItemView {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entries = this.client.getHistoryEntries().reverse();
|
const entries = this.client.getHistoryEntries();
|
||||||
|
|
||||||
if (this.historyEntryToElement.size === 0 && entries.length > 0) {
|
if (this.historyEntryToElement.size === 0 && entries.length > 0) {
|
||||||
// Clear the "No update has happened yet" message
|
// Clear the "No update has happened yet" message
|
||||||
|
|
@ -98,15 +116,7 @@ export class HistoryView extends ItemView {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
const element = this.historyEntryToElement.get(entry);
|
const element = this.historyEntryToElement.get(entry);
|
||||||
if (element !== undefined) {
|
if (element !== undefined) {
|
||||||
const timestampElement = element.querySelector(
|
HistoryView.updateTimeSince(element, entry);
|
||||||
".history-card-timestamp"
|
|
||||||
);
|
|
||||||
if (timestampElement != null) {
|
|
||||||
timestampElement.textContent = intlFormatDistance(
|
|
||||||
entry.timestamp,
|
|
||||||
new Date()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,8 @@ export class SyncClient {
|
||||||
return this.syncService.checkConnection();
|
return this.syncService.checkConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getHistoryEntries(): HistoryEntry[] {
|
public getHistoryEntries(): readonly HistoryEntry[] {
|
||||||
return this.history.getEntries();
|
return this.history.entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addSyncHistoryUpdateListener(
|
public addSyncHistoryUpdateListener(
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,9 @@ export interface HistoryStats {
|
||||||
|
|
||||||
export class SyncHistory {
|
export class SyncHistory {
|
||||||
private static readonly MAX_ENTRIES = 500;
|
private static readonly MAX_ENTRIES = 500;
|
||||||
|
private static readonly TIMEOUT_FOR_MERGING_ENTRIES_IN_SECONDS = 15;
|
||||||
|
|
||||||
private entries: HistoryEntry[] = [];
|
private _entries: HistoryEntry[] = [];
|
||||||
|
|
||||||
private readonly syncHistoryUpdateListeners: ((
|
private readonly syncHistoryUpdateListeners: ((
|
||||||
status: HistoryStats
|
status: HistoryStats
|
||||||
|
|
@ -42,19 +43,35 @@ export class SyncHistory {
|
||||||
|
|
||||||
public constructor(private readonly logger: Logger) {}
|
public constructor(private readonly logger: Logger) {}
|
||||||
|
|
||||||
public getEntries(): HistoryEntry[] {
|
public get entries(): readonly HistoryEntry[] {
|
||||||
return [...this.entries];
|
return this._entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public reset(): void {
|
/**
|
||||||
this.entries.length = 0;
|
* Insert the entry at the beginning of the history list. If the entry
|
||||||
this.status = {
|
* already in the list, it will get moved to the beginning and updated.
|
||||||
success: 0,
|
*
|
||||||
error: 0
|
* If the entry list is too long, the oldest entry will be removed.
|
||||||
|
*/
|
||||||
|
public addHistoryEntry(entry: CommonHistoryEntry): void {
|
||||||
|
const historyEntry = {
|
||||||
|
...entry,
|
||||||
|
timestamp: new Date()
|
||||||
};
|
};
|
||||||
this.syncHistoryUpdateListeners.forEach((listener) => {
|
|
||||||
listener(this.status);
|
const candidate = this.findSimilarRecentEntry(historyEntry);
|
||||||
});
|
if (candidate !== undefined) {
|
||||||
|
this._entries = this._entries.filter((e) => e !== candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the entry at the beginning
|
||||||
|
this._entries.unshift(historyEntry);
|
||||||
|
|
||||||
|
if (this._entries.length > SyncHistory.MAX_ENTRIES) {
|
||||||
|
this._entries.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateSuccessCount(historyEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addSyncHistoryUpdateListener(
|
public addSyncHistoryUpdateListener(
|
||||||
|
|
@ -64,25 +81,35 @@ export class SyncHistory {
|
||||||
listener({ ...this.status });
|
listener({ ...this.status });
|
||||||
}
|
}
|
||||||
|
|
||||||
public addHistoryEntry(entry: CommonHistoryEntry): void {
|
public reset(): void {
|
||||||
const historyEntry = {
|
this._entries.length = 0;
|
||||||
...entry,
|
this.status = {
|
||||||
timestamp: new Date()
|
success: 0,
|
||||||
|
error: 0
|
||||||
};
|
};
|
||||||
|
this.syncHistoryUpdateListeners.forEach((listener) => {
|
||||||
|
listener(this.status);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const candidate = this.entries.find(
|
private findSimilarRecentEntry(
|
||||||
(e) => e.relativePath === historyEntry.relativePath
|
entry: HistoryEntry
|
||||||
|
): HistoryEntry | undefined {
|
||||||
|
const candidate = this._entries.find(
|
||||||
|
(e) => e.relativePath === entry.relativePath
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
candidate !== undefined &&
|
candidate !== undefined &&
|
||||||
(this.entries.slice(-1)[0] === candidate ||
|
(this._entries[0] === candidate ||
|
||||||
candidate.timestamp.getTime() + 10 * 1000 >
|
candidate.timestamp.getTime() +
|
||||||
historyEntry.timestamp.getTime())
|
SyncHistory.TIMEOUT_FOR_MERGING_ENTRIES_IN_SECONDS * 1000 >
|
||||||
|
entry.timestamp.getTime())
|
||||||
) {
|
) {
|
||||||
this.entries = this.entries.filter((e) => e !== candidate);
|
return candidate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.entries.push(historyEntry);
|
|
||||||
|
|
||||||
|
private updateSuccessCount(entry: HistoryEntry): void {
|
||||||
if (entry.status === SyncStatus.SUCCESS) {
|
if (entry.status === SyncStatus.SUCCESS) {
|
||||||
this.status.success++;
|
this.status.success++;
|
||||||
this.logger.info(
|
this.logger.info(
|
||||||
|
|
@ -94,13 +121,8 @@ export class SyncHistory {
|
||||||
`Cannot sync file: ${entry.relativePath} - ${entry.message}`
|
`Cannot sync file: ${entry.relativePath} - ${entry.message}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.syncHistoryUpdateListeners.forEach((listener) => {
|
this.syncHistoryUpdateListeners.forEach((listener) => {
|
||||||
listener(this.status);
|
listener(this.status);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.entries.length > SyncHistory.MAX_ENTRIES) {
|
|
||||||
this.entries.shift();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue