diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 10590123a1..6a08321304 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -111,6 +111,8 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"lint-staged": "14.0.1",
+ "ora": "8.1.1",
+ "postgres": "3.4.5",
"prettier": "3.3.3",
"puppeteer": "22.15.0",
"strip-json-comments": "5.0.1",
@@ -5878,6 +5880,19 @@
"node": ">=8"
}
},
+ "node_modules/cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/cli-table3": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz",
@@ -8949,6 +8964,19 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
@@ -10101,6 +10129,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-interactive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+ "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
@@ -13215,6 +13256,19 @@
"node": ">=6"
}
},
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/mimic-response": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
@@ -13731,6 +13785,202 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/ora": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.1.1.tgz",
+ "integrity": "sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
+ "is-interactive": "^2.0.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ora/node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/log-symbols": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/ora/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/ospath": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz",
@@ -14285,6 +14535,20 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"license": "MIT"
},
+ "node_modules/postgres": {
+ "version": "3.4.5",
+ "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.5.tgz",
+ "integrity": "sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==",
+ "dev": true,
+ "license": "Unlicense",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/porsager"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -16118,6 +16382,19 @@
"node": ">=8"
}
},
+ "node_modules/stdin-discarder": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/stream-events": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index e95a30eccd..44ac88e31e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -17,6 +17,7 @@
"dev-puppeteer": "FRONTEND_OIDC_ENABLED=false FRONTEND_MONITORENV_URL=//localhost:9880 import-meta-env-prepare -u -x ./.env.local.defaults && vite --port 3000",
"bundle-sw": "esbuild src/workers/serviceWorker.ts --bundle --outfile=public/service-worker.js",
"prepare": "cd .. && ./frontend/node_modules/.bin/husky ./frontend/config/husky",
+ "generate:perfdata": "node ./scripts/generate_perf_data.js",
"generate:testdata": "node ./scripts/generate_test_data_seeds.js",
"start": "import-meta-env-prepare -u -x ./.env.local.defaults && vite preview --port 3000",
"start:emulate": "npm run clean && npm run build && import-meta-env -x ./.env.example -p ./build/index.html && import-meta-env-prepare -u -x ./.env.local.defaults && vite preview --port 3000",
@@ -136,6 +137,8 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"lint-staged": "14.0.1",
+ "ora": "8.1.1",
+ "postgres": "3.4.5",
"prettier": "3.3.3",
"puppeteer": "22.15.0",
"strip-json-comments": "5.0.1",
diff --git a/frontend/scripts/generate_perf_data.js b/frontend/scripts/generate_perf_data.js
new file mode 100644
index 0000000000..d026426d2f
--- /dev/null
+++ b/frontend/scripts/generate_perf_data.js
@@ -0,0 +1,280 @@
+/* eslint-disable no-await-in-loop */
+
+import { faker } from '@faker-js/faker'
+import dayjs from 'dayjs'
+import ora from 'ora'
+import postgres from 'postgres'
+
+const BATCH_SIZE = 1000
+const BATCH_SKELETON = new Array(BATCH_SIZE).fill(null)
+const START_DATE = dayjs().subtract(6, 'months').toDate()
+const END_DATE = dayjs().add(6, 'months').toDate()
+
+const FAKE_PNO_COUNT = 1000000
+const FAKE_PNO_BATCH_COUNT = FAKE_PNO_COUNT / BATCH_SIZE
+
+const FAKE_VESSEL_COUNT = 10000
+const FAKE_VESSEL_BATCH_COUNT = FAKE_VESSEL_COUNT / BATCH_SIZE
+
+const FAKE_REPORTING_COUNT = FAKE_VESSEL_COUNT * 3
+const FAKE_REPORTING_BATCH_COUNT = FAKE_REPORTING_COUNT / BATCH_SIZE
+
+function getFakePnoLogbookRawMessages(index) {
+ return [
+ {
+ operation_number: `FAKE_OPERATION_${FAKE_PNO_COUNT + index}`,
+ xml_message: `Message FLUX xml`
+ },
+ {
+ operation_number: `FAKE_OPERATION_${FAKE_PNO_COUNT + index}_RET`,
+ xml_message: `Message FLUX xml`
+ }
+ ]
+}
+
+function getFakePnoLogbookReports(index) {
+ const vesselId = faker.number.int({ max: FAKE_VESSEL_COUNT * 2, min: FAKE_VESSEL_COUNT + 1 })
+ const cfr = `FAKCFR_${vesselId}`
+ const vessel_name = `FAUX NAVIRE ${vesselId}`
+
+ const tripStartDateAsDayjs = dayjs(
+ faker.date.between({
+ from: START_DATE,
+ to: END_DATE
+ })
+ )
+
+ const operation_datetime_utc = tripStartDateAsDayjs.add(26, 'hours').format('YYYY-MM-DD HH:mm:ss')
+ const report_id = `FAKE_OPERATION_${FAKE_PNO_COUNT + index}`
+ const transmission_format = 'ERS'
+
+ return [
+ {
+ cfr,
+ enriched: true,
+ flag_state: 'FRA',
+ id: FAKE_PNO_COUNT + index,
+ integration_datetime_utc: operation_datetime_utc,
+ log_type: 'PNO',
+ operation_datetime_utc,
+ operation_number: report_id,
+ operation_type: 'DAT',
+ referenced_report_id: null,
+ report_datetime_utc: operation_datetime_utc,
+ report_id,
+ transmission_format,
+ trip_gears: [
+ { dimensions: '250;180', gear: 'TBN', mesh: 100 },
+ { dimensions: '250;280', gear: 'OTT', mesh: 120.5 }
+ ],
+ trip_segments: [
+ { segment: 'SWW04', segmentName: 'Chaluts pélagiques' },
+ { segment: 'SWW06', segmentName: 'Sennes' }
+ ],
+ value: {
+ authorTrigram: null,
+ catchOnboard: [
+ {
+ economicZone: 'FRA',
+ effortZone: 'C',
+ faoZone: '27.8.a',
+ nbFish: null,
+ species: 'ANF',
+ statisticalRectangle: '23E6',
+ weight: 150
+ }
+ ],
+ pnoTypes: [
+ {
+ hasDesignatedPorts: false,
+ minimumNotificationPeriod: 4,
+ pnoTypeName: 'Préavis type Z'
+ }
+ ],
+ port: 'BROIA',
+ predictedArrivalDatetimeUtc: tripStartDateAsDayjs.add(30, 'hours').format('YYYY-MM-DDTHH:mm:ss[Z]'),
+ predictedLandingDatetimeUtc: tripStartDateAsDayjs.add(31, 'hours').format('YYYY-MM-DDTHH:mm:ss[Z]'),
+ purpose: 'LAN',
+ riskFactor: 2.9,
+ tripStartDate: tripStartDateAsDayjs.format('YYYY-MM-DDTHH:mm:ss[Z]'),
+ updatedAt: null,
+ updatedBy: null
+ },
+ vessel_name
+ },
+ // We need to have the exact same props as the DAT report otherwise `sql()` batch insert will fail
+ {
+ cfr: null,
+ enriched: true,
+ flag_state: null,
+ id: 2 * FAKE_PNO_COUNT + index,
+ integration_datetime_utc: operation_datetime_utc,
+ log_type: null,
+ operation_datetime_utc,
+ operation_number: `${report_id}_RET`,
+ operation_type: 'RET',
+ referenced_report_id: report_id,
+ report_datetime_utc: null,
+ report_id: null,
+ transmission_format,
+ trip_gears: null,
+ trip_segments: null,
+ value: {
+ returnStatus: '000'
+ },
+ vessel_name: null
+ }
+ ]
+}
+
+function getFakeReporting(index) {
+ const vessel_id = faker.number.int({ max: FAKE_VESSEL_COUNT * 2, min: FAKE_VESSEL_COUNT + 1 })
+ const internal_reference_number = `FAKCFR_${vessel_id}`
+ const vessel_name = `FAUX NAVIRE ${vessel_id}`
+
+ const creationDate = dayjs(
+ faker.date.between({
+ from: START_DATE,
+ to: END_DATE
+ })
+ )
+
+ const type = faker.helpers.arrayElement(['ALERT', 'INFRACTION_SUSPICION', 'OBSERVATION'])
+ const value =
+ type === 'ALERT'
+ ? {
+ natinfCode: 7059,
+ riskFactor: faker.number.float({ max: 5, min: 0 }),
+ seaFront: faker.helpers.arrayElement(['MED', 'MEMN', 'NAMO', 'SA']),
+ type: 'THREE_MILES_TRAWLING_ALERT'
+ }
+ : {
+ authorContact: '',
+ authorTrigram: faker.string.alpha(3).toUpperCase(),
+ controlUnitId: null,
+ description: faker.lorem.sentence(),
+ dml: 'DML 29',
+ natinfCode: 23588,
+ reportingActor: faker.helpers.arrayElement(['OPS', 'UNIT']),
+ seaFront: faker.helpers.arrayElement(['MED', 'MEMN', 'NAMO', 'SA']),
+ title: faker.lorem.sentence(),
+ type
+ }
+
+ return {
+ archived: false,
+ creation_date: creationDate.format('YYYY-MM-DD HH:mm:ss'),
+ deleted: false,
+ external_reference_number: null,
+ flag_state: 'FR',
+ id: FAKE_REPORTING_COUNT + index,
+ internal_reference_number,
+ ircs: null,
+ latitude: faker.location.latitude({ max: 51, min: 42, precision: 3 }),
+ longitude: faker.location.longitude({ max: 10, min: -7, precision: 3 }),
+ type,
+ validation_date: creationDate.add(2, 'hours').format('YYYY-MM-DD HH:mm:ss'),
+ value,
+ vessel_id,
+ vessel_identifier: 'INTERNAL_REFERENCE_NUMBER',
+ vessel_name
+ }
+}
+
+function getFakeVessel(index) {
+ const id = FAKE_VESSEL_COUNT + index
+
+ return {
+ cfr: `FAKCFR_${id}`,
+ flag_state: 'FR',
+ id,
+ length: 99,
+ vessel_name: `FAUX NAVIRE ${id}`
+ }
+}
+
+const sql = postgres('postgres://postgres:postgres@localhost:5432/monitorfishdb')
+
+async function run() {
+ let batchIndex
+ const spinner = ora('Starting...').start()
+
+ try {
+ // Ignore SQL notices
+ await sql`SET client_min_messages TO WARNING`
+
+ spinner.text = 'Deleting fake vessels...'
+ await sql`DELETE FROM vessels WHERE id >= ${FAKE_VESSEL_COUNT + 1} AND id <= ${FAKE_VESSEL_COUNT * 2}`
+ spinner.succeed('Fake vessels successfully deleted.')
+
+ spinner.start('Generating fake vessels...')
+ batchIndex = 1
+ while (batchIndex <= FAKE_VESSEL_BATCH_COUNT) {
+ const startIndex = (batchIndex - 1) * BATCH_SIZE + 1
+ const endIndex = batchIndex * BATCH_SIZE
+ spinner.text = `Generating fake vessels ${startIndex}->${endIndex} / ${FAKE_VESSEL_COUNT} (${Math.round((10000 * startIndex) / FAKE_VESSEL_COUNT) / 100}%)...`
+
+ const fakeVessels = BATCH_SKELETON.map((_, index) => getFakeVessel(startIndex + index))
+ await sql`INSERT INTO vessels ${sql(fakeVessels)}`
+
+ batchIndex += 1
+ }
+ spinner.succeed('Fake vessels successfully generated.')
+
+ spinner.start('Deleting fake reportings...')
+ await sql`DELETE FROM reportings WHERE id >= ${FAKE_REPORTING_COUNT + 1} AND id <= ${FAKE_REPORTING_COUNT * 2}`
+ spinner.succeed('Fake reportings successfully deleted.')
+
+ spinner.start('Generating fake reporting...')
+ batchIndex = 1
+ while (batchIndex <= FAKE_REPORTING_BATCH_COUNT) {
+ const startIndex = (batchIndex - 1) * BATCH_SIZE + 1
+ const endIndex = batchIndex * BATCH_SIZE
+ spinner.text = `Generating fake reportings ${startIndex}->${endIndex} / ${FAKE_REPORTING_COUNT} (${Math.round((10000 * startIndex) / FAKE_REPORTING_COUNT) / 100}%)...`
+
+ const fakeReportings = BATCH_SKELETON.map((_, index) => getFakeReporting(startIndex + index))
+ await sql`INSERT INTO reportings ${sql(fakeReportings)}`
+
+ batchIndex += 1
+ }
+ spinner.succeed('Fake reportings successfully generated.')
+
+ spinner.start('Deleting fake PNO logbook reports...')
+ // Prevent TimescaleDB truncate cascade notices from spamming output (`truncate cascades to table "_hyper_2_135_chunk"`)
+ await sql`SET client_min_messages TO WARNING`
+ await sql`TRUNCATE TABLE logbook_raw_messages CASCADE`
+ await sql`TRUNCATE TABLE logbook_reports`
+ await sql`RESET client_min_messages`
+ spinner.succeed('Fake PNO logbook reports successfully deleted.')
+
+ spinner.start('Generating fake PNO logbook report...')
+ batchIndex = 1
+ while (batchIndex <= FAKE_PNO_BATCH_COUNT) {
+ const startIndex = (batchIndex - 1) * BATCH_SIZE + 1
+ const endIndex = batchIndex * BATCH_SIZE
+ spinner.text = `Generating fake PNO logbook report ${startIndex}->${endIndex} / ${FAKE_PNO_COUNT} (${Math.round((10000 * startIndex) / FAKE_PNO_COUNT) / 100}%)...`
+
+ const fakeLogbookRawMessages = BATCH_SKELETON.flatMap((_, index) =>
+ getFakePnoLogbookRawMessages(startIndex + index)
+ )
+ const fakeLogbookReports = BATCH_SKELETON.flatMap((_, index) => getFakePnoLogbookReports(startIndex + index))
+
+ spinner.text = `Generating fake PNO logbook report ${startIndex}->${endIndex} / ${FAKE_PNO_COUNT} (${Math.round((10000 * startIndex) / FAKE_PNO_COUNT) / 100}%) [RANDOMNESS CHECK: ${fakeLogbookReports[0].operation_datetime_utc}]...`
+ await sql`INSERT INTO logbook_raw_messages ${sql(fakeLogbookRawMessages)}`
+ await sql`INSERT INTO logbook_reports ${sql(fakeLogbookReports)}`
+
+ batchIndex += 1
+ }
+ spinner.succeed('Fake PNO logbook report successfully generated.')
+ } catch (error) {
+ spinner.fail('Failed to generate perf data.')
+
+ console.error(error)
+
+ process.exit(1)
+ } finally {
+ await sql.end()
+ }
+}
+
+run()
diff --git a/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx b/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx
index 19b6789fc5..efa368874f 100644
--- a/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx
+++ b/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx
@@ -75,7 +75,9 @@ export function PriorNotificationList({ isFromUrl }: PriorNotificationListProps)
}
// `!!error` !== `isError` because `isError` is `false` when the query is fetching.
const { data, error, isError, isFetching } = useGetPriorNotificationsQuery(rtkQueryParams, {
- ...RTK_ONE_MINUTE_POLLING_QUERY_OPTIONS,
+ pollingInterval: 3000,
+ refetchOnMountOrArgChange: true,
+ refetchOnReconnect: true,
...RTK_FORCE_REFETCH_QUERY_OPTIONS
})
useHandleFrontendApiError(