From ce1cf8efd5dd4fc0965c8e9dab7f16df9399a45f Mon Sep 17 00:00:00 2001 From: RonniSkansing Date: Sat, 15 Aug 2026 00:52:52 +0200 Subject: [PATCH] fix bugs Signed-off-by: RonniSkansing --- .../lib/components/CampaignTrendChart.svelte | 16 ++--- .../modal/CompanyReportTemplateModal.svelte | 60 +++++++++++++++++-- .../src/routes/recipient/[id]/+page.svelte | 2 +- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/frontend/src/lib/components/CampaignTrendChart.svelte b/frontend/src/lib/components/CampaignTrendChart.svelte index 4d84524..e0976b5 100644 --- a/frontend/src/lib/components/CampaignTrendChart.svelte +++ b/frontend/src/lib/components/CampaignTrendChart.svelte @@ -114,12 +114,13 @@ visibleMetrics = { ...defaultVisibleMetrics }; } - // whenever metrics change, merge into visibleMetrics but preserve user choices. - // reassign the object to ensure svelte reactivity fires. - $: if (metrics && Array.isArray(metrics)) { + // merge the known metrics into visibleMetrics but preserve user choices. both + // chart modes are merged at once so switching mode keeps the toggles of the + // mode that is not shown. reassign the object to ensure svelte reactivity fires. + $: if (allMetrics.length > 0) { const merged = { ...visibleMetrics }; // add any newly introduced metrics (default visible) - for (const metric of metrics) { + for (const metric of allMetrics) { if (!(metric.key in merged)) { merged[metric.key] = true; } @@ -129,15 +130,15 @@ merged[mavgKey] = merged[mavgKey] ?? false; } } - // remove keys that no longer correspond to current metrics + // remove keys that no longer correspond to a known metric for (const key of Object.keys(merged)) { if (key.startsWith('mavg-')) { const base = key.slice(5); - if (!metrics.find((m) => m.key === base)) { + if (!allMetrics.find((m) => m.key === base)) { delete merged[key]; } } else { - if (!metrics.find((m) => m.key === key)) { + if (!allMetrics.find((m) => m.key === key)) { delete merged[key]; } } @@ -326,6 +327,7 @@ mavg: { color: '#69e1ab', label: 'Completed MA' } } ]; + const allMetrics = [...phishingMetrics, ...trainingMetrics]; $: metrics = chartMode === 'training' ? trainingMetrics : phishingMetrics; // toggle metric visibility (reassign to trigger svelte reactivity and persist) diff --git a/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte b/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte index b30f127..3e8a292 100644 --- a/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte +++ b/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte @@ -19,6 +19,9 @@ let error = ''; let isSubmitting = false; let loadedForCompanyID = null; + // the phishing and training reports are separate templates; edit one at a time + let rows = []; + let reportKind = 'phishing'; // 'phishing' | 'training' // reactive: load the company template when the modal opens $: { @@ -35,14 +38,12 @@ content = ''; templateID = null; error = ''; + rows = []; try { showIsLoading(); const response = await api.reportTemplate.getAll(company.id); - if (response.success && response.data?.rows?.length > 0) { - const tmpl = response.data.rows[0]; - content = tmpl.content || ''; - templateID = tmpl.id || null; - } + rows = response.success ? response.data?.rows || [] : []; + selectReportKind('phishing'); } catch (e) { console.error('Failed to load company report template:', e); error = 'Failed to load template'; @@ -51,6 +52,25 @@ } }; + // loads the cached template row for the selected kind into the editor + const selectReportKind = (kind) => { + reportKind = kind; + error = ''; + const row = rows.find((r) => !!r.isTraining === (kind === 'training')); + content = row?.content || ''; + templateID = row?.id || null; + }; + + // re-fetch the templates after a save so the active kind keeps its id + const refreshRows = async () => { + const response = await api.reportTemplate.getAll(company.id); + rows = response.success ? response.data?.rows || [] : []; + const row = rows.find((r) => !!r.isTraining === (reportKind === 'training')); + if (row?.id) { + templateID = row.id; + } + }; + const close = () => { visible = false; error = ''; @@ -67,13 +87,15 @@ } else { response = await api.reportTemplate.create({ content, - companyID: company.id + companyID: company.id, + isTraining: reportKind === 'training' }); if (response.success && response.data?.id) { templateID = response.data.id; } } if (response.success) { + await refreshRows(); addToast('Report template saved', 'Success'); if (!saveOnly) { visible = false; @@ -96,6 +118,7 @@ const response = await api.reportTemplate.delete(templateID); if (response.success) { addToast('Report template deleted', 'Success'); + rows = rows.filter((r) => r.id !== templateID); templateID = null; content = ''; visible = false; @@ -117,6 +140,31 @@
+
+ Report for +
+ + +
+
{#if templateID} diff --git a/frontend/src/routes/recipient/[id]/+page.svelte b/frontend/src/routes/recipient/[id]/+page.svelte index 2eb163f..b87e2a7 100644 --- a/frontend/src/routes/recipient/[id]/+page.svelte +++ b/frontend/src/routes/recipient/[id]/+page.svelte @@ -160,7 +160,7 @@ {/if} Export events
-
+