diff --git a/package.json b/package.json index aca82f7..854f1ce 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,10 @@ "command": "diffviewer.showSideBySide", "title": "Show diff side by side", "icon": "$(files)" + }, + { + "command": "diffviewer.openCollapsed", + "title": "Open diff collapsed (all viewed)" } ], "customEditors": [ @@ -142,6 +146,13 @@ } ], "menus": { + "explorer/context": [ + { + "command": "diffviewer.openCollapsed", + "group": "navigation@99", + "when": "resourceLangId == 'diff'" + } + ], "editor/title": [ { "command": "diffviewer.showLineByLine", @@ -165,7 +176,7 @@ "pack:extension": "vsce package -o ./dist/vscode_diff_viewer_v$npm_package_version.vsix --githubBranch main", "run:webmode": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=. --version=stable", "jest:run": "jest --silent", - "test": "npm run jest:run", + "test": "npm run jest:run --", "test:coverage": "jest --coverage --silent", "test:coverage:ci": "jest --coverage --ci --silent", "prepare": "husky install" diff --git a/src/extension/__tests__/provider.test.ts b/src/extension/__tests__/provider.test.ts index e67f715..5e72596 100644 --- a/src/extension/__tests__/provider.test.ts +++ b/src/extension/__tests__/provider.test.ts @@ -7,7 +7,6 @@ import { MessageToExtensionHandlerImpl } from "../message/handler"; import { ViewedStateStore } from "../viewed-state"; import { buildSkeleton } from "../skeleton"; import { extractConfig, setOutputFormatConfig } from "../configuration"; -import { SkeletonElementIds } from "../../shared/css/elements"; import { MessageToWebview } from "../../shared/message"; // Mock dependencies @@ -188,7 +187,7 @@ describe("DiffViewerProvider", () => { webviewPath: mockWebviewPath, }); - expect(disposables).toHaveLength(3); + expect(disposables).toHaveLength(4); expect(mockRegisterCustomEditorProvider).toHaveBeenCalledWith("diffViewer", expect.any(DiffViewerProvider), { webviewOptions: { retainContextWhenHidden: true, @@ -198,24 +197,42 @@ describe("DiffViewerProvider", () => { }); expect(mockRegisterCommand).toHaveBeenCalledWith("diffviewer.showLineByLine", expect.any(Function)); expect(mockRegisterCommand).toHaveBeenCalledWith("diffviewer.showSideBySide", expect.any(Function)); + expect(mockRegisterCommand).toHaveBeenCalledWith("diffviewer.openCollapsed", expect.any(Function)); }); - it("should call setOutputFormatConfig when commands are executed", () => { + it.each([ + ["showSideBySide", "side-by-side"], + ["showLineByLine", "line-by-line"], + ])("should call setOutputFormatConfig when commands are executed", (cmd, expectedConfig) => { DiffViewerProvider.registerContributions({ extensionContext: mockExtensionContext, webviewPath: mockWebviewPath, }); - // Get the command functions - const lineByLineCommand = mockRegisterCommand.mock.calls[0][1]; - const sideBySideCommand = mockRegisterCommand.mock.calls[1][1]; + // Get the command function + const command = mockRegisterCommand.mock.calls.find((c) => c[0] == `diffviewer.${cmd}`)[1]; // Execute commands - lineByLineCommand(); - sideBySideCommand(); + command(); - expect(mockSetOutputFormatConfig).toHaveBeenCalledWith("line-by-line"); - expect(mockSetOutputFormatConfig).toHaveBeenCalledWith("side-by-side"); + expect(mockSetOutputFormatConfig).toHaveBeenCalledWith(expectedConfig); + }); + + it("should open a diff with all files collapsed", () => { + DiffViewerProvider.registerContributions({ + extensionContext: mockExtensionContext, + webviewPath: mockWebviewPath, + }); + + // Get the command function + const command = mockRegisterCommand.mock.calls.find((c) => c[0] == `diffviewer.openCollapsed`)[1]; + + (vscode.Uri.file as jest.Mock).mockReturnValueOnce({ with: jest.fn().mockReturnValue("uri-with-selected") }); + + // Execute commands + command(vscode.Uri.file("foo.patch")); + + expect(vscode.commands.executeCommand).toHaveBeenCalledWith("vscode.openWith", "uri-with-selected", "diffViewer"); }); }); @@ -307,7 +324,7 @@ describe("DiffViewerProvider", () => { config: expect.any(Object), diffFiles: expect.any(Array), viewedState: expect.any(Object), - diffContainer: SkeletonElementIds.DiffContainer, + collapseAll: false, }, }); }); @@ -452,7 +469,6 @@ describe("DiffViewerProvider", () => { config: expect.any(Object), diffFiles: expect.any(Array), viewedState: expect.any(Object), - diffContainer: SkeletonElementIds.DiffContainer, }), }); }); diff --git a/src/extension/provider.ts b/src/extension/provider.ts index d9bfa06..16f48f5 100644 --- a/src/extension/provider.ts +++ b/src/extension/provider.ts @@ -2,7 +2,6 @@ import { parse } from "diff2html"; import { ColorSchemeType } from "diff2html/lib/types"; import { basename } from "path"; import * as vscode from "vscode"; -import { SkeletonElementIds } from "../shared/css/elements"; import { MessageToExtensionHandler, MessageToWebview } from "../shared/message"; import { APP_CONFIG_SECTION, AppConfig, extractConfig, setOutputFormatConfig } from "./configuration"; import { MessageToExtensionHandlerImpl } from "./message/handler"; @@ -44,6 +43,10 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider { }), vscode.commands.registerCommand("diffviewer.showLineByLine", () => setOutputFormatConfig("line-by-line")), vscode.commands.registerCommand("diffviewer.showSideBySide", () => setOutputFormatConfig("side-by-side")), + vscode.commands.registerCommand("diffviewer.openCollapsed", async (file) => { + const collapsedUri = file.with({ query: "collapsed" }); + await vscode.commands.executeCommand("vscode.openWith", collapsedUri, "diffViewer"); + }), ]; } @@ -72,6 +75,8 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider { docId: diffDocument.uri.fsPath, }); + const collapseAll = new URLSearchParams(diffDocument.uri.query).has("collapsed"); + const messageReceivedHandler = new MessageToExtensionHandlerImpl({ diffDocument, viewedStateStore, @@ -83,7 +88,7 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider { const webviewContext: WebviewContext = { document: diffDocument, panel: webviewPanel, viewedStateStore }; this.registerEventHandlers({ webviewContext, messageHandler: messageReceivedHandler }); - this.updateWebview(webviewContext); + this.updateWebview(webviewContext, collapseAll); } private registerEventHandlers(args: { webviewContext: WebviewContext; messageHandler: MessageToExtensionHandler }) { @@ -113,7 +118,7 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider { args.webviewContext.panel.onDidDispose(() => disposables.dispose()); } - private updateWebview(webviewContext: WebviewContext): void { + private updateWebview(webviewContext: WebviewContext, collapseAll = false): void { this.postMessageToWebviewWrapper({ webview: webviewContext.panel.webview, message: { @@ -154,7 +159,7 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider { config: config, diffFiles: diffFiles, viewedState: viewedState, - diffContainer: SkeletonElementIds.DiffContainer, + collapseAll, }, }, }); diff --git a/src/extension/viewed-state.ts b/src/extension/viewed-state.ts index 7349b4e..349794e 100644 --- a/src/extension/viewed-state.ts +++ b/src/extension/viewed-state.ts @@ -34,7 +34,9 @@ export class ViewedStateStore { if (!this.args.docId) { this.transientViewedState = viewedState; } else { - this.args.context.workspaceState.update(this.args.docId, viewedState); + // remove the state if no files are marked as viewed + const stateToSave = Object.keys(viewedState).length === 0 ? undefined : viewedState; + this.args.context.workspaceState.update(this.args.docId, stateToSave); } } } diff --git a/src/webview/css/classes.ts b/src/webview/css/classes.ts new file mode 100644 index 0000000..520ad6b --- /dev/null +++ b/src/webview/css/classes.ts @@ -0,0 +1,4 @@ +export enum Diff2HtmlCssClasses { + Div__DiffFileContent__Collapsed = "d2h-d-none", + Input__ViewedToggle__Selected = "d2h-selected", +} diff --git a/src/webview/css/elements.ts b/src/webview/css/elements.ts index c50311f..bb14ded 100644 --- a/src/webview/css/elements.ts +++ b/src/webview/css/elements.ts @@ -5,6 +5,7 @@ export enum Diff2HtmlCssClassElements { Div__File = ".d2h-file-wrapper", Div__LeftDiffOnSideBySide__FirstChild = ".d2h-file-side-diff:first-child", Div__LineNumberRightOnLineByLine = ".line-num2", + Label__ViewedToggle = ".d2h-file-collapse", Input__ViewedToggle = ".d2h-file-collapse-input", Input__ViewedToggle__Checked = ".d2h-file-collapse-input:checked", Td__DeletedLine = ".d2h-del", diff --git a/src/webview/message/__tests__/handler.test.ts b/src/webview/message/__tests__/handler.test.ts index f08e299..3aa076c 100644 --- a/src/webview/message/__tests__/handler.test.ts +++ b/src/webview/message/__tests__/handler.test.ts @@ -203,6 +203,7 @@ describe("MessageToWebviewHandlerImpl", () => { mockDiffContainer = { querySelectorAll: mockQuerySelectorAll, addEventListener: mockAddEventListener, + style: {}, } as unknown as HTMLElement; mockDiffFiles = [createMockDiffFile("file1.ts"), createMockDiffFile("file2.ts")]; @@ -216,8 +217,8 @@ describe("MessageToWebviewHandlerImpl", () => { await handler.updateWebview({ config: mockConfig, diffFiles: mockDiffFiles, - diffContainer: "test-container", viewedState: mockViewedState, + collapseAll: false, }); expect(Diff2HtmlUI).not.toHaveBeenCalled(); @@ -227,12 +228,13 @@ describe("MessageToWebviewHandlerImpl", () => { const mockDiffContainer = { querySelectorAll: mockQuerySelectorAll, addEventListener: mockAddEventListener, + style: {}, } as unknown as HTMLElement; // Reset the mock to use the global implementation mockGetElementById.mockReset(); mockGetElementById.mockImplementation((id: string) => { - if (id === "test-container") { + if (id === "diff-container") { return mockDiffContainer; } if (id === "mark-all-viewed-checkbox") { @@ -259,8 +261,8 @@ describe("MessageToWebviewHandlerImpl", () => { await handler.updateWebview({ config: mockConfig, diffFiles: [], - diffContainer: "test-container", viewedState: mockViewedState, + collapseAll: false, }); expect(mockGetElementById).toHaveBeenCalledWith("empty-message-container"); @@ -278,7 +280,7 @@ describe("MessageToWebviewHandlerImpl", () => { // Reset the mock to use the global implementation mockGetElementById.mockReset(); mockGetElementById.mockImplementation((id: string) => { - if (id === "test-container") { + if (id === "diff-container") { return mockDiffContainer; } if (id === "mark-all-viewed-checkbox") { @@ -306,14 +308,74 @@ describe("MessageToWebviewHandlerImpl", () => { getPropertyValue: jest.fn().mockReturnValue("test-value"), }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const setAllViewedStates = ((handler as any).setAllViewedStates = jest.fn()); + await handler.updateWebview({ config: mockConfig, diffFiles: mockDiffFiles, - diffContainer: "test-container", viewedState: mockViewedState, + collapseAll: false, }); expect(Diff2HtmlUI).toHaveBeenCalledWith(mockDiffContainer, mockDiffFiles, mockConfig.diff2html); + expect(setAllViewedStates).not.toHaveBeenCalled(); + }); + + it("should collapse all files if called with collapseAll", async () => { + const mockRoot = { + style: { setProperty: jest.fn() }, + }; + Object.defineProperty(global.document, "documentElement", { + value: mockRoot, + writable: true, + }); + + // Reset the mock to use the global implementation + mockGetElementById.mockReset(); + mockGetElementById.mockImplementation((id: string) => { + if (id === "diff-container") { + return mockDiffContainer; + } + if (id === "mark-all-viewed-checkbox") { + return { addEventListener: mockAddEventListener }; + } + if (id === "loading-container") { + return { style: { display: "none" } }; + } + if (id === "empty-message-container") { + return { style: { display: "none" } }; + } + if (id === "viewed-indicator") { + return { textContent: "" }; + } + if (id === "viewed-progress") { + return { style: { width: "" } }; + } + if (id === "mark-all-viewed-container") { + return { classList: { add: jest.fn(), remove: jest.fn() } }; + } + return { style: { display: "none" } }; + }); + + mockGetComputedStyle.mockReturnValue({ + getPropertyValue: jest.fn().mockReturnValue("test-value"), + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const setAllViewedStates = ((handler as any).setAllViewedStates = jest.fn()); + + await handler.updateWebview({ + config: mockConfig, + diffFiles: mockDiffFiles, + viewedState: mockViewedState, + collapseAll: true, + }); + + expect(Diff2HtmlUI).toHaveBeenCalledWith(mockDiffContainer, mockDiffFiles, mockConfig.diff2html); + + expect(setAllViewedStates).toHaveBeenCalledTimes(1); + expect(setAllViewedStates).toHaveBeenCalledWith(true); }); }); @@ -376,22 +438,28 @@ describe("MessageToWebviewHandlerImpl", () => { addEventListener: mockAddEventListener, } as unknown as HTMLInputElement; + const mockClosest = () => ({ querySelector: () => ({ classList: { toggle: jest.fn() } }) }); + const mockToggles = [ - { checked: false, click: mockClick }, - { checked: false, click: mockClick }, + { checked: false, closest: mockClosest, classList: { remove: jest.fn() } }, + { checked: false, closest: mockClosest, classList: { remove: jest.fn() } }, ]; mockGetElementById.mockReturnValue(mockMarkAllCheckbox); // eslint-disable-next-line @typescript-eslint/no-explicit-any (handler as any).getViewedToggles = jest.fn().mockReturnValue(mockToggles); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (handler as any).updateFooter = jest.fn(); const mockEvent = { target: mockMarkAllCheckbox } as unknown as Event; // eslint-disable-next-line @typescript-eslint/no-explicit-any (handler as any).onMarkAllViewedChangedHandler(mockEvent); - expect(mockToggles[0].click).toHaveBeenCalled(); - expect(mockToggles[1].click).toHaveBeenCalled(); + expect(mockToggles[0].checked).toBe(true); + expect(mockToggles[1].checked).toBe(true); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((handler as any).updateFooter).toHaveBeenCalled(); }); }); @@ -560,6 +628,7 @@ describe("MessageToWebviewHandlerImpl", () => { click: mockClick, classList: { add: jest.fn() }, closest: mockClosest, + checked: false, // this will be set to true if the toggle is switched }; const mockFileContainer = { @@ -568,10 +637,11 @@ describe("MessageToWebviewHandlerImpl", () => { const mockDiffContainer = { querySelectorAll: jest.fn().mockReturnValue([mockToggle]), + style: {}, } as unknown as HTMLElement; mockClosest.mockReturnValue(mockFileContainer); - mockQuerySelector.mockReturnValue({ textContent: "file1.ts" }); + mockQuerySelector.mockReturnValue({ textContent: "file1.ts", classList: { toggle: jest.fn() } }); (getSha1Hash as jest.Mock).mockResolvedValue("hash1"); // Mock the getDiffElementFileName method to return the correct file name @@ -585,7 +655,7 @@ describe("MessageToWebviewHandlerImpl", () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any await (handler as any).hideViewedFiles(mockDiffContainer, mockViewedState); - expect(mockToggle.click).toHaveBeenCalled(); + expect(mockToggle.checked).toBe(true); }); it("should mark files as changed since viewed", async () => { @@ -601,10 +671,14 @@ describe("MessageToWebviewHandlerImpl", () => { const mockDiffContainer = { querySelectorAll: jest.fn().mockReturnValue([mockToggle]), + style: {}, } as unknown as HTMLElement; mockClosest.mockReturnValue(mockFileContainer); - mockQuerySelector.mockReturnValue({ textContent: "file1.ts" }); + mockQuerySelector.mockReturnValue({ + textContent: "file1.ts", + classList: { toggle: jest.fn() }, + }); (getSha1Hash as jest.Mock).mockResolvedValue("different-hash"); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -639,7 +713,7 @@ describe("MessageToWebviewHandlerImpl", () => { (handler as any).getDiffHash = jest.fn().mockResolvedValue("test-hash"); // eslint-disable-next-line @typescript-eslint/no-explicit-any - await (handler as any).sendFileViewedMessage(mockToggle as unknown as HTMLInputElement); + await (handler as any).sendFileViewedMessage(mockToggle as unknown as HTMLInputElement, true); expect(mockPostMessageToExtensionFn).toHaveBeenCalledWith({ kind: "toggleFileViewed", @@ -785,6 +859,7 @@ describe("MessageToWebviewHandlerImpl", () => { const mockDiffContainer = { querySelectorAll: mockQuerySelectorAll, addEventListener: mockAddEventListener, + style: {}, } as unknown as HTMLElement; const mockViewedToggles = [ @@ -810,8 +885,8 @@ describe("MessageToWebviewHandlerImpl", () => { await handler.updateWebview({ config: mockConfig, diffFiles: [createMockDiffFile("test.ts")], - diffContainer: "test-container", viewedState: mockViewedState, + collapseAll: false, }); expect(Diff2HtmlUI).toHaveBeenCalled(); diff --git a/src/webview/message/api.ts b/src/webview/message/api.ts index b91c771..8c9ace8 100644 --- a/src/webview/message/api.ts +++ b/src/webview/message/api.ts @@ -5,8 +5,8 @@ import { ViewedState } from "../../extension/viewed-state"; export interface UpdateWebviewPayload { config: AppConfig; diffFiles: DiffFile[]; - diffContainer: string; viewedState: ViewedState; + collapseAll: boolean; } export interface MessageToWebviewApi { diff --git a/src/webview/message/handler.ts b/src/webview/message/handler.ts index 7ebda01..176d5f2 100644 --- a/src/webview/message/handler.ts +++ b/src/webview/message/handler.ts @@ -7,6 +7,7 @@ import { extractNewFileNameFromDiffName, extractNumberFromString } from "../../s import { MessageToExtension, MessageToWebviewHandler } from "../../shared/message"; import { GenericMessageHandlerImpl } from "../../shared/message-handler"; import { AppTheme } from "../../shared/types"; +import { Diff2HtmlCssClasses } from "../css/classes"; import { Diff2HtmlCssClassElements } from "../css/elements"; import { UpdateWebviewPayload } from "./api"; import { getSha1Hash } from "./hash"; @@ -31,7 +32,7 @@ export class MessageToWebviewHandlerImpl extends GenericMessageHandlerImpl imple } public async updateWebview(payload: UpdateWebviewPayload): Promise { - const diffContainer = document.getElementById(payload.diffContainer); + const diffContainer = document.getElementById(SkeletonElementIds.DiffContainer); if (!diffContainer) { return; } @@ -46,13 +47,25 @@ export class MessageToWebviewHandlerImpl extends GenericMessageHandlerImpl imple const appTheme = this.currentConfig.diff2html.colorScheme === ColorSchemeType.DARK ? "dark" : "light"; this.setupTheme(appTheme); + // hide the diff container for now so the full diff doesn't show + if (payload.collapseAll) { + diffContainer.style.display = "none"; + } + const diff2html = new Diff2HtmlUI(diffContainer, payload.diffFiles, this.currentConfig.diff2html); diff2html.draw(); this.registerViewedToggleHandlers(diffContainer); this.registerDiffContainerHandlers(diffContainer); - await this.hideViewedFiles(diffContainer, payload.viewedState); + if (payload.collapseAll) { + this.setAllViewedStates(true); + } else { + await this.hideViewedFiles(diffContainer, payload.viewedState); + } this.updateFooter(); + + // show the diff + diffContainer.style.display = "block"; }); } @@ -91,7 +104,7 @@ export class MessageToWebviewHandlerImpl extends GenericMessageHandlerImpl imple viewedToggle.classList.remove(CHANGED_SINCE_VIEWED); this.scrollDiffFileHeaderIntoView(viewedToggle); this.updateFooter(); - this.sendFileViewedMessage(viewedToggle); + this.sendFileViewedMessage(viewedToggle, viewedToggle.checked); } private onMarkAllViewedChangedHandler(event: Event): void { @@ -101,12 +114,18 @@ export class MessageToWebviewHandlerImpl extends GenericMessageHandlerImpl imple } const isChecked = markAllViewedCheckbox.checked; + this.setAllViewedStates(isChecked); + this.updateFooter(); + } + + private setAllViewedStates(viewed: boolean) { const allToggles = this.getViewedToggles(); for (const toggle of Array.from(allToggles)) { - if (toggle.checked !== isChecked) { - toggle.click(); - } + this.updateDiff2HtmlFileCollapsed(toggle, viewed); + toggle.classList.remove(CHANGED_SINCE_VIEWED); + // no await here so we synchronously return from this function, the sending will happen later as hashes get computed + void this.sendFileViewedMessage(toggle, viewed); } } @@ -265,32 +284,50 @@ export class MessageToWebviewHandlerImpl extends GenericMessageHandlerImpl imple const viewedToggles = diffContainer.querySelectorAll( Diff2HtmlCssClassElements.Input__ViewedToggle, ); + + // first synchronously hide all viewed files so we don't render too much in case the file is huge and most is collapsed + // we'll do a second pass over hidden files, so we'll hold them in togglesToRevisit + const togglesToRevisit = []; for (const toggle of Array.from(viewedToggles)) { const fileName = this.getDiffElementFileName(toggle); if (fileName && viewedState[fileName]) { - const diffHash = await this.getDiffHash(toggle); - if (diffHash === viewedState[fileName]) { - toggle.click(); - } else { - toggle.classList.add(CHANGED_SINCE_VIEWED); - } + togglesToRevisit.push({ toggle, oldSha1: viewedState[fileName] }); + this.updateDiff2HtmlFileCollapsed(toggle, true); + } + } + + for (const { toggle, oldSha1 } of togglesToRevisit) { + const diffHash = await this.getDiffHash(toggle); + if (diffHash !== oldSha1) { + this.updateDiff2HtmlFileCollapsed(toggle, false); + toggle.classList.add(CHANGED_SINCE_VIEWED); } } } + private updateDiff2HtmlFileCollapsed(toggleElement: HTMLInputElement, collapse: boolean) { + // do the same thing that diff2html does to collapse or expand one file + toggleElement.checked = collapse; + const fileContainer = this.getDiffFileContainer(toggleElement); + const label = fileContainer?.querySelector(Diff2HtmlCssClassElements.Label__ViewedToggle); + label?.classList.toggle(Diff2HtmlCssClasses.Input__ViewedToggle__Selected, collapse); + const fileContent = fileContainer?.querySelector(Diff2HtmlCssClassElements.Div__DiffFileContent); + fileContent?.classList.toggle(Diff2HtmlCssClasses.Div__DiffFileContent__Collapsed, collapse); + } + private async getDiffHash(diffElement: HTMLElement): Promise { const fileContainer = this.getDiffFileContainer(diffElement); const fileContent = fileContainer?.querySelector(Diff2HtmlCssClassElements.Div__DiffFileContent)?.innerHTML; return fileContent ? getSha1Hash(fileContent) : null; } - private async sendFileViewedMessage(toggleElement: HTMLInputElement): Promise { - const fileName = this.getDiffElementFileName(toggleElement); + private async sendFileViewedMessage(diffElement: HTMLInputElement, viewed: boolean): Promise { + const fileName = this.getDiffElementFileName(diffElement); if (!fileName) { return; } - const viewedSha1 = toggleElement.checked ? await this.getDiffHash(toggleElement) : null; + const viewedSha1 = viewed ? await this.getDiffHash(diffElement) : null; this.postMessageToExtensionFn({ kind: "toggleFileViewed", @@ -310,21 +347,21 @@ export class MessageToWebviewHandlerImpl extends GenericMessageHandlerImpl imple this.showLoading(false); } - private showLoading(isVisible: boolean): void { + private showLoading(isLoading: boolean): void { const loadingContainer = document.getElementById(SkeletonElementIds.LoadingContainer); if (!loadingContainer) { return; } - loadingContainer.style.display = isVisible ? "block" : "none"; + loadingContainer.style.display = isLoading ? "block" : "none"; } - private showEmpty(isVisible: boolean): void { + private showEmpty(isEmpty: boolean): void { const emptyMessageContainer = document.getElementById(SkeletonElementIds.EmptyMessageContainer); if (!emptyMessageContainer) { return; } - emptyMessageContainer.style.display = isVisible ? "block" : "none"; + emptyMessageContainer.style.display = isEmpty ? "block" : "none"; } }