Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ <h5 class="rightAlign"><span [innerHTML]="compare(column.header, 'other')"></spa
nz-button
nzType="link"
class="download-button"
title="Download data">
[disabled]="!exportEnabled"
[title]="exportEnabled ? 'Download data' : 'Result export is disabled on this deployment'">
<i
nz-icon
nzType="cloud-download"></i>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ th.header-size {
font-size: 16px; // Slightly larger to match the cloud icon
color: #1890ff; // Ant Design's primary blue color
}

// Disabled when result export is switched off. The icon color and cursor above are
// hardcoded, so without this the disabled button would look exactly like the live one.
&[disabled] {
cursor: not-allowed;

i {
color: rgba(0, 0, 0, 0.25); // Ant Design's disabled text color
}
}
}

.table-row-hover:hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { By, DomSanitizer } from "@angular/platform-browser";
import { of, Subject } from "rxjs";
import { commonTestProviders } from "../../../../common/testing/test-utils";
import { GuiConfigService } from "../../../../common/service/gui-config.service";
import { MockGuiConfigService } from "../../../../common/service/gui-config.service.mock";
import { isAudioUrl, isImageUrl, isVideoUrl } from "../../../../common/util/media-type.util";
import {
OperatorPaginationResultService,
Expand Down Expand Up @@ -696,6 +697,11 @@ describe("ResultTableFrameComponent", () => {
});

it("renders headers, per-column stats, and clickable row cells once results arrive", () => {
// The download click below must land on a live button: MockGuiConfigService ships with the
// export switch off, which would disable it.
(TestBed.inject(GuiConfigService) as unknown as MockGuiConfigService).setConfig({
exportExecutionResultEnabled: true,
});
component.operatorId = "op1";
component.setupResultTable([SAMPLE_ROW], 1);
component.isFrontPagination = false;
Expand Down Expand Up @@ -741,11 +747,42 @@ describe("ResultTableFrameComponent", () => {
expect(openSpy).toHaveBeenCalledWith(0, SAMPLE_ROW);

const download = fixture.debugElement.query(By.css("button.download-button"));
expect((download.nativeElement as HTMLButtonElement).disabled).toBe(false);
download.triggerEventHandler("click", { stopPropagation: vi.fn() });
expect(downloadSpy).toHaveBeenCalledWith("alice", 0, 0, "name");
});
});

describe("per-cell download button and the export switch", () => {
// `commonTestProviders` supplies MockGuiConfigService (export switch off by default), so the
// switch is driven through it rather than through the `useValue` above.
function renderOneRow(exportEnabled: boolean): void {
(TestBed.inject(GuiConfigService) as unknown as MockGuiConfigService).setConfig({
exportExecutionResultEnabled: exportEnabled,
});
component.operatorId = "op1";
component.setupResultTable([SAMPLE_ROW], 1);
component.isFrontPagination = false;
fixture.detectChanges();
}

it("is enabled and offers a download when result export is on", () => {
renderOneRow(true);
const button = fixture.debugElement.query(By.css("button.download-button")).nativeElement as HTMLButtonElement;
expect(button.disabled).toBe(false);
expect(button.title).toBe("Download data");
});

it("is disabled and says why when result export is switched off", () => {
// The top menu and the context menu already honour the switch; before this the cell
// button rendered anyway and a click did nothing, with no request and no message.
renderOneRow(false);
const button = fixture.debugElement.query(By.css("button.download-button")).nativeElement as HTMLButtonElement;
expect(button.disabled).toBe(true);
expect(button.title).toBe("Result export is disabled on this deployment");
});
});

it("should detect media URLs for result cells", () => {
expect(component.isVideoCell("https://example.com/clip.mp4")).toBe(true);
expect(component.isAudioCell("https://example.com/sound.wav")).toBe(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,16 @@ export class ResultTableFrameComponent implements OnInit, OnChanges {
}));
}

/**
* Result export is a deployment switch (`export-execution-result-enabled`). The top menu and
* the context menu already honour it; the per-cell download button did not -- it rendered
* regardless, and clicking it returned silently from the export service with no request and
* no message. Disable it here so the reader sees why nothing happens.
*/
get exportEnabled(): boolean {
return this.guiConfigService.env.exportExecutionResultEnabled === true;
}

downloadData(data: any, rowIndex: number, columnIndex: number, columnName: string): void {
const realRowNumber = (this.currentPageIndex - 1) * this.pageSize + rowIndex;
const defaultFileName = `${columnName}_${realRowNumber}`;
Expand Down
Loading