Skip to content

Commit

Permalink
Merge pull request #31 from jembi/fix-edit-and-delete
Browse files Browse the repository at this point in the history
Fix edit and delete for expressions
  • Loading branch information
drizzentic authored Jul 29, 2024
2 parents 0367b1e + 1289a44 commit 2f2c6ce
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist
my.secrets
.dev.env
1 change: 1 addition & 0 deletions apps/kafka-mapper-consumer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"scripts": {
"start": "ts-node src/index.ts",
"start:dev": "node -r ts-node/register --env-file=.dev.env src/index.ts",
"build": "docker build -t jembi/kafka-mapper-consumer .",
"test": "npm run cucumber",
"cucumber": "cucumber-js test/features/**/*.feature --no-color --logLevel=error --require test/step-definitions/**/*.ts --require-module ts-node/register --format-options \"{\\\"snippetInterface\\\": \\\"async-await\\\"}\" --format summary --format progress-bar"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, memo } from "react";
import { FC, memo, useState } from "react";
import { useDrag } from "react-dnd";
import Chip from "@mui/material/Chip";
import { Avatar, Button } from "@mui/material";
Expand All @@ -7,14 +7,16 @@ import {
ColumnMapping,
useFhirMapperConfig,
} from "../FhirMapperConfigProvider";
import { EditExpressionDialog } from "./EditExpressionDialog";

export interface DraggableChipProps {
expression: ColumnMapping;
type: string;
table?: string;
}

export const DraggableChip: FC<DraggableChipProps> = memo(
function DraggableChip({ expression, type }) {
function DraggableChip({ expression, type, table }) {
const [{ opacity }, drag] = useDrag(
() => ({
type: "EXPRESSION",
Expand All @@ -27,21 +29,30 @@ export const DraggableChip: FC<DraggableChipProps> = memo(
[name, type]
);

const { removeExpression } = useFhirMapperConfig();
const { removeExpression, removeMappingSchemaItem } = useFhirMapperConfig();

return (
<div ref={drag} style={{ opacity }}>
<Chip
avatar={
<Avatar>
<Button variant="contained">
<Edit fontSize="small" />
</Button>
<EditExpressionDialog
table={table}
prevColumnName={expression.columnName}
prevExpression={expression.fhirPath}
/>
</Avatar>
}
label={expression.columnName}
color={"primary"}
onDelete={() => removeExpression(expression.columnName)}
onDelete={() => {
if (table) {
removeMappingSchemaItem(table, expression);
removeExpression("");
} else {
removeExpression(expression.columnName);
}
}}
clickable
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { useEffect, useState } from "react";
import {
Button,
Stack,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TextField,
Link,
} from "@mui/material";
import fhirpath from "fhirpath";
import { useFhirMapperConfig } from "../FhirMapperConfigProvider";
import { FhirResource } from "fhir/r4";
import { Edit } from "@mui/icons-material";
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";

export function EditExpressionDialog({
table,
prevExpression,
prevColumnName,
}) {
const [open, setOpen] = useState(false);
const [previewValue, setPreviewValue] = useState("");
const [expression, setExpression] = useState(prevExpression);
const [columnName, setColumnName] = useState(prevColumnName);
const { activeFhirResource, updateMappingSchemaItem } = useFhirMapperConfig();

const handleClickOpen = () => {
const resourceType = expression.split(".")[0];
if (resourceType !== activeFhirResource.resourceType) {
handleClose();
alert("Invalid FHIRPath expression. Please try again.");
return;
}
setOpen(true);
};

const handleClose = () => {
setOpen(false);
setPreviewValue("");
};

const handleAddElement = (event) => {
event.preventDefault();
const resourceType = expression.split(".")[0];
updateMappingSchemaItem(
table,
prevColumnName,
{ columnName: columnName, fhirPath: expression },
resourceType
);
handleClose();
};

function renderPreview() {
// evaluate FHIRPath expression on FHIR resource and return result
// TODO : add handle errors
try {
return fhirpath.evaluate(activeFhirResource, expression);
} catch {
return "Error! Invalid expression.";
}
}

useEffect(() => {
// Assuming renderPreview uses the expression state internally
const preview = renderPreview();
if (typeof preview === "string" && preview.startsWith("Error")) {
setPreviewValue("Error! Invalid expression.");
} else {
setPreviewValue(preview.toString());
}
}, [expression]);

return (
<>
<Button
variant="text"
aria-label="FHIRPath Expression"
onClick={handleClickOpen}
disabled={!table}
sx={{
backgroundColor: "white",
opacity: 0.6,
visibility: table ? "visible" : "hidden",
}}
>
<EditOutlinedIcon fontSize="small" color="action" />
</Button>
<Dialog open={open} onClose={handleClose}>
<DialogTitle id="add-expression-alert-dialog">
{"Add Custom Expression"}
</DialogTitle>
<DialogContent>
<Stack spacing={3} p={"10px"}>
<form id="add-expression" onSubmit={handleAddElement}>
<TextField
onChange={(e) => setColumnName(e.target.value)}
inputProps={{ pattern: "^[a-zA-Z_][a-zA-Z0-9_]*$" }}
id="column-name-input"
name="column-name-input"
label="Name of the output column"
variant="outlined"
type="text"
fullWidth
required
helperText="This is the name of the column that will be created in the table. Only alphanumeric characters and underscores allowed"
value={columnName}
/>
<TextField
id="expression-input"
name="expression-input"
label="Expression"
variant="outlined"
type="text"
onChange={(e) => {
setExpression(e.target.value);
}}
fullWidth
required
helperText={[
"This is the FHIRPath expression that will be used to extract the value from the FHIR resource. Read about FHIRPath expressions here: ",
<Link
key="FHIRpath-helperText-link"
href="https://www.hl7.org/fhirpath/"
target="_blank"
>
{"https://www.hl7.org/fhirpath/"}
</Link>,
]}
value={expression}
/>
</form>
<TextField
sx={{
"& .MuiInputBase-input.Mui-disabled": {
WebkitTextFillColor: "#111111",
},
}}
disabled
multiline
minRows={3}
id="expression-output-preview"
name="expression-output-preview"
label="Result preview"
variant="standard"
type="text"
helperText="This is a preview of the result of the expression. It will be used as a column value."
fullWidth
error={previewValue === "Error! Invalid expression."}
inputProps={{ readOnly: true }}
value={previewValue}
/>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button
color={"primary"}
variant={"contained"}
type="submit"
form="add-expression"
>
Update
</Button>
</DialogActions>
</Dialog>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function ExpressionsDropTable({
}: ExpressionsDropTableProps) {
return (
<ListItem key={expression.columnName + table}>
<DraggableChip expression={expression} type="EXPRESSION" />
<DraggableChip expression={expression} table={table} type="EXPRESSION" />
</ListItem>
);
}
Loading

0 comments on commit 2f2c6ce

Please sign in to comment.