Skip to content
Merged
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
51 changes: 51 additions & 0 deletions apps/web/src/hooks/__tests__/useInstrumentVisualization.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const mockStore = {

const mockDownloadFn = vi.fn();

const mockExcelDownloadFn = vi.hoisted(() => vi.fn());

const mockInfoQuery = {
data: []
};
Expand Down Expand Up @@ -53,6 +55,10 @@ vi.mock('@/hooks/useInstrumentInfoQuery', () => ({
useInstrumentInfoQuery: () => mockInfoQuery
}));

vi.mock('@/utils/excel', () => ({
downloadSubjectTableExcel: mockExcelDownloadFn
}));

vi.mock('@/hooks/useInstrumentRecords', () => ({
useInstrumentRecords: () => mockInstrumentRecords
}));
Expand Down Expand Up @@ -124,6 +130,51 @@ describe('useInstrumentVisualization', () => {
);
});
});
describe('Excel', () => {
it('Should download', () => {
const { result } = renderHook(() => useInstrumentVisualization({ params: { subjectId: 'testId' } }));
const { dl, records } = result.current;
act(() => dl('Excel'));
expect(records).toBeDefined();
expect(mockExcelDownloadFn).toHaveBeenCalledTimes(1);
const [filename, getContentFn] = mockExcelDownloadFn.mock.calls[0] ?? [];
expect(filename).toMatch('.xlsx');
const excelContents = getContentFn;

expect(excelContents).toEqual([
{
GroupID: 'testGroupId',
subjectId: 'testId',
// eslint-disable-next-line perfectionist/sort-objects
Date: '2025-04-30',
someValue: 'abc'
}
]);
});
});
describe('Excel Long', () => {
it('Should download', () => {
const { result } = renderHook(() => useInstrumentVisualization({ params: { subjectId: 'testId' } }));
const { dl, records } = result.current;
act(() => dl('Excel Long'));
expect(records).toBeDefined();
expect(mockExcelDownloadFn).toHaveBeenCalledTimes(1);

const [filename, getContentFn] = mockExcelDownloadFn.mock.calls[0] ?? [];
expect(filename).toMatch('.xlsx');
const excelContents = getContentFn;

expect(excelContents).toEqual([
{
Date: '2025-04-30',
GroupID: 'testGroupId',
SubjectID: 'testId',
Value: 'abc',
Variable: 'someValue'
}
]);
});
});
describe('JSON', () => {
it('Should download', async () => {
const { result } = renderHook(() => useInstrumentVisualization({ params: { subjectId: 'testId' } }));
Expand Down
13 changes: 12 additions & 1 deletion apps/web/src/hooks/useInstrumentVisualization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useInstrument } from '@/hooks/useInstrument';
import { useInstrumentInfoQuery } from '@/hooks/useInstrumentInfoQuery';
import { useInstrumentRecords } from '@/hooks/useInstrumentRecords';
import { useAppStore } from '@/store';
import { downloadSubjectTableExcel } from '@/utils/excel';

type InstrumentVisualizationRecord = {
[key: string]: unknown;
Expand Down Expand Up @@ -53,7 +54,7 @@ export function useInstrumentVisualization({ params }: UseInstrumentVisualizatio
}
});

const dl = (option: 'CSV' | 'CSV Long' | 'JSON' | 'TSV' | 'TSV Long') => {
const dl = (option: 'CSV' | 'CSV Long' | 'Excel' | 'Excel Long' | 'JSON' | 'TSV' | 'TSV Long') => {
if (!instrument) {
notifications.addNotification({ message: t('errors.noInstrumentSelected'), type: 'error' });
return;
Expand Down Expand Up @@ -157,6 +158,16 @@ export function useInstrumentVisualization({ params }: UseInstrumentVisualizatio
});
break;
}
case 'Excel': {
const rows = makeWideRows();
downloadSubjectTableExcel(`${baseFilename}.xlsx`, rows);
break;
}
case 'Excel Long': {
const rows = makeLongRows();
downloadSubjectTableExcel(`${baseFilename}.xlsx`, rows);
break;
}
case 'JSON': {
exportRecords.map((item) => {
item.subjectID = params.subjectId;
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/routes/_app/datahub/$subjectId/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const RouteComponent = () => {
widthFull
data-spotlight-type="export-data-dropdown"
disabled={!instrumentId}
options={['TSV', 'TSV Long', 'JSON', 'CSV', 'CSV Long']}
options={['TSV', 'TSV Long', 'JSON', 'CSV', 'CSV Long', 'Excel', 'Excel Long']}
title={t('core.download')}
triggerClassName="min-w-32"
onSelection={dl}
Expand Down
8 changes: 7 additions & 1 deletion apps/web/src/utils/__tests__/excel.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { describe, expect, it } from 'vitest';

import { downloadExcel } from '../excel';
import { downloadExcel, downloadSubjectTableExcel } from '../excel';

describe('downloadExcel', () => {
it('should be defined', () => {
expect(downloadExcel).toBeDefined();
});
});

describe('downloadSujectTableExcel', () => {
it('should be defined', () => {
expect(downloadSubjectTableExcel).toBeDefined();
});
});
6 changes: 6 additions & 0 deletions apps/web/src/utils/excel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ export function downloadExcel(filename: string, recordsExport: InstrumentRecords
utils.book_append_sheet(workbook, utils.json_to_sheet(recordsExport), 'ULTRA_LONG');
writeFileXLSX(workbook, filename);
}

export function downloadSubjectTableExcel(filename: string, records: { [key: string]: any }[]) {
const workbook = utils.book_new();
utils.book_append_sheet(workbook, utils.json_to_sheet(records), 'ULTRA_LONG');
writeFileXLSX(workbook, filename);
}