Skip to content

Commit a4bc3f6

Browse files
author
xjadrnic
committed
fix: review fixes, cleanup
1 parent 3fe47e9 commit a4bc3f6

11 files changed

Lines changed: 178 additions & 291 deletions

File tree

compose.yaml

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,4 @@
11
services:
2-
config-generator:
3-
image: alpine:latest
4-
entrypoint: /bin/sh
5-
command: -c "apk add --no-cache gettext && envsubst < /templates/prometheus.template.yml > /prometheus-config/prometheus.yml && envsubst < /templates/promtail-config.template.yaml > /promtail-config/promtail-config.yaml"
6-
volumes:
7-
- ./config/prometheus.template.yml:/templates/prometheus.template.yml:ro
8-
- ./config/promtail-config.template.yaml:/templates/promtail-config.template.yaml:ro
9-
- prometheus-config:/prometheus-config
10-
- promtail-config:/promtail-config
11-
env_file:
12-
- .env
13-
142
fhir-module:
153
image: ghcr.io/bbmri-cz/fhir-module:latest
164
container_name: fhir-module
@@ -22,7 +10,7 @@ services:
2210
- monitoring
2311
restart: no
2412
ports:
25-
- "5001:5000"
13+
- "5000:5000"
2614
environment:
2715
BLAZE_URL: "http://test-blaze:8080/fhir"
2816
MIABIS_BLAZE_URL: "http://miabis-blaze:8080/fhir"
@@ -57,10 +45,6 @@ services:
5745
image: prom/prometheus:latest
5846
profiles:
5947
- monitoring
60-
depends_on:
61-
config-generator:
62-
condition: service_completed_successfully
63-
required: false
6448
networks:
6549
- monitoring
6650
ports:
@@ -118,10 +102,6 @@ services:
118102
container_name: promtail
119103
profiles:
120104
- monitoring
121-
depends_on:
122-
config-generator:
123-
condition: service_completed_successfully
124-
required: false
125105
networks:
126106
- monitoring
127107
volumes:

ui/fhir-place/Dockerfile

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ WORKDIR /app
99
# Copy package files
1010
COPY package*.json ./
1111

12-
# Install all dependencies (including devDependencies for build)
12+
# Install all dependencies (including devDependencies for build), no --ignore-scripts because of the packages used (sqlite3)
1313
RUN npm ci && npm cache clean --force
1414

1515
# Copy source code
@@ -27,11 +27,9 @@ FROM node:20-alpine AS runner
2727

2828
WORKDIR /app
2929

30-
# Install tsx for TypeScript execution
31-
RUN npm install -g tsx
32-
33-
# Create a non-root user
34-
RUN addgroup -g 1001 -S nodejs && \
30+
# Install tsx for TypeScript execution and create a non-root user
31+
RUN npm install -g tsx && \
32+
addgroup -g 1001 -S nodejs && \
3533
adduser -S nextjs -u 1001
3634

3735
# Copy necessary files from builder stage
@@ -47,13 +45,10 @@ COPY --from=builder /app/drizzle ./drizzle
4745
COPY --from=builder /app/src/scripts ./src/scripts
4846
COPY --from=builder /app/src/lib ./src/lib
4947

50-
# Copy startup script
51-
COPY start.sh /app/start.sh
5248

5349
# Create data directory and set permissions
5450
RUN mkdir -p /app/data && \
55-
chown -R nextjs:nodejs /app && \
56-
chmod +x /app/start.sh
51+
chown -R nextjs:nodejs /app
5752
USER nextjs
5853

5954
# Expose port

ui/fhir-place/src/actions/settings/__tests__/changePassword.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe("changePassword", () => {
5858

5959
beforeEach(() => {
6060
jest.clearAllMocks();
61-
mockChangePasswordSchema.parse = jest
61+
mockChangePasswordSchema.parseAsync = jest
6262
.fn()
6363
.mockImplementation((data) => data);
6464

@@ -95,7 +95,9 @@ describe("changePassword", () => {
9595
const result = await changePassword(mockFormData, mockUserDetails);
9696

9797
expect(result).toBe(true);
98-
expect(mockChangePasswordSchema.parse).toHaveBeenCalledWith(mockFormData);
98+
expect(mockChangePasswordSchema.parseAsync).toHaveBeenCalledWith(
99+
mockFormData
100+
);
99101
expect(mockBcrypt.compare).toHaveBeenCalledWith(
100102
"OldPass123!",
101103
"old-hashed-password"
@@ -142,7 +144,7 @@ describe("changePassword", () => {
142144
message: "Current password is required",
143145
},
144146
]);
145-
mockChangePasswordSchema.parse.mockImplementation(() => {
147+
mockChangePasswordSchema.parseAsync.mockImplementation(() => {
146148
throw zodError;
147149
});
148150

ui/fhir-place/src/actions/settings/changePassword.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export async function changePassword(
1313
userDetails: UserDetails
1414
) {
1515
try {
16-
const validatedData = ChangePasswordSchema.parse(formData);
16+
const validatedData = await ChangePasswordSchema.parseAsync(formData);
1717

1818
const user = await db.query.users.findFirst({
1919
where: eq(users.id, userDetails.id),

ui/fhir-place/src/app/(authorized)/backend-control/page.tsx

Lines changed: 60 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
"use client";
22

3-
import { Button } from "@/components/ui/button";
43
import { RotateCcw, Trash2, RefreshCw } from "lucide-react";
5-
import {
6-
Dialog,
7-
DialogClose,
8-
DialogContent,
9-
DialogDescription,
10-
DialogFooter,
11-
DialogHeader,
12-
DialogTitle,
13-
DialogTrigger,
14-
} from "@/components/ui/dialog";
15-
import { CheckedFormInput } from "@/components/custom/form/CheckedFormInput";
16-
import { Form } from "@/components/ui/form";
174
import { OperationCard } from "@/components/custom/OperationCard";
185
import { ActionItem } from "@/components/custom/ActionItem";
196
import { ActionButton } from "@/components/custom/ActionButton";
7+
import { ConfirmationDialog } from "@/components/custom/ConfirmationDialog";
208
import { useBackendControl } from "@/hooks/useBackendControl";
21-
import { useDeleteDialog } from "@/hooks/useDeleteDialog";
9+
import { useConfirmationDialog } from "@/hooks/useConfirmationDialog";
2210

2311
export default function BackendControlPage() {
2412
const {
@@ -32,12 +20,20 @@ export default function BackendControlPage() {
3220
} = useBackendControl();
3321

3422
const {
35-
isDeleteDialogOpen,
36-
form,
37-
deleteAllConfirmMessage,
38-
handleDelete,
39-
handleDialogChange,
40-
} = useDeleteDialog(handleDeleteAll);
23+
isDialogOpen: isDeleteAllDialogOpen,
24+
form: deleteAllForm,
25+
confirmationMessage: deleteAllConfirmMessage,
26+
handleConfirm: handleDeleteAllConfirm,
27+
handleDialogChange: handleDeleteAllDialogChange,
28+
} = useConfirmationDialog("DELETE ALL", handleDeleteAll);
29+
30+
const {
31+
isDialogOpen: isMiabisDeleteDialogOpen,
32+
form: miabisDeleteForm,
33+
confirmationMessage: miabisDeleteConfirmMessage,
34+
handleConfirm: handleMiabisDeleteConfirm,
35+
handleDialogChange: handleMiabisDeleteDialogChange,
36+
} = useConfirmationDialog("DELETE ALL", handleMiabisDelete);
4137

4238
return (
4339
<main className="flex-1 p-6">
@@ -100,71 +96,61 @@ export default function BackendControlPage() {
10096
isFading={fadingBadges["Delete All"]}
10197
disabled={isLoading !== null}
10298
>
103-
<Dialog
104-
open={isDeleteDialogOpen}
105-
onOpenChange={handleDialogChange}
99+
<ConfirmationDialog
100+
isOpen={isDeleteAllDialogOpen}
101+
onOpenChange={handleDeleteAllDialogChange}
102+
title="Are you sure?"
103+
description="This action will delete all data from the FHIR server. This action cannot be undone."
104+
confirmationMessage={deleteAllConfirmMessage}
105+
confirmButtonText="Delete All"
106+
form={deleteAllForm}
107+
onConfirm={handleDeleteAllConfirm}
108+
isLoading={isLoading !== null}
106109
>
107-
<DialogTrigger asChild>
108-
<ActionButton
109-
onClick={() => {}}
110-
disabled={isLoading !== null}
111-
loading={isLoading === "Delete All"}
112-
icon={Trash2}
113-
variant="destructive"
114-
>
115-
Delete All
116-
</ActionButton>
117-
</DialogTrigger>
118-
<DialogContent className="sm:max-w-[425px]">
119-
<DialogHeader>
120-
<DialogTitle>Are you sure?</DialogTitle>
121-
<DialogDescription>
122-
This action will delete all data from the FHIR server.
123-
This action cannot be undone. To proceed, please type
124-
&quot;{deleteAllConfirmMessage}&quot; in the input field
125-
below.
126-
</DialogDescription>
127-
</DialogHeader>
128-
<Form {...form}>
129-
<form onSubmit={form.handleSubmit(handleDelete)}>
130-
<CheckedFormInput
131-
control={form.control}
132-
type="text"
133-
name="confirmInput"
134-
placeholder={deleteAllConfirmMessage}
135-
errors={form.formState.errors}
136-
/>
137-
<DialogFooter className="flex justify-end pt-4">
138-
<DialogClose asChild>
139-
<Button variant="outline">Cancel</Button>
140-
</DialogClose>
141-
<Button
142-
type="submit"
143-
disabled={isLoading !== null}
144-
variant="destructive"
145-
className="min-w-[100px]"
146-
>
147-
Delete All
148-
</Button>
149-
</DialogFooter>
150-
</form>
151-
</Form>
152-
</DialogContent>
153-
</Dialog>
110+
<ActionButton
111+
onClick={() => {}}
112+
disabled={isLoading !== null}
113+
loading={isLoading === "Delete All"}
114+
icon={Trash2}
115+
variant="destructive"
116+
>
117+
Delete All
118+
</ActionButton>
119+
</ConfirmationDialog>
154120
</ActionItem>
155121

156122
<ActionItem
157123
title="Delete MIABIS Data"
158124
description="Remove all MIABIS on FHIR resources"
159125
buttonText="Delete MIABIS"
160-
onAction={handleMiabisDelete}
126+
onAction={() => {}}
161127
isLoading={isLoading === "MIABIS Delete"}
162128
result={lastResults["MIABIS Delete"]}
163129
isFading={fadingBadges["MIABIS Delete"]}
164-
icon={Trash2}
165-
variant="destructive"
166130
disabled={isLoading !== null}
167-
/>
131+
>
132+
<ConfirmationDialog
133+
isOpen={isMiabisDeleteDialogOpen}
134+
onOpenChange={handleMiabisDeleteDialogChange}
135+
title="Are you sure?"
136+
description="This action will delete all MIABIS data from the FHIR server. This action cannot be undone."
137+
confirmationMessage={miabisDeleteConfirmMessage}
138+
confirmButtonText="Delete MIABIS"
139+
form={miabisDeleteForm}
140+
onConfirm={handleMiabisDeleteConfirm}
141+
isLoading={isLoading !== null}
142+
>
143+
<ActionButton
144+
onClick={() => {}}
145+
disabled={isLoading !== null}
146+
loading={isLoading === "MIABIS Delete"}
147+
icon={Trash2}
148+
variant="destructive"
149+
>
150+
Delete MIABIS
151+
</ActionButton>
152+
</ConfirmationDialog>
153+
</ActionItem>
168154
</OperationCard>
169155
</div>
170156
</div>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"use client";
2+
3+
import { Button } from "@/components/ui/button";
4+
import {
5+
Dialog,
6+
DialogClose,
7+
DialogContent,
8+
DialogDescription,
9+
DialogFooter,
10+
DialogHeader,
11+
DialogTitle,
12+
DialogTrigger,
13+
} from "@/components/ui/dialog";
14+
import { CheckedFormInput } from "@/components/custom/form/CheckedFormInput";
15+
import { Form } from "@/components/ui/form";
16+
import { ReactNode } from "react";
17+
import { UseFormReturn } from "react-hook-form";
18+
import { z } from "zod";
19+
import { ConfirmDeleteSchema } from "@/app/(authorized)/backend-control/form/schema";
20+
21+
export interface ConfirmationDialogProps {
22+
children: ReactNode;
23+
isOpen: boolean;
24+
onOpenChange: (open: boolean) => void;
25+
title: string;
26+
description: string;
27+
confirmationMessage: string;
28+
confirmButtonText: string;
29+
form: UseFormReturn<z.infer<typeof ConfirmDeleteSchema>>;
30+
onConfirm: (data: z.infer<typeof ConfirmDeleteSchema>) => void;
31+
isLoading?: boolean;
32+
}
33+
34+
export function ConfirmationDialog({
35+
children,
36+
isOpen,
37+
onOpenChange,
38+
title,
39+
description,
40+
confirmationMessage,
41+
confirmButtonText,
42+
form,
43+
onConfirm,
44+
isLoading = false,
45+
}: ConfirmationDialogProps) {
46+
return (
47+
<Dialog open={isOpen} onOpenChange={onOpenChange}>
48+
<DialogTrigger asChild>{children}</DialogTrigger>
49+
<DialogContent className="sm:max-w-[425px]">
50+
<DialogHeader>
51+
<DialogTitle>{title}</DialogTitle>
52+
<DialogDescription>
53+
{description} To proceed, please type &quot;{confirmationMessage}
54+
&quot; in the input field below.
55+
</DialogDescription>
56+
</DialogHeader>
57+
<Form {...form}>
58+
<form onSubmit={form.handleSubmit(onConfirm)}>
59+
<CheckedFormInput
60+
control={form.control}
61+
type="text"
62+
name="confirmInput"
63+
placeholder={confirmationMessage}
64+
errors={form.formState.errors}
65+
/>
66+
<DialogFooter className="flex justify-end pt-4">
67+
<DialogClose asChild>
68+
<Button variant="outline">Cancel</Button>
69+
</DialogClose>
70+
<Button
71+
type="submit"
72+
disabled={isLoading}
73+
variant="destructive"
74+
className="min-w-[100px]"
75+
>
76+
{confirmButtonText}
77+
</Button>
78+
</DialogFooter>
79+
</form>
80+
</Form>
81+
</DialogContent>
82+
</Dialog>
83+
);
84+
}

0 commit comments

Comments
 (0)