Skip to content

Commit

Permalink
refactor(ui): improve type definitions and consistency across matrix …
Browse files Browse the repository at this point in the history
…operations

- Update and align type definitions for matrix-related operations
- Refactor MatrixUpdateDTO to match actual usage in API interactions
- Enhance GridUpdate and related types for better type safety
- Adjust useMatrix hook to utilize updated type definitions
- Modify test cases to reflect new type structures
- Ensure consistency between client-side types and API expectations
  • Loading branch information
hdinia committed Sep 12, 2024
1 parent 057f535 commit d810cbe
Show file tree
Hide file tree
Showing 13 changed files with 255 additions and 207 deletions.
7 changes: 6 additions & 1 deletion webapp/src/components/common/MatrixGrid/MatrixActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,15 @@ function MatrixActions({
ButtonProps={{
startIcon: <FileDownload />,
}}
disabled={isSubmitting}
>
{t("global.import")}
</SplitButton>
<DownloadMatrixButton studyId={studyId} path={path} disabled={disabled} />
<DownloadMatrixButton
studyId={studyId}
path={path}
disabled={disabled || isSubmitting}
/>
</Box>
);
}
Expand Down
21 changes: 10 additions & 11 deletions webapp/src/components/common/MatrixGrid/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { render } from "@testing-library/react";
import MatrixGrid, { MatrixGridProps } from ".";
import Box from "@mui/material/Box";
import { mockGetBoundingClientRect } from "../../../tests/mocks/mockGetBoundingClientRect";
import { type EnhancedGridColumn } from "./types";
import { ColumnDataType } from "./utils";
import { type EnhancedGridColumn, ColumnTypes } from "./types";
import { mockHTMLCanvasElement } from "../../../tests/mocks/mockHTMLCanvasElement";

beforeEach(() => {
Expand Down Expand Up @@ -54,23 +53,23 @@ describe("MatrixGrid rendering", () => {
id: "col1",
title: "Column 1",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 0,
},
{
id: "col2",
title: "Column 2",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 1,
},
{
id: "col3",
title: "Column 3",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 2,
},
Expand Down Expand Up @@ -105,23 +104,23 @@ describe("MatrixGrid rendering", () => {
id: "col1",
title: "Column 1",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 0,
},
{
id: "col2",
title: "Column 2",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 1,
},
{
id: "col3",
title: "Column 3",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 2,
},
Expand Down Expand Up @@ -158,23 +157,23 @@ describe("MatrixGrid rendering", () => {
id: "col1",
title: "Column 1",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 0,
},
{
id: "col2",
title: "Column 2",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 1,
},
{
id: "col3",
title: "Column 3",
width: 100,
type: ColumnDataType.Number,
type: ColumnTypes.Number,
editable: true,
order: 2,
},
Expand Down
48 changes: 22 additions & 26 deletions webapp/src/components/common/MatrixGrid/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import "@glideapps/glide-data-grid/dist/index.css";
import DataEditor, {
CompactSelection,
EditListItem,
EditableGridCell,
EditListItem,
GridCellKind,
GridSelection,
Item,
} from "@glideapps/glide-data-grid";
import { useGridCellContent } from "./useGridCellContent";
import { useMemo, useState } from "react";
import { type CellFillPattern, type EnhancedGridColumn } from "./types";
import { EnhancedGridColumn, GridUpdate } from "./types";
import { darkTheme, readOnlyDarkTheme } from "./utils";
import { useColumnMapping } from "./useColumnMapping";

Expand All @@ -21,11 +22,8 @@ export interface MatrixGridProps {
rowHeaders?: string[];
width?: string;
height?: string;
onCellEdit?: (cell: Item, newValue: number) => void;
onMultipleCellsEdit?: (
updates: Array<{ coordinates: Item; value: number }>,
fillPattern?: CellFillPattern,
) => void;
onCellEdit?: (update: GridUpdate) => void;
onMultipleCellsEdit?: (updates: GridUpdate[]) => void;
readOnly?: boolean;
}

Expand Down Expand Up @@ -74,36 +72,34 @@ function MatrixGrid({
// Event Handlers
////////////////////////////////////////////////////////////////

const handleCellEdited = (cell: Item, value: EditableGridCell) => {
const updatedValue = value.data;

if (typeof updatedValue !== "number" || isNaN(updatedValue)) {
const handleCellEdited = (coordinates: Item, value: EditableGridCell) => {
if (value.kind !== GridCellKind.Number) {
// Invalid numeric value
return;
}

const dataCell = gridToData(cell);
const dataCoordinates = gridToData(coordinates);

if (dataCell && onCellEdit) {
onCellEdit(dataCell, updatedValue);
if (dataCoordinates && onCellEdit) {
onCellEdit({ coordinates: dataCoordinates, value });
}
};

const handleCellsEdited = (newValues: readonly EditListItem[]) => {
const updates = newValues
.map((edit) => {
const dataCell = gridToData(edit.location);
return dataCell
? {
coordinates: dataCell,
value: edit.value.data as number,
}
: null;
.map((edit): GridUpdate | null => {
const dataCoordinates = gridToData(edit.location);

if (edit.value.kind !== GridCellKind.Number || !dataCoordinates) {
return null;
}

return {
coordinates: dataCoordinates,
value: edit.value,
};
})
.filter(
(update): update is { coordinates: Item; value: number } =>
update !== null,
);
.filter((update): update is GridUpdate => update !== null);

if (updates.length === 0) {
// No valid updates
Expand Down
66 changes: 51 additions & 15 deletions webapp/src/components/common/MatrixGrid/types.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,68 @@
import {
BaseGridColumn,
FillPatternEventArgs,
EditableGridCell,
Item,
} from "@glideapps/glide-data-grid";
import { ColumnDataType } from "./utils";

export interface MatrixData {
data: number[][];
columns: number[];
index: number[];
}
////////////////////////////////////////////////////////////////
// Enums
////////////////////////////////////////////////////////////////

export type ColumnType = (typeof ColumnDataType)[keyof typeof ColumnDataType];
export const ColumnTypes = {
DateTime: "datetime",
Number: "number",
Text: "text",
Aggregate: "aggregate",
} as const;

export const Operations = {
ADD: "+",
SUB: "-",
MUL: "*",
DIV: "/",
ABS: "ABS",
EQ: "=",
} as const;

////////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////////

// Derived types
export type ColumnType = (typeof ColumnTypes)[keyof typeof ColumnTypes];
export type Operation = (typeof Operations)[keyof typeof Operations];

export interface EnhancedGridColumn extends BaseGridColumn {
id: string;
width?: number;
type: ColumnType;
editable: boolean;
}
// Represents data coming from the API
export interface MatrixDataDTO {
data: number[][];
columns: number[];
index: number[];
}

export type Coordinates = [number, number];

export type CellFillPattern = Omit<FillPatternEventArgs, "preventDefault">;
// Shape of updates provided by Glide Data Grid
export interface GridUpdate {
coordinates: Item; // The cell being updated
value: EditableGridCell;
}

// Shape of updates to be sent to the API
export interface MatrixUpdate {
operation: Operation;
value: number;
}

// TODO see MatrixIndex type, rundundant types
export interface TimeMetadataDTO {
start_date: string;
steps: number;
first_week_size: number;
level: "hourly" | "daily" | "weekly" | "monthly" | "yearly";
// Shape of multiple updates to be sent to the API
export interface MatrixUpdateDTO {
coordinates: number[][]; // Array of [col, row] pairs
operation: MatrixUpdate;
}

export type DateIncrementStrategy = (
Expand Down
21 changes: 10 additions & 11 deletions webapp/src/components/common/MatrixGrid/useColumnMapping.test.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import { renderHook } from "@testing-library/react";
import { describe, test, expect } from "vitest";
import { useColumnMapping } from "./useColumnMapping";
import { EnhancedGridColumn } from "./types";
import { ColumnDataType } from "./utils";
import { EnhancedGridColumn, ColumnTypes } from "./types";

describe("useColumnMapping", () => {
const testColumns: EnhancedGridColumn[] = [
{
id: "text",
title: "Text",
type: ColumnDataType.Text,
type: ColumnTypes.Text,
width: 100,
editable: false,
},
{
id: "date",
title: "Date",
type: ColumnDataType.DateTime,
type: ColumnTypes.DateTime,
width: 100,
editable: false,
},
{
id: "num1",
title: "Number 1",
type: ColumnDataType.Number,
type: ColumnTypes.Number,
width: 100,
editable: true,
},
{
id: "num2",
title: "Number 2",
type: ColumnDataType.Number,
type: ColumnTypes.Number,
width: 100,
editable: true,
},
{
id: "agg",
title: "Aggregate",
type: ColumnDataType.Aggregate,
type: ColumnTypes.Aggregate,
width: 100,
editable: false,
},
Expand Down Expand Up @@ -77,14 +76,14 @@ describe("useColumnMapping", () => {
{
id: "text",
title: "Text",
type: ColumnDataType.Text,
type: ColumnTypes.Text,
width: 100,
editable: false,
},
{
id: "date",
title: "Date",
type: ColumnDataType.DateTime,
type: ColumnTypes.DateTime,
width: 100,
editable: false,
},
Expand All @@ -100,14 +99,14 @@ describe("useColumnMapping", () => {
{
id: "num1",
title: "Number 1",
type: ColumnDataType.Number,
type: ColumnTypes.Number,
width: 100,
editable: true,
},
{
id: "num2",
title: "Number 2",
type: ColumnDataType.Number,
type: ColumnTypes.Number,
width: 100,
editable: true,
},
Expand Down
5 changes: 2 additions & 3 deletions webapp/src/components/common/MatrixGrid/useColumnMapping.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useMemo } from "react";
import { Item } from "@glideapps/glide-data-grid";
import { EnhancedGridColumn } from "./types";
import { ColumnDataType } from "./utils";
import { EnhancedGridColumn, ColumnTypes } from "./types";

/**
* A custom hook that provides coordinate mapping functions for a grid with mixed column types.
Expand Down Expand Up @@ -35,7 +34,7 @@ import { ColumnDataType } from "./utils";
export function useColumnMapping(columns: EnhancedGridColumn[]) {
return useMemo(() => {
const dataColumnIndices = columns.reduce((acc, col, index) => {
if (col.type === ColumnDataType.Number) {
if (col.type === ColumnTypes.Number) {
acc.push(index);
}
return acc;
Expand Down
Loading

0 comments on commit d810cbe

Please sign in to comment.