Skip to content

Commit

Permalink
Fix editing and lock check (#1482)
Browse files Browse the repository at this point in the history
  • Loading branch information
MiraGeowerkstatt authored Sep 3, 2024
2 parents 941d131 + a432ca9 commit 42c29e6
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 179 deletions.
24 changes: 19 additions & 5 deletions src/client/cypress/e2e/editor/dataCards.cy.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import { createBorehole, handlePrompt, loginAsAdmin, startBoreholeEditing } from "../helpers/testHelpers";
import {
createBorehole,
handlePrompt,
loginAsAdmin,
startBoreholeEditing,
stopBoreholeEditing,
} from "../helpers/testHelpers";
import { evaluateDisplayValue, evaluateTextarea, setInput, setSelect } from "../helpers/formHelpers";
import { addItem, saveForm, startEditing, stopEditing } from "../helpers/buttonHelpers";
import { addItem, cancelEditing, saveForm, startEditing } from "../helpers/buttonHelpers";

describe("Tests for the data cards in the editor.", () => {
it("resets datacards when stop editing", () => {
it("resets datacards when stop editing or cancel", () => {
createBorehole({ "extended.original_name": "INTEADAL" }).as("borehole_id");
cy.get("@borehole_id").then(id => {
loginAsAdmin(`/${id}/hydrogeology/wateringress`);
});

startBoreholeEditing();
cy.wait(500);

//Add card and cancel editing in datacard
addItem("addwateringress");
cy.get('[data-cy="waterIngress-card.0.edit"]').should("exist");
cancelEditing();
cy.get('[data-cy="waterIngress-card.0.edit"]').should("not.exist");

//Add card and stop editing borehole
addItem("addwateringress");
cy.get('[data-cy="waterIngress-card.0.edit"]').should("exist");
stopEditing();
stopBoreholeEditing();
cy.get('[data-cy="waterIngress-card.0.edit"]').should("not.exist");

startBoreholeEditing();
Expand All @@ -27,7 +41,7 @@ describe("Tests for the data cards in the editor.", () => {
cy.wait("@wateringress_GET");
startEditing();
setInput("comment", "Lorem.");
stopEditing();
stopBoreholeEditing();
evaluateDisplayValue("comment", "-");
});

Expand Down
17 changes: 17 additions & 0 deletions src/client/src/AppTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,22 @@ export const theme = createTheme({
},
},
},
MuiTableCell: {
styleOverrides: {
head: {
fontSize: "13px",
fontWeight: 700,
padding: "3px",
flex: 1,
verticalAlign: "top",
},
body: {
paddingRight: "3px",
paddingLeft: "3px",
flex: 1,
fontSize: "13px",
},
},
},
},
});
7 changes: 0 additions & 7 deletions src/client/src/components/form/formResultTableDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,11 @@ export const FormResultTableDisplay: React.FC<FormResultTableDisplayProps> = ({
const { t } = useTranslation();

const tableCellStyles: React.CSSProperties = {
paddingRight: "3px",
paddingLeft: "3px",
flex: 1,
width: "20%",
maxWidth: "20%",
fontSize: "13px",
};

const tableHeaderStyles: React.CSSProperties = {
fontWeight: 900,
padding: "3px",
flex: 1,
width: "20%",
maxWidth: "20%",
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import PropTypes from "prop-types";
import { connect } from "react-redux";
import { withTranslation } from "react-i18next";
import _ from "lodash";

import { loadDomains } from "../../../../api-lib/index.js";

import { loadDomains } from "../../../../api-lib";
import { Form, Header } from "semantic-ui-react";

class DomainDropdown extends React.Component {
Expand Down Expand Up @@ -207,7 +205,7 @@ class DomainDropdown extends React.Component {
);
if (readOnly) {
let selectedOption = options.find(option => option.value === selected);
return <Form.Input fluid readOnly value={selectedOption.text} />;
return <Form.Input fluid readOnly value={selectedOption?.text || ""} />;
}
return (
<Form.Select
Expand Down
37 changes: 9 additions & 28 deletions src/client/src/pages/detail/detailHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { useContext, useEffect, useState } from "react";
import { useContext } from "react";
import { Chip, IconButton, Stack, Typography } from "@mui/material";
import { theme } from "../../AppTheme.ts";
import ArrowLeftIcon from "../../assets/icons/arrow_left.svg?react";
import CheckmarkIcon from "../../assets/icons/checkmark.svg?react";
import TrashIcon from "../../assets/icons/trash.svg?react";
import { useHistory, useLocation } from "react-router-dom";
import { useHistory } from "react-router-dom";
import { DeleteButton, EditButton, EndEditButton } from "../../components/buttons/buttons.tsx";
import { useDispatch, useSelector } from "react-redux";
import { Borehole, ReduxRootState } from "../../api-lib/ReduxStateInterfaces.ts";
import { deleteBorehole, lockBorehole, unlockBorehole } from "../../api-lib";
import { useTranslation } from "react-i18next";
import { PromptContext } from "../../components/prompt/promptContext.tsx";

const DetailHeader = () => {
const [editingEnabled, setEditingEnabled] = useState(false);
const [editableByCurrentUser, setEditableByCurrentUser] = useState(false);
interface DetailHeaderProps {
editingEnabled: boolean;
setEditingEnabled: (editingEnabled: boolean) => void;
editableByCurrentUser: boolean;
}

const DetailHeader = ({ editingEnabled, setEditingEnabled, editableByCurrentUser }: DetailHeaderProps) => {
const borehole: Borehole = useSelector((state: ReduxRootState) => state.core_borehole);
const user = useSelector((state: ReduxRootState) => state.core_user);
const history = useHistory();
const location = useLocation();
const dispatch = useDispatch();
const { t } = useTranslation();
const { showPrompt } = useContext(PromptContext);
Expand All @@ -45,28 +48,6 @@ const DetailHeader = () => {
history.push("/");
};

useEffect(() => {
setEditingEnabled(borehole.data.lock !== null);
}, [borehole.data.lock]);

useEffect(() => {
if (borehole.data.lock !== null && borehole.data.lock.id !== user.data.id) {
setEditableByCurrentUser(false);
return;
}

const matchingWorkgroup =
user.data.workgroups.find(workgroup => workgroup.id === borehole.data.workgroup?.id) ?? false;
const userRoleMatches =
matchingWorkgroup &&
Object.prototype.hasOwnProperty.call(matchingWorkgroup, "roles") &&
matchingWorkgroup.roles.includes(borehole.data.role);
const isStatusPage = location.pathname.endsWith("/status");
const isBoreholeInEditWorkflow = borehole?.data.workflow?.role === "EDIT";

setEditableByCurrentUser(userRoleMatches && (isStatusPage || isBoreholeInEditWorkflow));
}, [editingEnabled, user, borehole, location]);

if (borehole.isFetching) {
return;
}
Expand Down
51 changes: 48 additions & 3 deletions src/client/src/pages/detail/detailPage.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,64 @@
import { LayoutBox, MainContentBox, SidebarBox } from "../../components/styledComponents.ts";
import { FC } from "react";
import { FC, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useLocation } from "react-router-dom";
import { Borehole, ReduxRootState } from "../../api-lib/ReduxStateInterfaces.ts";
import DetailSideNav from "./detailSideNav";
import DetailPageContent from "./detailPageContent";
import DetailHeader from "./detailHeader.tsx";

interface DetailPageContentProps {
editingEnabled: boolean;
editableByCurrentUser: boolean;
}

export const DetailPage: FC = () => {
const [editingEnabled, setEditingEnabled] = useState(false);
const [editableByCurrentUser, setEditableByCurrentUser] = useState(false);
const borehole: Borehole = useSelector((state: ReduxRootState) => state.core_borehole);
const user = useSelector((state: ReduxRootState) => state.core_user);
const location = useLocation();

useEffect(() => {
setEditingEnabled(borehole.data.lock !== null);
}, [borehole.data.lock]);

useEffect(() => {
if (borehole.data.lock !== null && borehole.data.lock.id !== user.data.id) {
setEditableByCurrentUser(false);
return;
}

const matchingWorkgroup =
user.data.workgroups.find(workgroup => workgroup.id === borehole.data.workgroup?.id) ?? false;
const userRoleMatches =
matchingWorkgroup &&
Object.prototype.hasOwnProperty.call(matchingWorkgroup, "roles") &&
matchingWorkgroup.roles.includes(borehole.data.role);
const isStatusPage = location.pathname.endsWith("/status");
const isBoreholeInEditWorkflow = borehole?.data.workflow?.role === "EDIT";

setEditableByCurrentUser(userRoleMatches && (isStatusPage || isBoreholeInEditWorkflow));
}, [editingEnabled, user, borehole, location]);

const props: DetailPageContentProps = {
editingEnabled: editingEnabled,
editableByCurrentUser: editableByCurrentUser,
};

return (
<>
<DetailHeader />
<DetailHeader
editingEnabled={editingEnabled}
setEditingEnabled={setEditingEnabled}
editableByCurrentUser={editableByCurrentUser}
/>
<LayoutBox>
<SidebarBox>
<DetailSideNav />
</SidebarBox>
<MainContentBox>
<DetailPageContent />
<DetailPageContent {...props} />
</MainContentBox>
</LayoutBox>
</>
Expand Down
44 changes: 22 additions & 22 deletions src/client/src/pages/detail/detailPageContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class DetailPageContent extends React.Component {
}

checkLock() {
const { t } = this.props;
const { t, editingEnabled, editableByCurrentUser } = this.props;
if (this.props.borehole.data.role !== "EDIT") {
this.context.showAlert(
t("common:errorStartEditingWrongStatus", {
Expand All @@ -115,8 +115,10 @@ class DetailPageContent extends React.Component {
);
return false;
}
if (this.props.borehole.data.lock === null || this.props.borehole.data.lock.id !== this.props.user.data.id) {
this.context.showAlert(t("common:errorStartEditing"), "error");
if (!editingEnabled) {
if (editableByCurrentUser) {
this.context.showAlert(t("errorStartEditing"), "error");
}
return false;
}
return true;
Expand All @@ -127,9 +129,7 @@ class DetailPageContent extends React.Component {
}

updateNumber(attribute, value, to = true) {
if (this.checkLock() === false) {
return;
}
if (!this.checkLock()) return;
const state = {
...this.state,
patchFetch: true,
Expand Down Expand Up @@ -232,10 +232,8 @@ class DetailPageContent extends React.Component {
}

render() {
const { t, borehole, user } = this.props;
const { t, borehole, user, editingEnabled } = this.props;
const size = null; // 'small'
const isEditable =
borehole?.data.role === "EDIT" && borehole?.data.lock !== null && borehole?.data.lock?.id === user?.data.id;
if (borehole.error !== null) {
return <div>{t(borehole.error, borehole.data)}</div>;
}
Expand Down Expand Up @@ -330,24 +328,24 @@ class DetailPageContent extends React.Component {
borehole={borehole}
updateChange={this.updateChange}
updateNumber={this.updateNumber}
isEditable={isEditable}
isEditable={editingEnabled}
/>
)}
/>
<Route
exact
path={"/:id/stratigraphy/lithology"}
render={() => <Lithology id={parseInt(id, 10)} unlocked={isEditable} />}
render={() => <Lithology id={parseInt(id, 10)} unlocked={editingEnabled} checkLock={this.checkLock} />}
/>
<Route
exact
path={"/:id/stratigraphy/chronostratigraphy"}
render={() => <ChronostratigraphyPanel id={parseInt(id, 10)} isEditable={isEditable} />}
render={() => <ChronostratigraphyPanel id={parseInt(id, 10)} isEditable={editingEnabled} />}
/>
<Route
exact
path={"/:id/stratigraphy/lithostratigraphy"}
render={() => <LithostratigraphyPanel id={parseInt(id, 10)} isEditable={isEditable} />}
render={() => <LithostratigraphyPanel id={parseInt(id, 10)} isEditable={editingEnabled} />}
/>
<Route
path={"/:id/stratigraphy"}
Expand All @@ -364,27 +362,27 @@ class DetailPageContent extends React.Component {
<Route
exact
path={"/:id/attachments"}
render={() => <EditorBoreholeFilesTable id={parseInt(id, 10)} unlocked={isEditable} />}
render={() => <EditorBoreholeFilesTable id={parseInt(id, 10)} unlocked={editingEnabled} />}
/>
<Route
exact
path={"/:id/hydrogeology/wateringress"}
render={() => <WaterIngress isEditable={isEditable} boreholeId={parseInt(id, 10)} />}
render={() => <WaterIngress isEditable={editingEnabled} boreholeId={parseInt(id, 10)} />}
/>
<Route
exact
path={"/:id/hydrogeology/groundwaterlevelmeasurement"}
render={() => <GroundwaterLevelMeasurement isEditable={isEditable} boreholeId={parseInt(id, 10)} />}
render={() => <GroundwaterLevelMeasurement isEditable={editingEnabled} boreholeId={parseInt(id, 10)} />}
/>
<Route
exact
path={"/:id/hydrogeology/fieldmeasurement"}
render={() => <FieldMeasurement isEditable={isEditable} boreholeId={parseInt(id, 10)} />}
render={() => <FieldMeasurement isEditable={editingEnabled} boreholeId={parseInt(id, 10)} />}
/>
<Route
exact
path={"/:id/hydrogeology/hydrotest"}
render={() => <Hydrotest isEditable={isEditable} boreholeId={parseInt(id, 10)} />}
render={() => <Hydrotest isEditable={editingEnabled} boreholeId={parseInt(id, 10)} />}
/>
<Route
path={"/:id/hydrogeology"}
Expand All @@ -400,9 +398,9 @@ class DetailPageContent extends React.Component {
/>
<Route
path={"/:boreholeId/completion/:completionId"}
render={() => <Completion isEditable={isEditable} />}
render={() => <Completion isEditable={editingEnabled} />}
/>
<Route path={"/:boreholeId/completion"} render={() => <Completion isEditable={isEditable} />} />
<Route path={"/:boreholeId/completion"} render={() => <Completion isEditable={editingEnabled} />} />
<Route
exact
path={"/:id/status"}
Expand All @@ -428,6 +426,8 @@ DetailPageContent.propTypes = {
t: PropTypes.func,
updateBorehole: PropTypes.func,
workflow: PropTypes.object,
editingEnabled: PropTypes.bool,
editableByCurrentUser: PropTypes.bool,
};

DetailPageContent.defaultProps = {
Expand Down Expand Up @@ -455,7 +455,7 @@ const mapDispatchToProps = dispatch => {
};
};

const ConnectedBoreholeForm = withRouter(
const ConnectedDetailPageContent = withRouter(
connect(mapStateToProps, mapDispatchToProps)(withTranslation(["common"])(DetailPageContent)),
);
export default ConnectedBoreholeForm;
export default ConnectedDetailPageContent;
Loading

0 comments on commit 42c29e6

Please sign in to comment.