Compare commits

..

2 Commits

Author SHA1 Message Date
bf2fe01da6 Merge pull request 'Update dependency node to v24.8.0' (#312) from renovate/node-24.x into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 4m33s
Playwright Tests / test (push) Successful in 26m19s
Build Nginx-based docker image / build-static-assets (push) Successful in 1h0m20s
Reviewed-on: #312
2025-09-11 15:45:36 +00:00
Renovate Bot
beb7be4b7d Update dependency node to v24.8.0
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m37s
Add copyright notice / copyright_notice (pull_request) Successful in 2m41s
Playwright Tests / test (pull_request) Successful in 20m29s
Build Nginx-based docker image / build-static-assets (push) Successful in 43m52s
2025-09-11 14:14:59 +00:00
8 changed files with 27 additions and 42 deletions

2
.nvmrc
View File

@ -1 +1 @@
24.3.0 24.8.0

View File

@ -8,7 +8,7 @@ import Arrangement from '@/app/ui/arrangements/arrangement';
import ArrangementsTable from '@/app/ui/arrangements/arrangements-table'; import ArrangementsTable from '@/app/ui/arrangements/arrangements-table';
import { classNames } from '@/app/ui/components/button'; import { classNames } from '@/app/ui/components/button';
import { Toast } from 'primereact/toast'; import { Toast } from 'primereact/toast';
import React, { useEffect, useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
export default function Page() { export default function Page() {
const toast = useRef<Toast>(null); const toast = useRef<Toast>(null);

View File

@ -13,8 +13,6 @@ export function loadTableSimulations(onLoad?: (tableSimulations: TableArrangemen
name: record.name, name: record.name,
discomfort: record.discomfort, discomfort: record.discomfort,
valid: record.valid, valid: record.valid,
progress: record.progress,
status : record.status
}); });
})); }));
}, (error) => { }, (error) => {

View File

@ -14,8 +14,6 @@ export type TableArrangement = {
guests?: Guest[]; guests?: Guest[];
discomfort?: number; discomfort?: number;
valid?: boolean; valid?: boolean;
progress: number;
status: 'in_progress' | 'completed' | 'not_started';
} }
export type User = { export type User = {

View File

@ -22,12 +22,10 @@ export type Table = {
export class TableSimulation implements Entity { export class TableSimulation implements Entity {
id?: string; id?: string;
tables: Table[]; tables: Table[];
progress: number;
constructor(id?: string, tables?: Table[], progress?: number) { constructor(id?: string, tables?: Table[]) {
this.id = id; this.id = id;
this.tables = tables || []; this.tables = tables || [];
this.progress = progress || 0;
} }
} }
@ -45,7 +43,7 @@ export class TableSimulationSerializer implements Serializable<TableSimulation>
} }
}, },
} }
}), data.progress); }));
} }
toJson(simulation: TableSimulation): string { toJson(simulation: TableSimulation): string {

View File

@ -10,21 +10,11 @@ import { loadTableSimulations } from "@/app/api/tableSimulations";
import { ArchiveBoxXMarkIcon, CheckBadgeIcon } from "@heroicons/react/24/outline"; import { ArchiveBoxXMarkIcon, CheckBadgeIcon } from "@heroicons/react/24/outline";
import { Tooltip } from "primereact/tooltip"; import { Tooltip } from "primereact/tooltip";
import clsx from "clsx"; import clsx from "clsx";
import { ProgressBar } from "primereact/progressbar";
import { useEffect } from "react";
import { TableSimulation, TableSimulationSerializer } from "@/app/lib/tableSimulation";
import { AbstractApi } from "@/app/api/abstract-api";
export default function ArrangementsTable({ onArrangementSelected }: { onArrangementSelected: (arrangementId: string) => void }) { export default function ArrangementsTable({ onArrangementSelected }: { onArrangementSelected: (arrangementId: string) => void }) {
const [arrangements, setArrangements] = useState<Array<TableArrangement>>([]); const [arrangements, setArrangements] = useState<Array<TableArrangement>>([]);
const [arrangementsLoaded, setArrangementsLoaded] = useState(false); const [arrangementsLoaded, setArrangementsLoaded] = useState(false);
useEffect(() => {
refreshSimulations();
const interval = setInterval(refreshSimulations, 10000);
return () => clearInterval(interval);
}, []);
function refreshSimulations() { function refreshSimulations() {
loadTableSimulations((arrangements) => { loadTableSimulations((arrangements) => {
setArrangements(arrangements); setArrangements(arrangements);
@ -36,9 +26,11 @@ export default function ArrangementsTable({ onArrangementSelected }: { onArrange
onArrangementSelected(e.currentTarget.getAttribute('data-arrangement-id') || ''); onArrangementSelected(e.currentTarget.getAttribute('data-arrangement-id') || '');
} }
!arrangementsLoaded && refreshSimulations();
return ( return (
<TableOfContents <TableOfContents
headers={['Name', 'Discomfort', 'Status', 'Actions']} headers={['Name', 'Discomfort', 'Actions', 'Status']}
caption='Simulations' caption='Simulations'
elements={arrangements} elements={arrangements}
rowRender={(arrangement) => ( rowRender={(arrangement) => (
@ -52,19 +44,18 @@ export default function ArrangementsTable({ onArrangementSelected }: { onArrange
<td className="px-6 py-4"> <td className="px-6 py-4">
{arrangement.discomfort} {arrangement.discomfort}
</td> </td>
<td className="px-4">
<Tooltip target=".tooltip-status" />
<>
{ arrangement.valid && arrangement.status === 'not_started' && <ProgressBar mode="indeterminate" style={{ height: '6px' }}></ProgressBar> }
{ arrangement.valid && arrangement.status !== 'not_started' && <ProgressBar value={(100 * arrangement.progress).toFixed(2) }></ProgressBar> }
{ !arrangement.valid && 'The list of potential guests has changed since this simulation.' }
</>
</td>
<td> <td>
<button data-arrangement-id={arrangement.id} onClick={arrangementClicked} className={classNames('primary')}>Load</button> <button data-arrangement-id={arrangement.id} onClick={arrangementClicked} className={classNames('primary')}>Load</button>
</td> </td>
<td>
<Tooltip target=".tooltip-status" />
{
arrangement.valid ?
<CheckBadgeIcon className='size-6 tooltip-status' data-pr-position="right" data-pr-tooltip="Simulation is valid" /> :
<ArchiveBoxXMarkIcon className='size-6 tooltip-status' data-pr-position="right" data-pr-tooltip="Simulation is expired due to attendance or affinity changes" />
}
</td>
</tr> </tr>
)} )}
/> />

View File

@ -32,7 +32,7 @@
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.52.0", "@playwright/test": "^1.52.0",
"@types/bcrypt": "^5.0.2", "@types/bcrypt": "^5.0.2",
"@types/node": "24.0.10", "@types/node": "24.3.1",
"@types/react": "18.3.23", "@types/react": "18.3.23",
"@types/react-dom": "18.3.7", "@types/react-dom": "18.3.7",
"wait-on": "^8.0.3" "wait-on": "^8.0.3"

20
pnpm-lock.yaml generated
View File

@ -82,8 +82,8 @@ importers:
specifier: ^5.0.2 specifier: ^5.0.2
version: 5.0.2 version: 5.0.2
'@types/node': '@types/node':
specifier: 24.0.10 specifier: 24.3.1
version: 24.0.10 version: 24.3.1
'@types/react': '@types/react':
specifier: 18.3.23 specifier: 18.3.23
version: 18.3.23 version: 18.3.23
@ -520,8 +520,8 @@ packages:
'@types/mdurl@2.0.0': '@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/node@24.0.10': '@types/node@24.3.1':
resolution: {integrity: sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==} resolution: {integrity: sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==}
'@types/prop-types@15.7.12': '@types/prop-types@15.7.12':
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
@ -1328,8 +1328,8 @@ packages:
uc.micro@2.1.0: uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
undici-types@7.8.0: undici-types@7.10.0:
resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
update-browserslist-db@1.1.3: update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
@ -1755,7 +1755,7 @@ snapshots:
'@types/bcrypt@5.0.2': '@types/bcrypt@5.0.2':
dependencies: dependencies:
'@types/node': 24.0.10 '@types/node': 24.3.1
'@types/linkify-it@5.0.0': {} '@types/linkify-it@5.0.0': {}
@ -1766,9 +1766,9 @@ snapshots:
'@types/mdurl@2.0.0': {} '@types/mdurl@2.0.0': {}
'@types/node@24.0.10': '@types/node@24.3.1':
dependencies: dependencies:
undici-types: 7.8.0 undici-types: 7.10.0
'@types/prop-types@15.7.12': {} '@types/prop-types@15.7.12': {}
@ -2595,7 +2595,7 @@ snapshots:
uc.micro@2.1.0: {} uc.micro@2.1.0: {}
undici-types@7.8.0: {} undici-types@7.10.0: {}
update-browserslist-db@1.1.3(browserslist@4.24.4): update-browserslist-db@1.1.3(browserslist@4.24.4):
dependencies: dependencies: