Skip to content

Commit 15064d6

Browse files
Use save on ctrl s hook (#1718)
2 parents c23a533 + f114bab commit 15064d6

File tree

10 files changed

+263
-190
lines changed

10 files changed

+263
-190
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- Some filter chips were missing translations or where not displayed correctly.
3636
- Filtering striae for `not specified` returned wrong results.
3737
- Filtering by `borehole status` did not work.
38+
- When saving with ctrl+s in the borehole sections, the form content was reset.
3839

3940
## v2.1.870 - 2024-09-27
4041

src/client/cypress/e2e/detailPage/sections.cy.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addItem, deleteItem, saveForm, startEditing } from "../helpers/buttonHelpers";
1+
import { addItem, deleteItem, saveForm, saveWithSaveBar, startEditing } from "../helpers/buttonHelpers";
22
import { evaluateDisplayValue, evaluateInput, setInput, setSelect } from "../helpers/formHelpers";
33
import { createBorehole, handlePrompt, loginAsAdmin, startBoreholeEditing } from "../helpers/testHelpers";
44

@@ -102,6 +102,52 @@ describe("Section crud tests", () => {
102102
cy.get('[data-cy="section-card.0"]').should("not.exist");
103103
});
104104

105+
it("saves section with ctrl s without resetting content", () => {
106+
cy.wait(30);
107+
// add section and save with ctrl s
108+
addItem("addSection");
109+
cy.wait("@codelist_GET");
110+
setInput("name", "A");
111+
setInput("sectionElements.0.fromDepth", "0");
112+
setInput("sectionElements.0.toDepth", "1");
113+
setSelect("sectionElements.0.drillingMudTypeId", 5);
114+
cy.get("body").type("{ctrl}s");
115+
evaluateDisplayValue("0.drilling_mud_type", "water-based dispersed");
116+
117+
// switch tab to borehole general tab and edit depth
118+
cy.get('[data-cy="general-tab"]').click();
119+
setInput("totalDepth", 5);
120+
evaluateInput("totalDepth", "5");
121+
122+
// click on sections without saving
123+
cy.get('[data-cy="sections-tab"]').click();
124+
const messageUnsavedChanges = "There are unsaved changes. Do you want to discard all changes?";
125+
handlePrompt(messageUnsavedChanges, "cancel");
126+
evaluateInput("totalDepth", "5");
127+
cy.get('[data-cy="sections-tab"]').click();
128+
handlePrompt(messageUnsavedChanges, "discard changes");
129+
130+
// sections tab should be unchanged when retuning from borehole tab
131+
evaluateDisplayValue("0.drilling_mud_type", "water-based dispersed");
132+
133+
// switch tab to borehole general tab and edit depth with saving
134+
cy.get('[data-cy="general-tab"]').click();
135+
evaluateInput("totalDepth", "");
136+
setInput("totalDepth", 7);
137+
evaluateInput("totalDepth", "7");
138+
saveWithSaveBar();
139+
140+
// edit sections tab and save again
141+
cy.get('[data-cy="sections-tab"]').click();
142+
startEditing();
143+
setSelect("sectionElements.0.drillingMudTypeId", 4);
144+
cy.get("body").type("{ctrl}s");
145+
146+
// borehole tab should still display saved depth value
147+
cy.get('[data-cy="general-tab"]').click();
148+
evaluateInput("totalDepth", "7");
149+
});
150+
105151
it("changes drillingMudSubtype select options based on drillingMudType", () => {
106152
cy.wait(30);
107153
addItem("addSection");

src/client/src/components/dataCard/dataInputCard.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useContext, useEffect } from "react";
22
import { FormProvider, useForm } from "react-hook-form";
33
import { useTranslation } from "react-i18next";
44
import { DevTool } from "../../../hookformDevtools";
5+
import { useSaveOnCtrlS } from "../../pages/detail/useSaveOnCtrlS";
56
import { CancelButton, SaveButton } from "../buttons/buttons.tsx";
67
import { FormContainer } from "../form/form";
78
import { PromptContext } from "../prompt/promptContext.tsx";
@@ -73,6 +74,9 @@ export const DataInputCard = props => {
7374
}
7475
};
7576

77+
// Save with ctrl+s
78+
useSaveOnCtrlS(formMethods.handleSubmit(submitForm));
79+
7680
return (
7781
<>
7882
<FormProvider {...formMethods}>

src/client/src/pages/detail/detailPageContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ export const DetailPageContent = ({
109109
render={() => (
110110
<BoreholePanel
111111
ref={boreholePanelRef}
112-
onSubmit={onBoreholeFormSubmit}
113112
boreholeId={id}
114113
borehole={borehole}
115114
editingEnabled={editingEnabled}
115+
onSubmit={onBoreholeFormSubmit}
116116
/>
117117
)}
118118
/>
Lines changed: 151 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { useCallback, useEffect, useState } from "react";
1+
import { forwardRef, useCallback, useEffect, useState } from "react";
2+
import { FormProvider, useForm } from "react-hook-form";
3+
import { DevTool } from "../../../../../hookformDevtools.ts";
24
import { getBoreholeGeometryDepthTVD } from "../../../../api/fetchApiV2.js";
35
import {
46
FormBooleanSelect,
@@ -9,20 +11,45 @@ import {
911
} from "../../../../components/form/form.ts";
1012
import { parseFloatWithThousandsSeparator } from "../../../../components/legacyComponents/formUtils.ts";
1113
import { FormSegmentBox } from "../../../../components/styledComponents.ts";
12-
import { BoreholeDetailProps } from "./boreholePanelInterfaces.ts";
14+
import { UseFormWithSaveBar } from "../useFormWithSaveBar.ts";
15+
import { BoreholeDetailProps, BoreholeFormInputs } from "./boreholePanelInterfaces.ts";
1316

14-
export const BoreholeForm = ({ formMethods, borehole, editingEnabled }: BoreholeDetailProps) => {
17+
export const BoreholeForm = forwardRef(({ borehole, editingEnabled, onSubmit }: BoreholeDetailProps, ref) => {
1518
const [totalDepthTVD, setTotalDepthTVD] = useState<number | null>(null);
1619
const [topBedrockFreshTVD, setTopBedrockFreshTVD] = useState<number | null>(null);
1720
const [topBedrockWeatheredTVD, setTopBedrockWeatheredTVD] = useState<number | null>(null);
1821
const roundTvdValue = (value: number | null) => {
1922
return value ? Math.round(value * 100) / 100 : null;
2023
};
2124

25+
const formMethods = useForm<BoreholeFormInputs>({
26+
mode: "onChange",
27+
defaultValues: {
28+
typeId: borehole.typeId,
29+
purposeId: borehole.purposeId,
30+
statusId: borehole.statusId,
31+
totalDepth: borehole.totalDepth,
32+
qtDepthId: borehole.qtDepthId,
33+
topBedrockFreshMd: borehole.topBedrockFreshMd,
34+
topBedrockWeatheredMd: borehole.topBedrockWeatheredMd,
35+
lithologyTopBedrockId: borehole.lithologyTopBedrockId,
36+
lithostratigraphyId: borehole.lithostratigraphyId,
37+
chronostratigraphyId: borehole.chronostratigraphyId,
38+
hasGroundwater: borehole.hasGroundwater === true ? 1 : borehole.hasGroundwater === false ? 0 : 2,
39+
remarks: borehole.remarks,
40+
},
41+
});
42+
2243
const totalDepth = formMethods.watch("totalDepth");
2344
const topBedrockFreshMd = formMethods.watch("topBedrockFreshMd");
2445
const topBedrockWeatheredMd = formMethods.watch("topBedrockWeatheredMd");
2546

47+
UseFormWithSaveBar({
48+
formMethods,
49+
onSubmit,
50+
ref,
51+
});
52+
2653
const fetchDepthTVD = useCallback(
2754
async (fieldValue: number | null) => {
2855
if (!fieldValue) return null;
@@ -63,118 +90,125 @@ export const BoreholeForm = ({ formMethods, borehole, editingEnabled }: Borehole
6390
}, [fetchDepthTVD, topBedrockWeatheredMd]);
6491

6592
return (
66-
<FormSegmentBox>
67-
<FormContainer>
68-
<FormContainer direction="row">
69-
<FormDomainSelect
70-
fieldName={"typeId"}
71-
label={"borehole_type"}
72-
schemaName={"borehole_type"}
73-
readonly={!editingEnabled}
74-
selected={borehole.typeId}
75-
/>
76-
<FormDomainSelect
77-
fieldName={"purposeId"}
78-
label={"purpose"}
79-
schemaName={"extended.purpose"}
80-
readonly={!editingEnabled}
81-
selected={borehole.purposeId}
82-
/>
83-
<FormDomainSelect
84-
fieldName={"statusId"}
85-
label={"boreholestatus"}
86-
schemaName={"extended.status"}
87-
readonly={!editingEnabled}
88-
selected={borehole.statusId}
89-
/>
90-
</FormContainer>
91-
<FormContainer>
92-
<FormContainer direction="row">
93-
<FormInput
94-
fieldName={"totalDepth"}
95-
label={"totaldepth"}
96-
value={borehole?.totalDepth || ""}
97-
withThousandSeparator={true}
98-
readonly={!editingEnabled}
99-
/>
100-
<FormDomainSelect
101-
fieldName={"qtDepthId"}
102-
label={"qt_depth"}
103-
schemaName={"depth_precision"}
104-
readonly={!editingEnabled}
105-
selected={borehole.qtDepthId}
106-
/>
107-
<FormInputDisplayOnly label={"total_depth_tvd"} value={totalDepthTVD} withThousandSeparator={true} />
108-
</FormContainer>
109-
</FormContainer>
110-
<FormContainer direction="row">
111-
<FormInput
112-
fieldName={"topBedrockFreshMd"}
113-
label={"top_bedrock_fresh_md"}
114-
value={borehole?.topBedrockFreshMd || ""}
115-
withThousandSeparator={true}
116-
readonly={!editingEnabled}
117-
/>
118-
<FormInputDisplayOnly
119-
label={"top_bedrock_fresh_tvd"}
120-
value={topBedrockFreshTVD}
121-
withThousandSeparator={true}
122-
/>
123-
</FormContainer>
124-
<FormContainer direction="row">
125-
<FormInput
126-
fieldName={"topBedrockWeatheredMd"}
127-
label={"top_bedrock_weathered_md"}
128-
value={borehole?.topBedrockWeatheredMd || ""}
129-
withThousandSeparator={true}
130-
readonly={!editingEnabled}
131-
/>
132-
<FormInputDisplayOnly
133-
label={"top_bedrock_weathered_tvd"}
134-
value={topBedrockWeatheredTVD}
135-
withThousandSeparator={true}
136-
/>
137-
</FormContainer>
138-
<FormContainer direction="row">
139-
<FormDomainSelect
140-
fieldName={"lithologyTopBedrockId"}
141-
label={"lithology_top_bedrock"}
142-
schemaName={"custom.lithology_top_bedrock"}
143-
readonly={!editingEnabled}
144-
selected={borehole.lithologyTopBedrockId}
145-
/>
146-
<FormDomainSelect
147-
fieldName={"lithostratigraphyId"}
148-
label={"lithostratigraphy_top_bedrock"}
149-
schemaName={"custom.lithostratigraphy_top_bedrock"}
150-
readonly={!editingEnabled}
151-
selected={borehole.lithostratigraphyId}
152-
/>
153-
</FormContainer>
154-
<FormContainer direction="row">
155-
<FormDomainSelect
156-
fieldName={"chronostratigraphyId"}
157-
label={"chronostratigraphy_top_bedrock"}
158-
schemaName={"custom.chronostratigraphy_top_bedrock"}
159-
readonly={!editingEnabled}
160-
selected={borehole.chronostratigraphyId}
161-
/>
162-
<FormBooleanSelect
163-
canReset={false}
164-
readonly={!editingEnabled}
165-
fieldName={"hasGroundwater"}
166-
label="groundwater"
167-
selected={borehole.hasGroundwater}
168-
/>
169-
</FormContainer>
170-
<FormInput
171-
fieldName={"remarks"}
172-
multiline={true}
173-
label={"remarks"}
174-
value={borehole?.remarks || ""}
175-
readonly={!editingEnabled}
176-
/>
177-
</FormContainer>
178-
</FormSegmentBox>
93+
<>
94+
<DevTool control={formMethods.control} placement="top-right" />
95+
<FormProvider {...formMethods}>
96+
<form onSubmit={formMethods.handleSubmit(onSubmit)}>
97+
<FormSegmentBox>
98+
<FormContainer>
99+
<FormContainer direction="row">
100+
<FormDomainSelect
101+
fieldName={"typeId"}
102+
label={"borehole_type"}
103+
schemaName={"borehole_type"}
104+
readonly={!editingEnabled}
105+
selected={borehole.typeId}
106+
/>
107+
<FormDomainSelect
108+
fieldName={"purposeId"}
109+
label={"purpose"}
110+
schemaName={"extended.purpose"}
111+
readonly={!editingEnabled}
112+
selected={borehole.purposeId}
113+
/>
114+
<FormDomainSelect
115+
fieldName={"statusId"}
116+
label={"boreholestatus"}
117+
schemaName={"extended.status"}
118+
readonly={!editingEnabled}
119+
selected={borehole.statusId}
120+
/>
121+
</FormContainer>
122+
<FormContainer>
123+
<FormContainer direction="row">
124+
<FormInput
125+
fieldName={"totalDepth"}
126+
label={"totaldepth"}
127+
value={borehole?.totalDepth || ""}
128+
withThousandSeparator={true}
129+
readonly={!editingEnabled}
130+
/>
131+
<FormDomainSelect
132+
fieldName={"qtDepthId"}
133+
label={"qt_depth"}
134+
schemaName={"depth_precision"}
135+
readonly={!editingEnabled}
136+
selected={borehole.qtDepthId}
137+
/>
138+
<FormInputDisplayOnly label={"total_depth_tvd"} value={totalDepthTVD} withThousandSeparator={true} />
139+
</FormContainer>
140+
</FormContainer>
141+
<FormContainer direction="row">
142+
<FormInput
143+
fieldName={"topBedrockFreshMd"}
144+
label={"top_bedrock_fresh_md"}
145+
value={borehole?.topBedrockFreshMd || ""}
146+
withThousandSeparator={true}
147+
readonly={!editingEnabled}
148+
/>
149+
<FormInputDisplayOnly
150+
label={"top_bedrock_fresh_tvd"}
151+
value={topBedrockFreshTVD}
152+
withThousandSeparator={true}
153+
/>
154+
</FormContainer>
155+
<FormContainer direction="row">
156+
<FormInput
157+
fieldName={"topBedrockWeatheredMd"}
158+
label={"top_bedrock_weathered_md"}
159+
value={borehole?.topBedrockWeatheredMd || ""}
160+
withThousandSeparator={true}
161+
readonly={!editingEnabled}
162+
/>
163+
<FormInputDisplayOnly
164+
label={"top_bedrock_weathered_tvd"}
165+
value={topBedrockWeatheredTVD}
166+
withThousandSeparator={true}
167+
/>
168+
</FormContainer>
169+
<FormContainer direction="row">
170+
<FormDomainSelect
171+
fieldName={"lithologyTopBedrockId"}
172+
label={"lithology_top_bedrock"}
173+
schemaName={"custom.lithology_top_bedrock"}
174+
readonly={!editingEnabled}
175+
selected={borehole.lithologyTopBedrockId}
176+
/>
177+
<FormDomainSelect
178+
fieldName={"lithostratigraphyId"}
179+
label={"lithostratigraphy_top_bedrock"}
180+
schemaName={"custom.lithostratigraphy_top_bedrock"}
181+
readonly={!editingEnabled}
182+
selected={borehole.lithostratigraphyId}
183+
/>
184+
</FormContainer>
185+
<FormContainer direction="row">
186+
<FormDomainSelect
187+
fieldName={"chronostratigraphyId"}
188+
label={"chronostratigraphy_top_bedrock"}
189+
schemaName={"custom.chronostratigraphy_top_bedrock"}
190+
readonly={!editingEnabled}
191+
selected={borehole.chronostratigraphyId}
192+
/>
193+
<FormBooleanSelect
194+
canReset={false}
195+
readonly={!editingEnabled}
196+
fieldName={"hasGroundwater"}
197+
label="groundwater"
198+
selected={borehole.hasGroundwater}
199+
/>
200+
</FormContainer>
201+
<FormInput
202+
fieldName={"remarks"}
203+
multiline={true}
204+
label={"remarks"}
205+
value={borehole?.remarks || ""}
206+
readonly={!editingEnabled}
207+
/>
208+
</FormContainer>
209+
</FormSegmentBox>
210+
</form>
211+
</FormProvider>
212+
</>
179213
);
180-
};
214+
});

0 commit comments

Comments
 (0)