Skip to content

Commit

Permalink
feat(common-ui,clusters-ui): implement optimistic row creation
Browse files Browse the repository at this point in the history
* use new endpoint to include matrices in duplication
  • Loading branch information
skamril committed Mar 25, 2024
1 parent fd258ec commit 3b8ba25
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
RenewableGroup,
createRenewableCluster,
deleteRenewableClusters,
duplicateRenewableCluster,
getRenewableClusters,
} from "./utils";
import useAppSelector from "../../../../../../../redux/hooks/useAppSelector";
Expand Down Expand Up @@ -113,6 +114,20 @@ function Renewables() {
return addCapacity(cluster);
};

const handleDuplicate = async (
row: RenewableClusterWithCapacity,
newName: string,
) => {
const cluster = await duplicateRenewableCluster(
study.id,
areaId,
row.id,
newName,
);

return { ...row, ...cluster };
};

const handleDelete = (rows: RenewableClusterWithCapacity[]) => {
const ids = rows.map((row) => row.id);
return deleteRenewableClusters(study.id, areaId, ids);
Expand All @@ -133,6 +148,7 @@ function Renewables() {
columns={columns}
groups={[...RENEWABLE_GROUPS]}
onCreate={handleCreate}
onDuplicate={handleDuplicate}
onDelete={handleDelete}
onNameClick={handleNameClick}
deleteConfirmationMessage={(count) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ const getClusterUrl = (
async function makeRequest<T>(
method: "get" | "post" | "patch" | "delete",
url: string,
data?: Partial<RenewableCluster> | { data: Array<Cluster["id"]> },
data?: Partial<RenewableCluster> | { data: Array<Cluster["id"]> } | null,
params?: Record<string, string>,
): Promise<T> {
const res = await client[method]<T>(url, data);
const res = await client[method]<T>(url, data, params && { params });
return res.data;
}

Expand Down Expand Up @@ -129,6 +130,20 @@ export function createRenewableCluster(
);
}

export function duplicateRenewableCluster(
studyId: StudyMetadata["id"],
areaId: Area["name"],
clusterIdSource: RenewableCluster["id"],
newName: RenewableCluster["name"],
) {
return makeRequest<RenewableCluster>(
"post",
`/v1/studies/${studyId}/areas/${areaId}/renewables/${clusterIdSource}`,
null,
{ newName },
);
}

export function deleteRenewableClusters(
studyId: StudyMetadata["id"],
areaId: Area["name"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
createStorage,
STORAGE_GROUPS,
StorageGroup,
duplicateStorage,
} from "./utils";
import usePromiseWithSnackbarError from "../../../../../../../hooks/usePromiseWithSnackbarError";
import type { TRow } from "../../../../../../common/GroupedDataTable/types";
Expand Down Expand Up @@ -161,6 +162,10 @@ function Storages() {
return createStorage(study.id, areaId, values);
};

const handleDuplicate = (row: Storage, newName: string) => {
return duplicateStorage(study.id, areaId, row.id, newName);
};

const handleDelete = (rows: Storage[]) => {
const ids = rows.map((row) => row.id);
return deleteStorages(study.id, areaId, ids);
Expand All @@ -181,6 +186,7 @@ function Storages() {
columns={columns}
groups={[...STORAGE_GROUPS]}
onCreate={handleCreate}
onDuplicate={handleDuplicate}
onDelete={handleDelete}
onNameClick={handleNameClick}
deleteConfirmationMessage={(count) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ const getStorageUrl = (
async function makeRequest<T>(
method: "get" | "post" | "patch" | "delete",
url: string,
data?: Partial<Storage> | { data: Array<Storage["id"]> },
data?: Partial<Storage> | { data: Array<Storage["id"]> } | null,
params?: Record<string, string>,
): Promise<T> {
const res = await client[method]<T>(url, data);
const res = await client[method]<T>(url, data, params && { params });
return res.data;
}

Expand Down Expand Up @@ -96,6 +97,20 @@ export function createStorage(
return makeRequest<Storage>("post", getStoragesUrl(studyId, areaId), data);
}

export function duplicateStorage(
studyId: StudyMetadata["id"],
areaId: Area["name"],
clusterIdSource: Storage["id"],
newName: Storage["name"],
) {
return makeRequest<Storage>(
"post",
`/v1/studies/${studyId}/areas/${areaId}/storages/${clusterIdSource}`,
null,
{ newName },
);
}

export function deleteStorages(
studyId: StudyMetadata["id"],
areaId: Area["name"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
THERMAL_GROUPS,
ThermalCluster,
ThermalGroup,
duplicateThermalCluster,
} from "./utils";
import useAppSelector from "../../../../../../../redux/hooks/useAppSelector";
import { getCurrentAreaId } from "../../../../../../../redux/selectors";
Expand Down Expand Up @@ -127,6 +128,20 @@ function Thermal() {
return addCapacity(cluster);
};

const handleDuplicate = async (
row: ThermalClusterWithCapacity,
newName: string,
) => {
const cluster = await duplicateThermalCluster(
study.id,
areaId,
row.id,
newName,
);

return { ...row, ...cluster };
};

const handleDelete = (rows: ThermalClusterWithCapacity[]) => {
const ids = rows.map((row) => row.id);
return deleteThermalClusters(study.id, areaId, ids);
Expand All @@ -147,6 +162,7 @@ function Thermal() {
columns={columns}
groups={[...THERMAL_GROUPS]}
onCreate={handleCreate}
onDuplicate={handleDuplicate}
onDelete={handleDelete}
onNameClick={handleNameClick}
deleteConfirmationMessage={(count) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ const getClusterUrl = (
async function makeRequest<T>(
method: "get" | "post" | "patch" | "delete",
url: string,
data?: Partial<ThermalCluster> | { data: Array<Cluster["id"]> },
data?: Partial<ThermalCluster> | { data: Array<Cluster["id"]> } | null,
params?: Record<string, string>,
): Promise<T> {
const res = await client[method]<T>(url, data);
const res = await client[method]<T>(url, data, params && { params });
return res.data;
}

Expand Down Expand Up @@ -157,6 +158,20 @@ export function createThermalCluster(
);
}

export function duplicateThermalCluster(
studyId: StudyMetadata["id"],
areaId: Area["name"],
clusterIdSource: ThermalCluster["id"],
newName: ThermalCluster["name"],
) {
return makeRequest<ThermalCluster>(
"post",
`/v1/studies/${studyId}/areas/${areaId}/thermals/${clusterIdSource}`,
null,
{ newName },
);
}

export function deleteThermalClusters(
studyId: StudyMetadata["id"],
areaId: Area["name"],
Expand Down
52 changes: 31 additions & 21 deletions webapp/src/components/common/GroupedDataTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface GroupedDataTableProps<
columns: Array<MRT_ColumnDef<TData, any>>;
groups: TGroups;
onCreate?: (values: TRow<TGroups[number]>) => Promise<TData>;
onDuplicate?: (row: TData, newName: string) => Promise<TData>;
onDelete?: (rows: TData[]) => PromiseAny | void;
onNameClick?: (row: MRT_Row<TData>) => void;
isLoading?: boolean;
Expand All @@ -60,6 +61,7 @@ function GroupedDataTable<
columns,
groups,
onCreate,
onDuplicate,
onDelete,
onNameClick,
isLoading,
Expand Down Expand Up @@ -220,7 +222,7 @@ function GroupedDataTable<
{t("button.add")}
</Button>
)}
{onCreate && (
{onDuplicate && (
<Button
startIcon={<ContentCopyIcon />}
variant="outlined"
Expand Down Expand Up @@ -316,6 +318,34 @@ function GroupedDataTable<
createOps.decrement();
};

const handleDuplicate = async (newName: string) => {
closeDialog();

if (!onDuplicate || !selectedRow) {
return;
}

setRowSelection({});

const duplicatedRow = {
...selectedRow,
name: newName,
};

createOps.increment();
addPendingRow(duplicatedRow);

try {
const newRow = await onDuplicate(selectedRow, newName);
setTableData((prev) => [...prev, newRow]);
} catch (error) {
enqueueErrorSnackbar(t("global.error.createFailed"), toError(error));
}

removePendingRow(duplicatedRow);
createOps.decrement();
};

const handleDelete = async () => {
closeDialog();

Expand Down Expand Up @@ -343,26 +373,6 @@ function GroupedDataTable<
deleteOps.decrement();
};

const handleDuplicate = async (name: string) => {
if (!selectedRow) {
return;
}

const id = generateUniqueValue(name, tableData);

const duplicatedRow = {
...selectedRow,
id,
name,
};

if (onCreate) {
const newRow = await onCreate(duplicatedRow);
setTableData((prevTableData) => [...prevTableData, newRow]);
setRowSelection({});
}
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 3b8ba25

Please sign in to comment.