@dashboard-designer/ui 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.js +973 -201
- package/dist/styles.css +394 -4
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// src/designer/DashboardDesigner.tsx
|
|
2
|
-
import
|
|
2
|
+
import React13, { useEffect as useEffect13, useMemo as useMemo6, useState as useState12 } from "react";
|
|
3
3
|
import GridLayout from "react-grid-layout";
|
|
4
|
-
import { useTranslation as
|
|
4
|
+
import { useTranslation as useTranslation15 } from "react-i18next";
|
|
5
5
|
import {
|
|
6
6
|
ArrowUpLeft,
|
|
7
7
|
FileDown,
|
|
8
8
|
History as History2,
|
|
9
|
+
Mail as Mail2,
|
|
9
10
|
Pencil,
|
|
10
|
-
Plus as
|
|
11
|
+
Plus as Plus6,
|
|
11
12
|
Printer,
|
|
12
13
|
Redo2,
|
|
13
14
|
RotateCcw as RotateCcw3,
|
|
14
15
|
Save as Save2,
|
|
15
16
|
Settings2,
|
|
16
17
|
Share2,
|
|
17
|
-
Trash2 as
|
|
18
|
+
Trash2 as Trash25,
|
|
18
19
|
Undo2
|
|
19
20
|
} from "lucide-react";
|
|
20
21
|
import {
|
|
@@ -79,6 +80,11 @@ var DashboardApiClient = class {
|
|
|
79
80
|
body: JSON.stringify(connection)
|
|
80
81
|
});
|
|
81
82
|
}
|
|
83
|
+
deleteConnection(id) {
|
|
84
|
+
return this.req(`/api/connections/${id}`, {
|
|
85
|
+
method: "DELETE"
|
|
86
|
+
});
|
|
87
|
+
}
|
|
82
88
|
testConnection(id) {
|
|
83
89
|
return this.req(`/api/connections/${id}/test`, {
|
|
84
90
|
method: "POST",
|
|
@@ -150,6 +156,15 @@ var DashboardApiClient = class {
|
|
|
150
156
|
body: JSON.stringify(input)
|
|
151
157
|
});
|
|
152
158
|
}
|
|
159
|
+
emailStatus() {
|
|
160
|
+
return this.req("/api/email/status");
|
|
161
|
+
}
|
|
162
|
+
sendDashboardEmail(input) {
|
|
163
|
+
return this.req("/api/email/send", {
|
|
164
|
+
method: "POST",
|
|
165
|
+
body: JSON.stringify(input)
|
|
166
|
+
});
|
|
167
|
+
}
|
|
153
168
|
};
|
|
154
169
|
|
|
155
170
|
// src/i18n.ts
|
|
@@ -360,13 +375,55 @@ var resources = {
|
|
|
360
375
|
exportOptions: "Export & print",
|
|
361
376
|
allowPrint: "Allow print",
|
|
362
377
|
allowExportPdf: "Allow export to PDF",
|
|
378
|
+
allowEmail: "Allow send email",
|
|
379
|
+
emailAttachmentOptions: "Email attachments",
|
|
380
|
+
emailAttachPdf: "Attach dashboard PDF",
|
|
381
|
+
emailAllowExtraAttachments: "Allow additional files",
|
|
382
|
+
emailMaxExtraAttachments: "Max additional files",
|
|
363
383
|
print: "Print",
|
|
364
384
|
printDashboard: "Print dashboard",
|
|
365
385
|
exportPdf: "Export PDF",
|
|
366
386
|
exportPdfHint: "Open the print dialog and choose Save as PDF",
|
|
387
|
+
emailAction: "Email",
|
|
388
|
+
sendEmail: "Send email",
|
|
389
|
+
composeEmail: "Compose email",
|
|
390
|
+
emailTo: "To",
|
|
391
|
+
emailCc: "Cc",
|
|
392
|
+
emailSubject: "Subject",
|
|
393
|
+
emailBody: "Message",
|
|
394
|
+
emailAttachment: "Attachment",
|
|
395
|
+
emailAttachments: "Attachments",
|
|
396
|
+
emailAddAttachment: "Add file",
|
|
397
|
+
emailAttachmentPdfNote: "Generated on send",
|
|
398
|
+
emailTooManyAttachments: "You can add up to {{count}} extra files",
|
|
399
|
+
emailBodyPlaceholder: "Write your message\u2026",
|
|
400
|
+
emailFormatToolbar: "Formatting",
|
|
401
|
+
emailBold: "Bold",
|
|
402
|
+
emailItalic: "Italic",
|
|
403
|
+
emailUnderline: "Underline",
|
|
404
|
+
emailBulletList: "Bullet list",
|
|
405
|
+
emailNumberedList: "Numbered list",
|
|
406
|
+
emailInsertLink: "Insert link",
|
|
407
|
+
emailClearFormat: "Clear formatting",
|
|
408
|
+
emailLinkPrompt: "Link URL",
|
|
409
|
+
emailSending: "Sending\u2026",
|
|
410
|
+
emailSent: "Email sent",
|
|
411
|
+
emailNotConfigured: "Email is not configured on the server. Set DD_SMTP_HOST and DD_SMTP_FROM.",
|
|
412
|
+
emailComposeHint: "Compose a formatted message. A PDF of the dashboard is attached automatically; you can add more files.",
|
|
413
|
+
emailDefaultSubject: "Dashboard: {{title}}",
|
|
414
|
+
emailDefaultBody: "Please find the dashboard \u201C{{title}}\u201D attached as a PDF.",
|
|
367
415
|
helpExportOptions: "Control which export actions appear in the dashboard toolbar.",
|
|
368
416
|
helpAllowPrint: "Shows a Print button that opens the browser print dialog for this dashboard.",
|
|
369
417
|
helpAllowExportPdf: "Shows Export PDF. Uses the print dialog so charts render correctly \u2014 choose Save as PDF as the destination.",
|
|
418
|
+
helpAllowEmail: "Shows Send email in the toolbar. Requires SMTP settings on the API (DD_SMTP_*).",
|
|
419
|
+
helpEmailAttachPdf: "When enabled, Send email generates and attaches a PDF snapshot of the dashboard.",
|
|
420
|
+
helpEmailAllowExtraAttachments: "When enabled, users can add their own files in the compose dialog.",
|
|
421
|
+
helpEmailMaxExtraAttachments: "Maximum number of user-added files (0\u201310).",
|
|
422
|
+
helpEmailTo: "Recipient addresses, separated by commas.",
|
|
423
|
+
helpEmailCc: "Optional Cc recipients, separated by commas.",
|
|
424
|
+
helpEmailBody: "Format with the toolbar: bold, italic, lists, and links. Sent as HTML email.",
|
|
425
|
+
helpEmailAttachment: "A PDF snapshot of the visible dashboard canvas is generated when you click Send.",
|
|
426
|
+
helpEmailExtraAttachments: "Optional extra files (up to 5, 10MB each). Images, PDFs, and documents are supported.",
|
|
370
427
|
themeColors: "Color theme",
|
|
371
428
|
themePreset: "Theme",
|
|
372
429
|
themePresetDefault: "Default (forest)",
|
|
@@ -617,13 +674,55 @@ var resources = {
|
|
|
617
674
|
exportOptions: "Exportar e imprimir",
|
|
618
675
|
allowPrint: "Permitir imprimir",
|
|
619
676
|
allowExportPdf: "Permitir exportar a PDF",
|
|
677
|
+
allowEmail: "Permitir enviar correo",
|
|
678
|
+
emailAttachmentOptions: "Adjuntos del correo",
|
|
679
|
+
emailAttachPdf: "Adjuntar PDF del panel",
|
|
680
|
+
emailAllowExtraAttachments: "Permitir archivos adicionales",
|
|
681
|
+
emailMaxExtraAttachments: "M\xE1x. archivos adicionales",
|
|
620
682
|
print: "Imprimir",
|
|
621
683
|
printDashboard: "Imprimir panel",
|
|
622
684
|
exportPdf: "Exportar PDF",
|
|
623
685
|
exportPdfHint: "Abre el di\xE1logo de impresi\xF3n y elija Guardar como PDF",
|
|
686
|
+
emailAction: "Correo",
|
|
687
|
+
sendEmail: "Enviar correo",
|
|
688
|
+
composeEmail: "Redactar correo",
|
|
689
|
+
emailTo: "Para",
|
|
690
|
+
emailCc: "Cc",
|
|
691
|
+
emailSubject: "Asunto",
|
|
692
|
+
emailBody: "Mensaje",
|
|
693
|
+
emailAttachment: "Adjunto",
|
|
694
|
+
emailAttachments: "Adjuntos",
|
|
695
|
+
emailAddAttachment: "A\xF1adir archivo",
|
|
696
|
+
emailAttachmentPdfNote: "Se genera al enviar",
|
|
697
|
+
emailTooManyAttachments: "Puede a\xF1adir hasta {{count}} archivos extra",
|
|
698
|
+
emailBodyPlaceholder: "Escriba su mensaje\u2026",
|
|
699
|
+
emailFormatToolbar: "Formato",
|
|
700
|
+
emailBold: "Negrita",
|
|
701
|
+
emailItalic: "Cursiva",
|
|
702
|
+
emailUnderline: "Subrayado",
|
|
703
|
+
emailBulletList: "Lista con vi\xF1etas",
|
|
704
|
+
emailNumberedList: "Lista numerada",
|
|
705
|
+
emailInsertLink: "Insertar enlace",
|
|
706
|
+
emailClearFormat: "Quitar formato",
|
|
707
|
+
emailLinkPrompt: "URL del enlace",
|
|
708
|
+
emailSending: "Enviando\u2026",
|
|
709
|
+
emailSent: "Correo enviado",
|
|
710
|
+
emailNotConfigured: "El correo no est\xE1 configurado en el servidor. Defina DD_SMTP_HOST y DD_SMTP_FROM.",
|
|
711
|
+
emailComposeHint: "Redacte un mensaje con formato. Se adjunta autom\xE1ticamente un PDF del panel; puede a\xF1adir m\xE1s archivos.",
|
|
712
|
+
emailDefaultSubject: "Panel: {{title}}",
|
|
713
|
+
emailDefaultBody: "Adjunto encontrar\xE1 el panel \u201C{{title}}\u201D en PDF.",
|
|
624
714
|
helpExportOptions: "Controla qu\xE9 acciones de exportaci\xF3n aparecen en la barra del panel.",
|
|
625
715
|
helpAllowPrint: "Muestra Imprimir y abre el di\xE1logo de impresi\xF3n del navegador.",
|
|
626
716
|
helpAllowExportPdf: "Muestra Exportar PDF. Usa el di\xE1logo de impresi\xF3n para que los gr\xE1ficos se vean bien \u2014 elija Guardar como PDF.",
|
|
717
|
+
helpAllowEmail: "Muestra Enviar correo en la barra. Requiere SMTP en la API (DD_SMTP_*).",
|
|
718
|
+
helpEmailAttachPdf: "Si est\xE1 activo, Enviar correo genera y adjunta una instant\xE1nea PDF del panel.",
|
|
719
|
+
helpEmailAllowExtraAttachments: "Si est\xE1 activo, los usuarios pueden a\xF1adir archivos en el di\xE1logo de composici\xF3n.",
|
|
720
|
+
helpEmailMaxExtraAttachments: "N\xFAmero m\xE1ximo de archivos a\xF1adidos por el usuario (0\u201310).",
|
|
721
|
+
helpEmailTo: "Direcciones de destinatario, separadas por comas.",
|
|
722
|
+
helpEmailCc: "Destinatarios en copia (opcional), separados por comas.",
|
|
723
|
+
helpEmailBody: "Use la barra para negrita, cursiva, listas y enlaces. Se env\xEDa como HTML.",
|
|
724
|
+
helpEmailAttachment: "Al pulsar Enviar se genera una instant\xE1nea PDF del lienzo visible del panel.",
|
|
725
|
+
helpEmailExtraAttachments: "Archivos opcionales (hasta 5, 10 MB cada uno). Se admiten im\xE1genes, PDF y documentos.",
|
|
627
726
|
themeColors: "Tema de color",
|
|
628
727
|
themePreset: "Tema",
|
|
629
728
|
themePresetDefault: "Predeterminado (bosque)",
|
|
@@ -3533,17 +3632,581 @@ function SharePanel({ open, onClose, dashboardId, api }) {
|
|
|
3533
3632
|
) });
|
|
3534
3633
|
}
|
|
3535
3634
|
|
|
3536
|
-
// src/designer/
|
|
3537
|
-
import { useEffect as
|
|
3538
|
-
import {
|
|
3635
|
+
// src/designer/EmailComposePanel.tsx
|
|
3636
|
+
import { useEffect as useEffect10, useId as useId5, useRef as useRef7, useState as useState9 } from "react";
|
|
3637
|
+
import { Mail, Paperclip, Plus as Plus4, Trash2 as Trash23, X as X7 } from "lucide-react";
|
|
3638
|
+
import { useTranslation as useTranslation13 } from "react-i18next";
|
|
3639
|
+
import { resolveEmailOptions } from "@dashboard-designer/core";
|
|
3640
|
+
|
|
3641
|
+
// src/components/RichTextEditor.tsx
|
|
3642
|
+
import { useEffect as useEffect9, useRef as useRef6 } from "react";
|
|
3643
|
+
import {
|
|
3644
|
+
Bold,
|
|
3645
|
+
Italic,
|
|
3646
|
+
Link2 as Link22,
|
|
3647
|
+
List,
|
|
3648
|
+
ListOrdered,
|
|
3649
|
+
RemoveFormatting,
|
|
3650
|
+
Underline
|
|
3651
|
+
} from "lucide-react";
|
|
3539
3652
|
import { useTranslation as useTranslation12 } from "react-i18next";
|
|
3653
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3654
|
+
function escapeHtml(text) {
|
|
3655
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3656
|
+
}
|
|
3657
|
+
function plainTextToEmailHtml(text) {
|
|
3658
|
+
const trimmed = text.trim();
|
|
3659
|
+
if (!trimmed) return "<p><br></p>";
|
|
3660
|
+
if (/<[a-z][\s\S]*>/i.test(trimmed)) return trimmed;
|
|
3661
|
+
return trimmed.split(/\n{2,}/).map((block) => `<p>${escapeHtml(block).replace(/\n/g, "<br>")}</p>`).join("");
|
|
3662
|
+
}
|
|
3663
|
+
function htmlToPlainText(html) {
|
|
3664
|
+
if (typeof document === "undefined") {
|
|
3665
|
+
return html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
3666
|
+
}
|
|
3667
|
+
const el = document.createElement("div");
|
|
3668
|
+
el.innerHTML = html;
|
|
3669
|
+
return (el.innerText || el.textContent || "").replace(/\u00a0/g, " ").trim();
|
|
3670
|
+
}
|
|
3671
|
+
function runCommand(command, value) {
|
|
3672
|
+
document.execCommand(command, false, value);
|
|
3673
|
+
}
|
|
3674
|
+
function RichTextEditor({
|
|
3675
|
+
id,
|
|
3676
|
+
valueHtml,
|
|
3677
|
+
onChange,
|
|
3678
|
+
disabled,
|
|
3679
|
+
placeholder
|
|
3680
|
+
}) {
|
|
3681
|
+
const { t } = useTranslation12();
|
|
3682
|
+
const ref = useRef6(null);
|
|
3683
|
+
const lastEmitted = useRef6(valueHtml);
|
|
3684
|
+
useEffect9(() => {
|
|
3685
|
+
const el = ref.current;
|
|
3686
|
+
if (!el) return;
|
|
3687
|
+
if (valueHtml !== lastEmitted.current && el.innerHTML !== valueHtml) {
|
|
3688
|
+
el.innerHTML = valueHtml || "<p><br></p>";
|
|
3689
|
+
lastEmitted.current = valueHtml;
|
|
3690
|
+
}
|
|
3691
|
+
}, [valueHtml]);
|
|
3692
|
+
const emit = () => {
|
|
3693
|
+
const el = ref.current;
|
|
3694
|
+
if (!el) return;
|
|
3695
|
+
const html = el.innerHTML;
|
|
3696
|
+
lastEmitted.current = html;
|
|
3697
|
+
onChange(html);
|
|
3698
|
+
};
|
|
3699
|
+
const format = (command, value) => {
|
|
3700
|
+
if (disabled) return;
|
|
3701
|
+
ref.current?.focus();
|
|
3702
|
+
runCommand(command, value);
|
|
3703
|
+
emit();
|
|
3704
|
+
};
|
|
3705
|
+
const addLink = () => {
|
|
3706
|
+
if (disabled) return;
|
|
3707
|
+
const url = window.prompt(t("emailLinkPrompt"), "https://");
|
|
3708
|
+
if (!url) return;
|
|
3709
|
+
format("createLink", url);
|
|
3710
|
+
};
|
|
3711
|
+
return /* @__PURE__ */ jsxs12("div", { className: `dd-rte${disabled ? " is-disabled" : ""}`, children: [
|
|
3712
|
+
/* @__PURE__ */ jsxs12("div", { className: "dd-rte-toolbar", role: "toolbar", "aria-label": t("emailFormatToolbar"), children: [
|
|
3713
|
+
/* @__PURE__ */ jsx12(
|
|
3714
|
+
"button",
|
|
3715
|
+
{
|
|
3716
|
+
type: "button",
|
|
3717
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3718
|
+
title: t("emailBold"),
|
|
3719
|
+
"aria-label": t("emailBold"),
|
|
3720
|
+
disabled,
|
|
3721
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3722
|
+
onClick: () => format("bold"),
|
|
3723
|
+
children: /* @__PURE__ */ jsx12(Bold, { size: ICON_SIZE })
|
|
3724
|
+
}
|
|
3725
|
+
),
|
|
3726
|
+
/* @__PURE__ */ jsx12(
|
|
3727
|
+
"button",
|
|
3728
|
+
{
|
|
3729
|
+
type: "button",
|
|
3730
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3731
|
+
title: t("emailItalic"),
|
|
3732
|
+
"aria-label": t("emailItalic"),
|
|
3733
|
+
disabled,
|
|
3734
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3735
|
+
onClick: () => format("italic"),
|
|
3736
|
+
children: /* @__PURE__ */ jsx12(Italic, { size: ICON_SIZE })
|
|
3737
|
+
}
|
|
3738
|
+
),
|
|
3739
|
+
/* @__PURE__ */ jsx12(
|
|
3740
|
+
"button",
|
|
3741
|
+
{
|
|
3742
|
+
type: "button",
|
|
3743
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3744
|
+
title: t("emailUnderline"),
|
|
3745
|
+
"aria-label": t("emailUnderline"),
|
|
3746
|
+
disabled,
|
|
3747
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3748
|
+
onClick: () => format("underline"),
|
|
3749
|
+
children: /* @__PURE__ */ jsx12(Underline, { size: ICON_SIZE })
|
|
3750
|
+
}
|
|
3751
|
+
),
|
|
3752
|
+
/* @__PURE__ */ jsx12("span", { className: "dd-rte-sep", "aria-hidden": true }),
|
|
3753
|
+
/* @__PURE__ */ jsx12(
|
|
3754
|
+
"button",
|
|
3755
|
+
{
|
|
3756
|
+
type: "button",
|
|
3757
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3758
|
+
title: t("emailBulletList"),
|
|
3759
|
+
"aria-label": t("emailBulletList"),
|
|
3760
|
+
disabled,
|
|
3761
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3762
|
+
onClick: () => format("insertUnorderedList"),
|
|
3763
|
+
children: /* @__PURE__ */ jsx12(List, { size: ICON_SIZE })
|
|
3764
|
+
}
|
|
3765
|
+
),
|
|
3766
|
+
/* @__PURE__ */ jsx12(
|
|
3767
|
+
"button",
|
|
3768
|
+
{
|
|
3769
|
+
type: "button",
|
|
3770
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3771
|
+
title: t("emailNumberedList"),
|
|
3772
|
+
"aria-label": t("emailNumberedList"),
|
|
3773
|
+
disabled,
|
|
3774
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3775
|
+
onClick: () => format("insertOrderedList"),
|
|
3776
|
+
children: /* @__PURE__ */ jsx12(ListOrdered, { size: ICON_SIZE })
|
|
3777
|
+
}
|
|
3778
|
+
),
|
|
3779
|
+
/* @__PURE__ */ jsx12("span", { className: "dd-rte-sep", "aria-hidden": true }),
|
|
3780
|
+
/* @__PURE__ */ jsx12(
|
|
3781
|
+
"button",
|
|
3782
|
+
{
|
|
3783
|
+
type: "button",
|
|
3784
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3785
|
+
title: t("emailInsertLink"),
|
|
3786
|
+
"aria-label": t("emailInsertLink"),
|
|
3787
|
+
disabled,
|
|
3788
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3789
|
+
onClick: addLink,
|
|
3790
|
+
children: /* @__PURE__ */ jsx12(Link22, { size: ICON_SIZE })
|
|
3791
|
+
}
|
|
3792
|
+
),
|
|
3793
|
+
/* @__PURE__ */ jsx12(
|
|
3794
|
+
"button",
|
|
3795
|
+
{
|
|
3796
|
+
type: "button",
|
|
3797
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3798
|
+
title: t("emailClearFormat"),
|
|
3799
|
+
"aria-label": t("emailClearFormat"),
|
|
3800
|
+
disabled,
|
|
3801
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3802
|
+
onClick: () => format("removeFormat"),
|
|
3803
|
+
children: /* @__PURE__ */ jsx12(RemoveFormatting, { size: ICON_SIZE })
|
|
3804
|
+
}
|
|
3805
|
+
)
|
|
3806
|
+
] }),
|
|
3807
|
+
/* @__PURE__ */ jsx12(
|
|
3808
|
+
"div",
|
|
3809
|
+
{
|
|
3810
|
+
id,
|
|
3811
|
+
ref,
|
|
3812
|
+
className: "dd-rte-editor dd-input",
|
|
3813
|
+
contentEditable: !disabled,
|
|
3814
|
+
role: "textbox",
|
|
3815
|
+
"aria-multiline": "true",
|
|
3816
|
+
"data-placeholder": placeholder,
|
|
3817
|
+
suppressContentEditableWarning: true,
|
|
3818
|
+
onInput: emit,
|
|
3819
|
+
onBlur: emit
|
|
3820
|
+
}
|
|
3821
|
+
)
|
|
3822
|
+
] });
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
// src/export/captureDashboardPdf.ts
|
|
3826
|
+
import html2canvas from "html2canvas";
|
|
3827
|
+
import { jsPDF } from "jspdf";
|
|
3828
|
+
function slugifyTitle2(title) {
|
|
3829
|
+
const s = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3830
|
+
return s || "dashboard";
|
|
3831
|
+
}
|
|
3832
|
+
function blobToBase64(blob) {
|
|
3833
|
+
return new Promise((resolve, reject) => {
|
|
3834
|
+
const reader = new FileReader();
|
|
3835
|
+
reader.onload = () => {
|
|
3836
|
+
const result = String(reader.result || "");
|
|
3837
|
+
const comma = result.indexOf(",");
|
|
3838
|
+
resolve(comma >= 0 ? result.slice(comma + 1) : result);
|
|
3839
|
+
};
|
|
3840
|
+
reader.onerror = () => reject(reader.error || new Error("Failed to read PDF"));
|
|
3841
|
+
reader.readAsDataURL(blob);
|
|
3842
|
+
});
|
|
3843
|
+
}
|
|
3844
|
+
async function captureDashboardPdfAttachment(canvasEl, title) {
|
|
3845
|
+
if (!canvasEl) {
|
|
3846
|
+
throw new Error("Dashboard canvas not found. Close this dialog and try again.");
|
|
3847
|
+
}
|
|
3848
|
+
const shot = await html2canvas(canvasEl, {
|
|
3849
|
+
scale: Math.min(2, window.devicePixelRatio || 1.5),
|
|
3850
|
+
useCORS: true,
|
|
3851
|
+
allowTaint: true,
|
|
3852
|
+
logging: false,
|
|
3853
|
+
backgroundColor: "#ffffff",
|
|
3854
|
+
scrollX: 0,
|
|
3855
|
+
scrollY: -window.scrollY
|
|
3856
|
+
});
|
|
3857
|
+
const imgWidthPx = shot.width;
|
|
3858
|
+
const imgHeightPx = shot.height;
|
|
3859
|
+
if (imgWidthPx < 8 || imgHeightPx < 8) {
|
|
3860
|
+
throw new Error("Could not capture dashboard for PDF");
|
|
3861
|
+
}
|
|
3862
|
+
const orientation = imgWidthPx >= imgHeightPx ? "landscape" : "portrait";
|
|
3863
|
+
const pdf = new jsPDF({ orientation, unit: "pt", format: "a4", compress: true });
|
|
3864
|
+
const pageWidth = pdf.internal.pageSize.getWidth();
|
|
3865
|
+
const pageHeight = pdf.internal.pageSize.getHeight();
|
|
3866
|
+
const margin = 24;
|
|
3867
|
+
const usableWidth = pageWidth - margin * 2;
|
|
3868
|
+
const usableHeight = pageHeight - margin * 2;
|
|
3869
|
+
const scale = usableWidth / imgWidthPx;
|
|
3870
|
+
const pageSliceHeightPx = usableHeight / scale;
|
|
3871
|
+
let yPx = 0;
|
|
3872
|
+
let pageIndex = 0;
|
|
3873
|
+
while (yPx < imgHeightPx - 0.5) {
|
|
3874
|
+
if (pageIndex > 0) pdf.addPage();
|
|
3875
|
+
const sliceHeightPx = Math.min(pageSliceHeightPx, imgHeightPx - yPx);
|
|
3876
|
+
const sliceCanvas = document.createElement("canvas");
|
|
3877
|
+
sliceCanvas.width = imgWidthPx;
|
|
3878
|
+
sliceCanvas.height = Math.max(1, Math.ceil(sliceHeightPx));
|
|
3879
|
+
const ctx = sliceCanvas.getContext("2d");
|
|
3880
|
+
if (!ctx) throw new Error("Could not create PDF page");
|
|
3881
|
+
ctx.fillStyle = "#ffffff";
|
|
3882
|
+
ctx.fillRect(0, 0, sliceCanvas.width, sliceCanvas.height);
|
|
3883
|
+
ctx.drawImage(
|
|
3884
|
+
shot,
|
|
3885
|
+
0,
|
|
3886
|
+
yPx,
|
|
3887
|
+
imgWidthPx,
|
|
3888
|
+
sliceHeightPx,
|
|
3889
|
+
0,
|
|
3890
|
+
0,
|
|
3891
|
+
imgWidthPx,
|
|
3892
|
+
sliceHeightPx
|
|
3893
|
+
);
|
|
3894
|
+
const sliceData = sliceCanvas.toDataURL("image/jpeg", 0.92);
|
|
3895
|
+
const sliceRenderHeight = sliceHeightPx * scale;
|
|
3896
|
+
pdf.addImage(sliceData, "JPEG", margin, margin, usableWidth, sliceRenderHeight);
|
|
3897
|
+
yPx += sliceHeightPx;
|
|
3898
|
+
pageIndex += 1;
|
|
3899
|
+
if (pageIndex > 40) break;
|
|
3900
|
+
}
|
|
3901
|
+
const blob = pdf.output("blob");
|
|
3902
|
+
const contentBase64 = await blobToBase64(blob);
|
|
3903
|
+
return {
|
|
3904
|
+
filename: `${slugifyTitle2(title)}.pdf`,
|
|
3905
|
+
contentType: "application/pdf",
|
|
3906
|
+
contentBase64,
|
|
3907
|
+
byteLength: blob.size
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3910
|
+
|
|
3911
|
+
// src/designer/EmailComposePanel.tsx
|
|
3912
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3913
|
+
var MAX_EXTRA_BYTES = 10 * 1024 * 1024;
|
|
3914
|
+
function slugify(title) {
|
|
3915
|
+
const s = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3916
|
+
return s || "dashboard";
|
|
3917
|
+
}
|
|
3918
|
+
function readFileAsAttachment(file) {
|
|
3919
|
+
return new Promise((resolve, reject) => {
|
|
3920
|
+
if (file.size > MAX_EXTRA_BYTES) {
|
|
3921
|
+
reject(new Error(`File \u201C${file.name}\u201D exceeds 10MB`));
|
|
3922
|
+
return;
|
|
3923
|
+
}
|
|
3924
|
+
const reader = new FileReader();
|
|
3925
|
+
reader.onload = () => {
|
|
3926
|
+
const result = String(reader.result || "");
|
|
3927
|
+
const comma = result.indexOf(",");
|
|
3928
|
+
const contentBase64 = comma >= 0 ? result.slice(comma + 1) : result;
|
|
3929
|
+
resolve({
|
|
3930
|
+
id: crypto.randomUUID(),
|
|
3931
|
+
filename: file.name,
|
|
3932
|
+
contentType: file.type || "application/octet-stream",
|
|
3933
|
+
contentBase64
|
|
3934
|
+
});
|
|
3935
|
+
};
|
|
3936
|
+
reader.onerror = () => reject(reader.error || new Error(`Failed to read ${file.name}`));
|
|
3937
|
+
reader.readAsDataURL(file);
|
|
3938
|
+
});
|
|
3939
|
+
}
|
|
3940
|
+
function EmailComposePanel({
|
|
3941
|
+
open,
|
|
3942
|
+
onClose,
|
|
3943
|
+
dashboard,
|
|
3944
|
+
api,
|
|
3945
|
+
canvasElementId = "dd-canvas"
|
|
3946
|
+
}) {
|
|
3947
|
+
const { t } = useTranslation13();
|
|
3948
|
+
const fileInputId = useId5();
|
|
3949
|
+
const fileInputRef = useRef7(null);
|
|
3950
|
+
const emailOpts = resolveEmailOptions(dashboard.exportOptions);
|
|
3951
|
+
const maxExtra = emailOpts.maxExtraAttachments;
|
|
3952
|
+
const [to, setTo] = useState9("");
|
|
3953
|
+
const [cc, setCc] = useState9("");
|
|
3954
|
+
const [subject, setSubject] = useState9("");
|
|
3955
|
+
const [bodyHtml, setBodyHtml] = useState9("<p><br></p>");
|
|
3956
|
+
const [extraAttachments, setExtraAttachments] = useState9([]);
|
|
3957
|
+
const [configured, setConfigured] = useState9(null);
|
|
3958
|
+
const [sending, setSending] = useState9(false);
|
|
3959
|
+
const [error, setError] = useState9(null);
|
|
3960
|
+
const [success, setSuccess] = useState9(null);
|
|
3961
|
+
const dashboardPdfName = `${slugify(dashboard.title)}.pdf`;
|
|
3962
|
+
const showAttachments = emailOpts.attachPdf || emailOpts.allowExtraAttachments && maxExtra > 0;
|
|
3963
|
+
useEffect10(() => {
|
|
3964
|
+
if (!open) return;
|
|
3965
|
+
setError(null);
|
|
3966
|
+
setSuccess(null);
|
|
3967
|
+
setTo("");
|
|
3968
|
+
setCc("");
|
|
3969
|
+
setSubject(t("emailDefaultSubject", { title: dashboard.title }));
|
|
3970
|
+
setBodyHtml(plainTextToEmailHtml(t("emailDefaultBody", { title: dashboard.title })));
|
|
3971
|
+
setExtraAttachments([]);
|
|
3972
|
+
setConfigured(null);
|
|
3973
|
+
api.emailStatus().then((r) => setConfigured(r.configured)).catch(() => setConfigured(false));
|
|
3974
|
+
}, [open, dashboard.id, dashboard.title, api, t]);
|
|
3975
|
+
if (!open) return null;
|
|
3976
|
+
const addFiles = async (files) => {
|
|
3977
|
+
if (!files?.length || !emailOpts.allowExtraAttachments) return;
|
|
3978
|
+
setError(null);
|
|
3979
|
+
try {
|
|
3980
|
+
const remaining = maxExtra - extraAttachments.length;
|
|
3981
|
+
if (remaining <= 0) {
|
|
3982
|
+
setError(t("emailTooManyAttachments", { count: maxExtra }));
|
|
3983
|
+
return;
|
|
3984
|
+
}
|
|
3985
|
+
const picked = Array.from(files).slice(0, remaining);
|
|
3986
|
+
const loaded = await Promise.all(picked.map(readFileAsAttachment));
|
|
3987
|
+
setExtraAttachments((prev) => [...prev, ...loaded]);
|
|
3988
|
+
} catch (err) {
|
|
3989
|
+
setError(err.message);
|
|
3990
|
+
} finally {
|
|
3991
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
3992
|
+
}
|
|
3993
|
+
};
|
|
3994
|
+
const removeExtra = (id) => {
|
|
3995
|
+
setExtraAttachments((prev) => prev.filter((a) => a.id !== id));
|
|
3996
|
+
};
|
|
3997
|
+
const send = async () => {
|
|
3998
|
+
setSending(true);
|
|
3999
|
+
setError(null);
|
|
4000
|
+
setSuccess(null);
|
|
4001
|
+
try {
|
|
4002
|
+
let attachment;
|
|
4003
|
+
if (emailOpts.attachPdf) {
|
|
4004
|
+
const canvas = document.getElementById(canvasElementId);
|
|
4005
|
+
const pdf = await captureDashboardPdfAttachment(canvas, dashboard.title);
|
|
4006
|
+
attachment = {
|
|
4007
|
+
filename: pdf.filename,
|
|
4008
|
+
contentType: pdf.contentType,
|
|
4009
|
+
contentBase64: pdf.contentBase64
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
const extras = emailOpts.allowExtraAttachments ? extraAttachments.slice(0, maxExtra).map(({ filename, contentType, contentBase64 }) => ({
|
|
4013
|
+
filename,
|
|
4014
|
+
contentType,
|
|
4015
|
+
contentBase64
|
|
4016
|
+
})) : [];
|
|
4017
|
+
const plain = htmlToPlainText(bodyHtml);
|
|
4018
|
+
await api.sendDashboardEmail({
|
|
4019
|
+
to,
|
|
4020
|
+
cc: cc.trim() || void 0,
|
|
4021
|
+
subject,
|
|
4022
|
+
body: plain,
|
|
4023
|
+
bodyHtml,
|
|
4024
|
+
dashboardTitle: dashboard.title,
|
|
4025
|
+
attachment,
|
|
4026
|
+
extraAttachments: extras.length ? extras : void 0
|
|
4027
|
+
});
|
|
4028
|
+
setSuccess(t("emailSent"));
|
|
4029
|
+
} catch (err) {
|
|
4030
|
+
setError(err.message);
|
|
4031
|
+
} finally {
|
|
4032
|
+
setSending(false);
|
|
4033
|
+
}
|
|
4034
|
+
};
|
|
4035
|
+
return /* @__PURE__ */ jsx13("div", { className: "dd-modal-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs13(
|
|
4036
|
+
"div",
|
|
4037
|
+
{
|
|
4038
|
+
className: "dd-dialog dd-email-panel",
|
|
4039
|
+
role: "dialog",
|
|
4040
|
+
"aria-modal": "true",
|
|
4041
|
+
"aria-labelledby": "dd-email-title",
|
|
4042
|
+
onClick: (e) => e.stopPropagation(),
|
|
4043
|
+
children: [
|
|
4044
|
+
/* @__PURE__ */ jsxs13("header", { className: "dd-dialog-header", children: [
|
|
4045
|
+
/* @__PURE__ */ jsxs13("h2", { id: "dd-email-title", children: [
|
|
4046
|
+
/* @__PURE__ */ jsx13(Mail, { size: ICON_SIZE, "aria-hidden": true }),
|
|
4047
|
+
" ",
|
|
4048
|
+
t("composeEmail")
|
|
4049
|
+
] }),
|
|
4050
|
+
/* @__PURE__ */ jsx13(
|
|
4051
|
+
"button",
|
|
4052
|
+
{
|
|
4053
|
+
type: "button",
|
|
4054
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
4055
|
+
onClick: onClose,
|
|
4056
|
+
"aria-label": t("cancel"),
|
|
4057
|
+
children: /* @__PURE__ */ jsx13(X7, { size: ICON_SIZE })
|
|
4058
|
+
}
|
|
4059
|
+
)
|
|
4060
|
+
] }),
|
|
4061
|
+
/* @__PURE__ */ jsxs13("div", { className: "dd-dialog-body dd-email-body-wrap", children: [
|
|
4062
|
+
configured === false && /* @__PURE__ */ jsx13("p", { className: "dd-error", role: "alert", children: t("emailNotConfigured") }),
|
|
4063
|
+
/* @__PURE__ */ jsx13("p", { className: "dd-hint", children: t("emailComposeHint") }),
|
|
4064
|
+
/* @__PURE__ */ jsxs13("div", { className: "dd-field", children: [
|
|
4065
|
+
/* @__PURE__ */ jsx13(FieldLabel, { htmlFor: "dd-email-to", help: t("helpEmailTo"), children: t("emailTo") }),
|
|
4066
|
+
/* @__PURE__ */ jsx13(
|
|
4067
|
+
"input",
|
|
4068
|
+
{
|
|
4069
|
+
id: "dd-email-to",
|
|
4070
|
+
className: "dd-input",
|
|
4071
|
+
type: "text",
|
|
4072
|
+
value: to,
|
|
4073
|
+
onChange: (e) => setTo(e.target.value),
|
|
4074
|
+
placeholder: "name@example.com",
|
|
4075
|
+
autoComplete: "email"
|
|
4076
|
+
}
|
|
4077
|
+
)
|
|
4078
|
+
] }),
|
|
4079
|
+
/* @__PURE__ */ jsxs13("div", { className: "dd-field", children: [
|
|
4080
|
+
/* @__PURE__ */ jsx13(FieldLabel, { htmlFor: "dd-email-cc", help: t("helpEmailCc"), children: t("emailCc") }),
|
|
4081
|
+
/* @__PURE__ */ jsx13(
|
|
4082
|
+
"input",
|
|
4083
|
+
{
|
|
4084
|
+
id: "dd-email-cc",
|
|
4085
|
+
className: "dd-input",
|
|
4086
|
+
type: "text",
|
|
4087
|
+
value: cc,
|
|
4088
|
+
onChange: (e) => setCc(e.target.value),
|
|
4089
|
+
placeholder: "optional",
|
|
4090
|
+
autoComplete: "email"
|
|
4091
|
+
}
|
|
4092
|
+
)
|
|
4093
|
+
] }),
|
|
4094
|
+
/* @__PURE__ */ jsxs13("div", { className: "dd-field", children: [
|
|
4095
|
+
/* @__PURE__ */ jsx13(FieldLabel, { htmlFor: "dd-email-subject", children: t("emailSubject") }),
|
|
4096
|
+
/* @__PURE__ */ jsx13(
|
|
4097
|
+
"input",
|
|
4098
|
+
{
|
|
4099
|
+
id: "dd-email-subject",
|
|
4100
|
+
className: "dd-input",
|
|
4101
|
+
type: "text",
|
|
4102
|
+
value: subject,
|
|
4103
|
+
onChange: (e) => setSubject(e.target.value)
|
|
4104
|
+
}
|
|
4105
|
+
)
|
|
4106
|
+
] }),
|
|
4107
|
+
/* @__PURE__ */ jsxs13("div", { className: "dd-field", children: [
|
|
4108
|
+
/* @__PURE__ */ jsx13(FieldLabel, { htmlFor: "dd-email-body", help: t("helpEmailBody"), children: t("emailBody") }),
|
|
4109
|
+
/* @__PURE__ */ jsx13(
|
|
4110
|
+
RichTextEditor,
|
|
4111
|
+
{
|
|
4112
|
+
id: "dd-email-body",
|
|
4113
|
+
valueHtml: bodyHtml,
|
|
4114
|
+
onChange: setBodyHtml,
|
|
4115
|
+
disabled: sending,
|
|
4116
|
+
placeholder: t("emailBodyPlaceholder")
|
|
4117
|
+
}
|
|
4118
|
+
)
|
|
4119
|
+
] }),
|
|
4120
|
+
showAttachments && /* @__PURE__ */ jsxs13("div", { className: "dd-field dd-email-attachment-field", children: [
|
|
4121
|
+
/* @__PURE__ */ jsx13(FieldLabel, { help: t("helpEmailAttachment"), children: t("emailAttachments") }),
|
|
4122
|
+
/* @__PURE__ */ jsxs13("ul", { className: "dd-email-attach-list", children: [
|
|
4123
|
+
emailOpts.attachPdf && /* @__PURE__ */ jsxs13("li", { className: "dd-email-attachment", children: [
|
|
4124
|
+
/* @__PURE__ */ jsx13(Paperclip, { size: ICON_SIZE, "aria-hidden": true }),
|
|
4125
|
+
/* @__PURE__ */ jsx13("code", { children: dashboardPdfName }),
|
|
4126
|
+
/* @__PURE__ */ jsx13("span", { className: "dd-muted dd-email-attachment-note", children: t("emailAttachmentPdfNote") })
|
|
4127
|
+
] }),
|
|
4128
|
+
emailOpts.allowExtraAttachments && extraAttachments.map((file) => /* @__PURE__ */ jsxs13("li", { className: "dd-email-attachment", children: [
|
|
4129
|
+
/* @__PURE__ */ jsx13(Paperclip, { size: ICON_SIZE, "aria-hidden": true }),
|
|
4130
|
+
/* @__PURE__ */ jsx13("code", { title: file.filename, children: file.filename }),
|
|
4131
|
+
/* @__PURE__ */ jsx13(
|
|
4132
|
+
"button",
|
|
4133
|
+
{
|
|
4134
|
+
type: "button",
|
|
4135
|
+
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
4136
|
+
title: t("remove"),
|
|
4137
|
+
"aria-label": t("remove"),
|
|
4138
|
+
disabled: sending,
|
|
4139
|
+
onClick: () => removeExtra(file.id),
|
|
4140
|
+
children: /* @__PURE__ */ jsx13(Trash23, { size: ICON_SIZE })
|
|
4141
|
+
}
|
|
4142
|
+
)
|
|
4143
|
+
] }, file.id))
|
|
4144
|
+
] }),
|
|
4145
|
+
emailOpts.allowExtraAttachments && maxExtra > 0 && /* @__PURE__ */ jsxs13("div", { className: "dd-email-attach-actions", children: [
|
|
4146
|
+
/* @__PURE__ */ jsx13(
|
|
4147
|
+
"input",
|
|
4148
|
+
{
|
|
4149
|
+
ref: fileInputRef,
|
|
4150
|
+
id: fileInputId,
|
|
4151
|
+
type: "file",
|
|
4152
|
+
multiple: true,
|
|
4153
|
+
className: "dd-visually-hidden",
|
|
4154
|
+
onChange: (e) => void addFiles(e.target.files),
|
|
4155
|
+
disabled: sending || extraAttachments.length >= maxExtra
|
|
4156
|
+
}
|
|
4157
|
+
),
|
|
4158
|
+
/* @__PURE__ */ jsxs13(
|
|
4159
|
+
"button",
|
|
4160
|
+
{
|
|
4161
|
+
type: "button",
|
|
4162
|
+
className: "dd-btn",
|
|
4163
|
+
disabled: sending || extraAttachments.length >= maxExtra,
|
|
4164
|
+
onClick: () => fileInputRef.current?.click(),
|
|
4165
|
+
children: [
|
|
4166
|
+
/* @__PURE__ */ jsx13(Plus4, { size: ICON_SIZE }),
|
|
4167
|
+
t("emailAddAttachment")
|
|
4168
|
+
]
|
|
4169
|
+
}
|
|
4170
|
+
),
|
|
4171
|
+
/* @__PURE__ */ jsx13(FieldHelp, { text: t("helpEmailExtraAttachments") })
|
|
4172
|
+
] })
|
|
4173
|
+
] }),
|
|
4174
|
+
error && /* @__PURE__ */ jsx13("p", { className: "dd-error", role: "alert", children: error }),
|
|
4175
|
+
success && /* @__PURE__ */ jsx13("p", { className: "dd-status-ok", role: "status", children: success })
|
|
4176
|
+
] }),
|
|
4177
|
+
/* @__PURE__ */ jsx13("footer", { className: "dd-dialog-footer", children: /* @__PURE__ */ jsxs13("div", { className: "dd-dialog-footer-end", children: [
|
|
4178
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "dd-btn", onClick: onClose, disabled: sending, children: t("cancel") }),
|
|
4179
|
+
/* @__PURE__ */ jsxs13(
|
|
4180
|
+
"button",
|
|
4181
|
+
{
|
|
4182
|
+
type: "button",
|
|
4183
|
+
className: "dd-btn dd-btn-primary",
|
|
4184
|
+
onClick: () => void send(),
|
|
4185
|
+
disabled: sending || !to.trim() || !subject.trim() || configured === false,
|
|
4186
|
+
children: [
|
|
4187
|
+
/* @__PURE__ */ jsx13(Mail, { size: ICON_SIZE }),
|
|
4188
|
+
sending ? t("emailSending") : t("sendEmail")
|
|
4189
|
+
]
|
|
4190
|
+
}
|
|
4191
|
+
)
|
|
4192
|
+
] }) })
|
|
4193
|
+
]
|
|
4194
|
+
}
|
|
4195
|
+
) });
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
// src/designer/DashboardSettingsPanel.tsx
|
|
4199
|
+
import { useEffect as useEffect11, useMemo as useMemo5, useState as useState10 } from "react";
|
|
4200
|
+
import { Plus as Plus5, RotateCcw as RotateCcw2, Trash2 as Trash24, X as X8 } from "lucide-react";
|
|
4201
|
+
import { useTranslation as useTranslation14 } from "react-i18next";
|
|
3540
4202
|
import {
|
|
3541
4203
|
matchThemePreset,
|
|
3542
4204
|
resolveDashboardTheme as resolveDashboardTheme2,
|
|
4205
|
+
resolveEmailOptions as resolveEmailOptions2,
|
|
3543
4206
|
resolveExportOptions,
|
|
3544
4207
|
THEME_PRESETS
|
|
3545
4208
|
} from "@dashboard-designer/core";
|
|
3546
|
-
import { jsx as
|
|
4209
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3547
4210
|
var CURRENCIES = ["USD", "EUR", "GBP", "INR", "JPY", "CAD", "AUD", "MXN"];
|
|
3548
4211
|
var TIMEZONES = [
|
|
3549
4212
|
"UTC",
|
|
@@ -3559,6 +4222,7 @@ var TIMEZONES = [
|
|
|
3559
4222
|
function draftFromDashboard(dashboard) {
|
|
3560
4223
|
const theme = resolveDashboardTheme2(dashboard.theme);
|
|
3561
4224
|
const exportOpts = resolveExportOptions(dashboard.exportOptions);
|
|
4225
|
+
const emailOpts = resolveEmailOptions2(dashboard.exportOptions);
|
|
3562
4226
|
return {
|
|
3563
4227
|
locale: dashboard.locale || "en",
|
|
3564
4228
|
currency: dashboard.currency || "USD",
|
|
@@ -3567,9 +4231,16 @@ function draftFromDashboard(dashboard) {
|
|
|
3567
4231
|
accent: theme.accent,
|
|
3568
4232
|
chartColors: [...theme.chartColors],
|
|
3569
4233
|
allowPrint: exportOpts.print,
|
|
3570
|
-
allowPdf: exportOpts.pdf
|
|
4234
|
+
allowPdf: exportOpts.pdf,
|
|
4235
|
+
allowEmail: exportOpts.email,
|
|
4236
|
+
emailAttachPdf: emailOpts.attachPdf,
|
|
4237
|
+
emailAllowExtra: emailOpts.allowExtraAttachments,
|
|
4238
|
+
emailMaxExtra: emailOpts.maxExtraAttachments
|
|
3571
4239
|
};
|
|
3572
4240
|
}
|
|
4241
|
+
function isDefaultEmailOptions(draft) {
|
|
4242
|
+
return draft.emailAttachPdf && draft.emailAllowExtra && draft.emailMaxExtra === 5;
|
|
4243
|
+
}
|
|
3573
4244
|
function normalizeHex(value, fallback) {
|
|
3574
4245
|
const v = value.trim();
|
|
3575
4246
|
if (/^#[0-9a-f]{6}$/i.test(v)) return v.toLowerCase();
|
|
@@ -3587,9 +4258,9 @@ function DashboardSettingsPanel({
|
|
|
3587
4258
|
onClose,
|
|
3588
4259
|
onChange
|
|
3589
4260
|
}) {
|
|
3590
|
-
const { t } =
|
|
3591
|
-
const [draft, setDraft] =
|
|
3592
|
-
|
|
4261
|
+
const { t } = useTranslation14();
|
|
4262
|
+
const [draft, setDraft] = useState10(() => draftFromDashboard(dashboard));
|
|
4263
|
+
useEffect11(() => {
|
|
3593
4264
|
if (!open) return;
|
|
3594
4265
|
setDraft(draftFromDashboard(dashboard));
|
|
3595
4266
|
}, [
|
|
@@ -3632,7 +4303,17 @@ function DashboardSettingsPanel({
|
|
|
3632
4303
|
)
|
|
3633
4304
|
};
|
|
3634
4305
|
const isDefault = matchThemePreset(theme) === "default";
|
|
3635
|
-
const
|
|
4306
|
+
const emailOptions = draft.allowEmail && !isDefaultEmailOptions(draft) ? {
|
|
4307
|
+
attachPdf: draft.emailAttachPdf,
|
|
4308
|
+
allowExtraAttachments: draft.emailAllowExtra,
|
|
4309
|
+
maxExtraAttachments: draft.emailMaxExtra
|
|
4310
|
+
} : void 0;
|
|
4311
|
+
const exportOptions = draft.allowPrint && draft.allowPdf && !draft.allowEmail && !emailOptions ? void 0 : {
|
|
4312
|
+
print: draft.allowPrint,
|
|
4313
|
+
pdf: draft.allowPdf,
|
|
4314
|
+
...draft.allowEmail ? { email: true } : {},
|
|
4315
|
+
...emailOptions ? { emailOptions } : {}
|
|
4316
|
+
};
|
|
3636
4317
|
onChange({
|
|
3637
4318
|
locale: draft.locale,
|
|
3638
4319
|
currency: draft.currency,
|
|
@@ -3643,7 +4324,7 @@ function DashboardSettingsPanel({
|
|
|
3643
4324
|
});
|
|
3644
4325
|
onClose();
|
|
3645
4326
|
};
|
|
3646
|
-
return /* @__PURE__ */
|
|
4327
|
+
return /* @__PURE__ */ jsx14("div", { className: "dd-modal-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs14(
|
|
3647
4328
|
"div",
|
|
3648
4329
|
{
|
|
3649
4330
|
className: "dd-dialog dd-settings-panel",
|
|
@@ -3652,25 +4333,25 @@ function DashboardSettingsPanel({
|
|
|
3652
4333
|
"aria-labelledby": "dd-settings-title",
|
|
3653
4334
|
onClick: (e) => e.stopPropagation(),
|
|
3654
4335
|
children: [
|
|
3655
|
-
/* @__PURE__ */
|
|
3656
|
-
/* @__PURE__ */
|
|
3657
|
-
/* @__PURE__ */
|
|
4336
|
+
/* @__PURE__ */ jsxs14("header", { className: "dd-dialog-header", children: [
|
|
4337
|
+
/* @__PURE__ */ jsx14("h2", { id: "dd-settings-title", children: t("dashboardSettings") }),
|
|
4338
|
+
/* @__PURE__ */ jsx14(
|
|
3658
4339
|
"button",
|
|
3659
4340
|
{
|
|
3660
4341
|
type: "button",
|
|
3661
4342
|
className: "dd-btn dd-btn-ghost dd-btn-icon",
|
|
3662
4343
|
onClick: onClose,
|
|
3663
4344
|
"aria-label": t("cancel"),
|
|
3664
|
-
children: /* @__PURE__ */
|
|
4345
|
+
children: /* @__PURE__ */ jsx14(X8, { size: ICON_SIZE })
|
|
3665
4346
|
}
|
|
3666
4347
|
)
|
|
3667
4348
|
] }),
|
|
3668
|
-
/* @__PURE__ */
|
|
3669
|
-
/* @__PURE__ */
|
|
3670
|
-
/* @__PURE__ */
|
|
3671
|
-
/* @__PURE__ */
|
|
3672
|
-
/* @__PURE__ */
|
|
3673
|
-
/* @__PURE__ */
|
|
4349
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-dialog-body", children: [
|
|
4350
|
+
/* @__PURE__ */ jsx14("p", { className: "dd-hint", children: t("dashboardSettingsHint") }),
|
|
4351
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-settings-grid", children: [
|
|
4352
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4353
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-dash-locale", help: t("helpLocale"), children: t("locale") }),
|
|
4354
|
+
/* @__PURE__ */ jsxs14(
|
|
3674
4355
|
"select",
|
|
3675
4356
|
{
|
|
3676
4357
|
id: "dd-dash-locale",
|
|
@@ -3678,30 +4359,30 @@ function DashboardSettingsPanel({
|
|
|
3678
4359
|
value: draft.locale,
|
|
3679
4360
|
onChange: (e) => setDraft((d) => ({ ...d, locale: e.target.value })),
|
|
3680
4361
|
children: [
|
|
3681
|
-
/* @__PURE__ */
|
|
3682
|
-
/* @__PURE__ */
|
|
3683
|
-
/* @__PURE__ */
|
|
3684
|
-
/* @__PURE__ */
|
|
4362
|
+
/* @__PURE__ */ jsx14("option", { value: "en", children: "English" }),
|
|
4363
|
+
/* @__PURE__ */ jsx14("option", { value: "es", children: "Espa\xF1ol" }),
|
|
4364
|
+
/* @__PURE__ */ jsx14("option", { value: "ar", children: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629 (RTL)" }),
|
|
4365
|
+
/* @__PURE__ */ jsx14("option", { value: "he", children: "\u05E2\u05D1\u05E8\u05D9\u05EA (RTL)" })
|
|
3685
4366
|
]
|
|
3686
4367
|
}
|
|
3687
4368
|
)
|
|
3688
4369
|
] }),
|
|
3689
|
-
/* @__PURE__ */
|
|
3690
|
-
/* @__PURE__ */
|
|
3691
|
-
/* @__PURE__ */
|
|
4370
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4371
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-dash-currency", help: t("helpCurrency"), children: t("currency") }),
|
|
4372
|
+
/* @__PURE__ */ jsx14(
|
|
3692
4373
|
"select",
|
|
3693
4374
|
{
|
|
3694
4375
|
id: "dd-dash-currency",
|
|
3695
4376
|
className: "dd-input",
|
|
3696
4377
|
value: draft.currency,
|
|
3697
4378
|
onChange: (e) => setDraft((d) => ({ ...d, currency: e.target.value })),
|
|
3698
|
-
children: CURRENCIES.map((c) => /* @__PURE__ */
|
|
4379
|
+
children: CURRENCIES.map((c) => /* @__PURE__ */ jsx14("option", { value: c, children: c }, c))
|
|
3699
4380
|
}
|
|
3700
4381
|
)
|
|
3701
4382
|
] }),
|
|
3702
|
-
/* @__PURE__ */
|
|
3703
|
-
/* @__PURE__ */
|
|
3704
|
-
/* @__PURE__ */
|
|
4383
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4384
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-dash-tz", help: t("helpTimeZone"), children: t("timeZone") }),
|
|
4385
|
+
/* @__PURE__ */ jsxs14(
|
|
3705
4386
|
"select",
|
|
3706
4387
|
{
|
|
3707
4388
|
id: "dd-dash-tz",
|
|
@@ -3709,15 +4390,15 @@ function DashboardSettingsPanel({
|
|
|
3709
4390
|
value: draft.timeZone,
|
|
3710
4391
|
onChange: (e) => setDraft((d) => ({ ...d, timeZone: e.target.value })),
|
|
3711
4392
|
children: [
|
|
3712
|
-
/* @__PURE__ */
|
|
3713
|
-
TIMEZONES.map((tz) => /* @__PURE__ */
|
|
4393
|
+
/* @__PURE__ */ jsx14("option", { value: "", children: t("timeZoneBrowser") }),
|
|
4394
|
+
TIMEZONES.map((tz) => /* @__PURE__ */ jsx14("option", { value: tz, children: tz }, tz))
|
|
3714
4395
|
]
|
|
3715
4396
|
}
|
|
3716
4397
|
)
|
|
3717
4398
|
] }),
|
|
3718
|
-
/* @__PURE__ */
|
|
3719
|
-
/* @__PURE__ */
|
|
3720
|
-
/* @__PURE__ */
|
|
4399
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4400
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-dash-dir", help: t("helpTextDirection"), children: t("textDirection") }),
|
|
4401
|
+
/* @__PURE__ */ jsxs14(
|
|
3721
4402
|
"select",
|
|
3722
4403
|
{
|
|
3723
4404
|
id: "dd-dash-dir",
|
|
@@ -3725,22 +4406,22 @@ function DashboardSettingsPanel({
|
|
|
3725
4406
|
value: draft.dir,
|
|
3726
4407
|
onChange: (e) => setDraft((d) => ({ ...d, dir: e.target.value })),
|
|
3727
4408
|
children: [
|
|
3728
|
-
/* @__PURE__ */
|
|
3729
|
-
/* @__PURE__ */
|
|
3730
|
-
/* @__PURE__ */
|
|
4409
|
+
/* @__PURE__ */ jsx14("option", { value: "", children: t("dirAuto") }),
|
|
4410
|
+
/* @__PURE__ */ jsx14("option", { value: "ltr", children: "LTR" }),
|
|
4411
|
+
/* @__PURE__ */ jsx14("option", { value: "rtl", children: "RTL" })
|
|
3731
4412
|
]
|
|
3732
4413
|
}
|
|
3733
4414
|
)
|
|
3734
4415
|
] })
|
|
3735
4416
|
] }),
|
|
3736
|
-
/* @__PURE__ */
|
|
3737
|
-
/* @__PURE__ */
|
|
3738
|
-
/* @__PURE__ */
|
|
3739
|
-
/* @__PURE__ */
|
|
4417
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-theme-section", children: [
|
|
4418
|
+
/* @__PURE__ */ jsx14("div", { className: "dd-theme-section-head", children: /* @__PURE__ */ jsxs14("div", { children: [
|
|
4419
|
+
/* @__PURE__ */ jsx14("h3", { className: "dd-theme-title", children: t("exportOptions") }),
|
|
4420
|
+
/* @__PURE__ */ jsx14("p", { className: "dd-hint dd-theme-hint", children: t("helpExportOptions") })
|
|
3740
4421
|
] }) }),
|
|
3741
|
-
/* @__PURE__ */
|
|
3742
|
-
/* @__PURE__ */
|
|
3743
|
-
/* @__PURE__ */
|
|
4422
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field dd-check-field", children: [
|
|
4423
|
+
/* @__PURE__ */ jsxs14("label", { className: "dd-check-row", htmlFor: "dd-export-print", children: [
|
|
4424
|
+
/* @__PURE__ */ jsx14(
|
|
3744
4425
|
"input",
|
|
3745
4426
|
{
|
|
3746
4427
|
id: "dd-export-print",
|
|
@@ -3749,13 +4430,13 @@ function DashboardSettingsPanel({
|
|
|
3749
4430
|
onChange: (e) => setDraft((d) => ({ ...d, allowPrint: e.target.checked }))
|
|
3750
4431
|
}
|
|
3751
4432
|
),
|
|
3752
|
-
/* @__PURE__ */
|
|
4433
|
+
/* @__PURE__ */ jsx14("span", { className: "dd-check-row-text", children: t("allowPrint") })
|
|
3753
4434
|
] }),
|
|
3754
|
-
/* @__PURE__ */
|
|
4435
|
+
/* @__PURE__ */ jsx14(FieldHelp, { text: t("helpAllowPrint") })
|
|
3755
4436
|
] }),
|
|
3756
|
-
/* @__PURE__ */
|
|
3757
|
-
/* @__PURE__ */
|
|
3758
|
-
/* @__PURE__ */
|
|
4437
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field dd-check-field", children: [
|
|
4438
|
+
/* @__PURE__ */ jsxs14("label", { className: "dd-check-row", htmlFor: "dd-export-pdf", children: [
|
|
4439
|
+
/* @__PURE__ */ jsx14(
|
|
3759
4440
|
"input",
|
|
3760
4441
|
{
|
|
3761
4442
|
id: "dd-export-pdf",
|
|
@@ -3764,18 +4445,87 @@ function DashboardSettingsPanel({
|
|
|
3764
4445
|
onChange: (e) => setDraft((d) => ({ ...d, allowPdf: e.target.checked }))
|
|
3765
4446
|
}
|
|
3766
4447
|
),
|
|
3767
|
-
/* @__PURE__ */
|
|
4448
|
+
/* @__PURE__ */ jsx14("span", { className: "dd-check-row-text", children: t("allowExportPdf") })
|
|
4449
|
+
] }),
|
|
4450
|
+
/* @__PURE__ */ jsx14(FieldHelp, { text: t("helpAllowExportPdf") })
|
|
4451
|
+
] }),
|
|
4452
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field dd-check-field", children: [
|
|
4453
|
+
/* @__PURE__ */ jsxs14("label", { className: "dd-check-row", htmlFor: "dd-export-email", children: [
|
|
4454
|
+
/* @__PURE__ */ jsx14(
|
|
4455
|
+
"input",
|
|
4456
|
+
{
|
|
4457
|
+
id: "dd-export-email",
|
|
4458
|
+
type: "checkbox",
|
|
4459
|
+
checked: draft.allowEmail,
|
|
4460
|
+
onChange: (e) => setDraft((d) => ({ ...d, allowEmail: e.target.checked }))
|
|
4461
|
+
}
|
|
4462
|
+
),
|
|
4463
|
+
/* @__PURE__ */ jsx14("span", { className: "dd-check-row-text", children: t("allowEmail") })
|
|
4464
|
+
] }),
|
|
4465
|
+
/* @__PURE__ */ jsx14(FieldHelp, { text: t("helpAllowEmail") })
|
|
4466
|
+
] }),
|
|
4467
|
+
draft.allowEmail && /* @__PURE__ */ jsxs14("div", { className: "dd-email-options", children: [
|
|
4468
|
+
/* @__PURE__ */ jsx14("p", { className: "dd-hint dd-email-options-title", children: t("emailAttachmentOptions") }),
|
|
4469
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field dd-check-field", children: [
|
|
4470
|
+
/* @__PURE__ */ jsxs14("label", { className: "dd-check-row", htmlFor: "dd-email-attach-pdf", children: [
|
|
4471
|
+
/* @__PURE__ */ jsx14(
|
|
4472
|
+
"input",
|
|
4473
|
+
{
|
|
4474
|
+
id: "dd-email-attach-pdf",
|
|
4475
|
+
type: "checkbox",
|
|
4476
|
+
checked: draft.emailAttachPdf,
|
|
4477
|
+
onChange: (e) => setDraft((d) => ({ ...d, emailAttachPdf: e.target.checked }))
|
|
4478
|
+
}
|
|
4479
|
+
),
|
|
4480
|
+
/* @__PURE__ */ jsx14("span", { className: "dd-check-row-text", children: t("emailAttachPdf") })
|
|
4481
|
+
] }),
|
|
4482
|
+
/* @__PURE__ */ jsx14(FieldHelp, { text: t("helpEmailAttachPdf") })
|
|
4483
|
+
] }),
|
|
4484
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field dd-check-field", children: [
|
|
4485
|
+
/* @__PURE__ */ jsxs14("label", { className: "dd-check-row", htmlFor: "dd-email-allow-extra", children: [
|
|
4486
|
+
/* @__PURE__ */ jsx14(
|
|
4487
|
+
"input",
|
|
4488
|
+
{
|
|
4489
|
+
id: "dd-email-allow-extra",
|
|
4490
|
+
type: "checkbox",
|
|
4491
|
+
checked: draft.emailAllowExtra,
|
|
4492
|
+
onChange: (e) => setDraft((d) => ({ ...d, emailAllowExtra: e.target.checked }))
|
|
4493
|
+
}
|
|
4494
|
+
),
|
|
4495
|
+
/* @__PURE__ */ jsx14("span", { className: "dd-check-row-text", children: t("emailAllowExtraAttachments") })
|
|
4496
|
+
] }),
|
|
4497
|
+
/* @__PURE__ */ jsx14(FieldHelp, { text: t("helpEmailAllowExtraAttachments") })
|
|
3768
4498
|
] }),
|
|
3769
|
-
/* @__PURE__ */
|
|
4499
|
+
draft.emailAllowExtra && /* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4500
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-email-max-extra", help: t("helpEmailMaxExtraAttachments"), children: t("emailMaxExtraAttachments") }),
|
|
4501
|
+
/* @__PURE__ */ jsx14(
|
|
4502
|
+
"input",
|
|
4503
|
+
{
|
|
4504
|
+
id: "dd-email-max-extra",
|
|
4505
|
+
className: "dd-input",
|
|
4506
|
+
type: "number",
|
|
4507
|
+
min: 0,
|
|
4508
|
+
max: 10,
|
|
4509
|
+
value: draft.emailMaxExtra,
|
|
4510
|
+
onChange: (e) => {
|
|
4511
|
+
const n = Number(e.target.value);
|
|
4512
|
+
setDraft((d) => ({
|
|
4513
|
+
...d,
|
|
4514
|
+
emailMaxExtra: Number.isFinite(n) ? Math.max(0, Math.min(10, Math.floor(n))) : 5
|
|
4515
|
+
}));
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
)
|
|
4519
|
+
] })
|
|
3770
4520
|
] })
|
|
3771
4521
|
] }),
|
|
3772
|
-
/* @__PURE__ */
|
|
3773
|
-
/* @__PURE__ */
|
|
3774
|
-
/* @__PURE__ */
|
|
3775
|
-
/* @__PURE__ */
|
|
3776
|
-
/* @__PURE__ */
|
|
4522
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-theme-section", children: [
|
|
4523
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-theme-section-head", children: [
|
|
4524
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
4525
|
+
/* @__PURE__ */ jsx14("h3", { className: "dd-theme-title", children: t("themeColors") }),
|
|
4526
|
+
/* @__PURE__ */ jsx14("p", { className: "dd-hint dd-theme-hint", children: t("helpThemeColors") })
|
|
3777
4527
|
] }),
|
|
3778
|
-
/* @__PURE__ */
|
|
4528
|
+
/* @__PURE__ */ jsxs14(
|
|
3779
4529
|
"button",
|
|
3780
4530
|
{
|
|
3781
4531
|
type: "button",
|
|
@@ -3783,15 +4533,15 @@ function DashboardSettingsPanel({
|
|
|
3783
4533
|
onClick: resetTheme,
|
|
3784
4534
|
title: t("resetTheme"),
|
|
3785
4535
|
children: [
|
|
3786
|
-
/* @__PURE__ */
|
|
4536
|
+
/* @__PURE__ */ jsx14(RotateCcw2, { size: ICON_SIZE }),
|
|
3787
4537
|
t("resetTheme")
|
|
3788
4538
|
]
|
|
3789
4539
|
}
|
|
3790
4540
|
)
|
|
3791
4541
|
] }),
|
|
3792
|
-
/* @__PURE__ */
|
|
3793
|
-
/* @__PURE__ */
|
|
3794
|
-
/* @__PURE__ */
|
|
4542
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4543
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-theme-preset", help: t("helpThemePreset"), children: t("themePreset") }),
|
|
4544
|
+
/* @__PURE__ */ jsxs14(
|
|
3795
4545
|
"select",
|
|
3796
4546
|
{
|
|
3797
4547
|
id: "dd-theme-preset",
|
|
@@ -3802,19 +4552,19 @@ function DashboardSettingsPanel({
|
|
|
3802
4552
|
applyPreset(e.target.value);
|
|
3803
4553
|
},
|
|
3804
4554
|
children: [
|
|
3805
|
-
/* @__PURE__ */
|
|
3806
|
-
/* @__PURE__ */
|
|
3807
|
-
/* @__PURE__ */
|
|
3808
|
-
/* @__PURE__ */
|
|
3809
|
-
/* @__PURE__ */
|
|
4555
|
+
/* @__PURE__ */ jsx14("option", { value: "default", children: t("themePresetDefault") }),
|
|
4556
|
+
/* @__PURE__ */ jsx14("option", { value: "ocean", children: t("themePresetOcean") }),
|
|
4557
|
+
/* @__PURE__ */ jsx14("option", { value: "sunset", children: t("themePresetSunset") }),
|
|
4558
|
+
/* @__PURE__ */ jsx14("option", { value: "slate", children: t("themePresetSlate") }),
|
|
4559
|
+
/* @__PURE__ */ jsx14("option", { value: "custom", disabled: presetId !== "custom", children: t("themePresetCustom") })
|
|
3810
4560
|
]
|
|
3811
4561
|
}
|
|
3812
4562
|
)
|
|
3813
4563
|
] }),
|
|
3814
|
-
/* @__PURE__ */
|
|
3815
|
-
/* @__PURE__ */
|
|
3816
|
-
/* @__PURE__ */
|
|
3817
|
-
/* @__PURE__ */
|
|
4564
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4565
|
+
/* @__PURE__ */ jsx14(FieldLabel, { htmlFor: "dd-theme-accent", help: t("helpThemeAccent"), children: t("themeAccent") }),
|
|
4566
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-color-row", children: [
|
|
4567
|
+
/* @__PURE__ */ jsx14(
|
|
3818
4568
|
"input",
|
|
3819
4569
|
{
|
|
3820
4570
|
id: "dd-theme-accent",
|
|
@@ -3825,7 +4575,7 @@ function DashboardSettingsPanel({
|
|
|
3825
4575
|
"aria-label": t("themeAccent")
|
|
3826
4576
|
}
|
|
3827
4577
|
),
|
|
3828
|
-
/* @__PURE__ */
|
|
4578
|
+
/* @__PURE__ */ jsx14(
|
|
3829
4579
|
"input",
|
|
3830
4580
|
{
|
|
3831
4581
|
className: "dd-input dd-color-hex",
|
|
@@ -3836,10 +4586,10 @@ function DashboardSettingsPanel({
|
|
|
3836
4586
|
)
|
|
3837
4587
|
] })
|
|
3838
4588
|
] }),
|
|
3839
|
-
/* @__PURE__ */
|
|
3840
|
-
/* @__PURE__ */
|
|
3841
|
-
/* @__PURE__ */
|
|
3842
|
-
/* @__PURE__ */
|
|
4589
|
+
/* @__PURE__ */ jsxs14("div", { className: "dd-field", children: [
|
|
4590
|
+
/* @__PURE__ */ jsx14(FieldLabel, { help: t("helpThemeChartColors"), children: t("themeChartColors") }),
|
|
4591
|
+
/* @__PURE__ */ jsx14("div", { className: "dd-chart-color-list", children: draft.chartColors.map((color, index) => /* @__PURE__ */ jsxs14("div", { className: "dd-color-row", children: [
|
|
4592
|
+
/* @__PURE__ */ jsx14(
|
|
3843
4593
|
"input",
|
|
3844
4594
|
{
|
|
3845
4595
|
type: "color",
|
|
@@ -3856,7 +4606,7 @@ function DashboardSettingsPanel({
|
|
|
3856
4606
|
"aria-label": t("themeChartColorN", { n: index + 1 })
|
|
3857
4607
|
}
|
|
3858
4608
|
),
|
|
3859
|
-
/* @__PURE__ */
|
|
4609
|
+
/* @__PURE__ */ jsx14(
|
|
3860
4610
|
"input",
|
|
3861
4611
|
{
|
|
3862
4612
|
className: "dd-input dd-color-hex",
|
|
@@ -3869,7 +4619,7 @@ function DashboardSettingsPanel({
|
|
|
3869
4619
|
spellCheck: false
|
|
3870
4620
|
}
|
|
3871
4621
|
),
|
|
3872
|
-
/* @__PURE__ */
|
|
4622
|
+
/* @__PURE__ */ jsx14(
|
|
3873
4623
|
"button",
|
|
3874
4624
|
{
|
|
3875
4625
|
type: "button",
|
|
@@ -3881,11 +4631,11 @@ function DashboardSettingsPanel({
|
|
|
3881
4631
|
...d,
|
|
3882
4632
|
chartColors: d.chartColors.filter((_, i) => i !== index)
|
|
3883
4633
|
})),
|
|
3884
|
-
children: /* @__PURE__ */
|
|
4634
|
+
children: /* @__PURE__ */ jsx14(Trash24, { size: ICON_SIZE })
|
|
3885
4635
|
}
|
|
3886
4636
|
)
|
|
3887
4637
|
] }, index)) }),
|
|
3888
|
-
/* @__PURE__ */
|
|
4638
|
+
/* @__PURE__ */ jsxs14(
|
|
3889
4639
|
"button",
|
|
3890
4640
|
{
|
|
3891
4641
|
type: "button",
|
|
@@ -3898,12 +4648,12 @@ function DashboardSettingsPanel({
|
|
|
3898
4648
|
]
|
|
3899
4649
|
})),
|
|
3900
4650
|
children: [
|
|
3901
|
-
/* @__PURE__ */
|
|
4651
|
+
/* @__PURE__ */ jsx14(Plus5, { size: ICON_SIZE }),
|
|
3902
4652
|
t("addColor")
|
|
3903
4653
|
]
|
|
3904
4654
|
}
|
|
3905
4655
|
),
|
|
3906
|
-
/* @__PURE__ */
|
|
4656
|
+
/* @__PURE__ */ jsx14("div", { className: "dd-theme-preview", "aria-hidden": true, children: draft.chartColors.map((c, i) => /* @__PURE__ */ jsx14(
|
|
3907
4657
|
"span",
|
|
3908
4658
|
{
|
|
3909
4659
|
className: "dd-theme-preview-chip",
|
|
@@ -3914,9 +4664,9 @@ function DashboardSettingsPanel({
|
|
|
3914
4664
|
] })
|
|
3915
4665
|
] })
|
|
3916
4666
|
] }),
|
|
3917
|
-
/* @__PURE__ */
|
|
3918
|
-
/* @__PURE__ */
|
|
3919
|
-
/* @__PURE__ */
|
|
4667
|
+
/* @__PURE__ */ jsxs14("footer", { className: "dd-dialog-footer dd-dialog-footer-end", children: [
|
|
4668
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "dd-btn", onClick: onClose, children: t("cancel") }),
|
|
4669
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "dd-btn dd-btn-primary", onClick: apply, children: t("apply") })
|
|
3920
4670
|
] })
|
|
3921
4671
|
]
|
|
3922
4672
|
}
|
|
@@ -3924,7 +4674,7 @@ function DashboardSettingsPanel({
|
|
|
3924
4674
|
}
|
|
3925
4675
|
|
|
3926
4676
|
// src/designer/useDashboardHistory.ts
|
|
3927
|
-
import { useCallback, useEffect as
|
|
4677
|
+
import { useCallback, useEffect as useEffect12, useRef as useRef8, useState as useState11 } from "react";
|
|
3928
4678
|
var MAX_HISTORY = 50;
|
|
3929
4679
|
function cloneDashboard(dashboard) {
|
|
3930
4680
|
return structuredClone(dashboard);
|
|
@@ -3933,22 +4683,22 @@ function dashboardsEqual(a, b) {
|
|
|
3933
4683
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
3934
4684
|
}
|
|
3935
4685
|
function useDashboardHistory(initial, onChange, readOnly = false) {
|
|
3936
|
-
const [dashboard, setDashboard] =
|
|
3937
|
-
const [past, setPast] =
|
|
3938
|
-
const [future, setFuture] =
|
|
3939
|
-
const [baseline, setBaseline] =
|
|
3940
|
-
const presentRef =
|
|
3941
|
-
const pastRef =
|
|
3942
|
-
const futureRef =
|
|
3943
|
-
const baselineRef =
|
|
3944
|
-
const skipNextExternalSync =
|
|
3945
|
-
const layoutBeforeRef =
|
|
3946
|
-
const suppressLayoutWriteRef =
|
|
4686
|
+
const [dashboard, setDashboard] = useState11(() => cloneDashboard(initial));
|
|
4687
|
+
const [past, setPast] = useState11([]);
|
|
4688
|
+
const [future, setFuture] = useState11([]);
|
|
4689
|
+
const [baseline, setBaseline] = useState11(() => cloneDashboard(initial));
|
|
4690
|
+
const presentRef = useRef8(dashboard);
|
|
4691
|
+
const pastRef = useRef8(past);
|
|
4692
|
+
const futureRef = useRef8(future);
|
|
4693
|
+
const baselineRef = useRef8(baseline);
|
|
4694
|
+
const skipNextExternalSync = useRef8(false);
|
|
4695
|
+
const layoutBeforeRef = useRef8(null);
|
|
4696
|
+
const suppressLayoutWriteRef = useRef8(false);
|
|
3947
4697
|
presentRef.current = dashboard;
|
|
3948
4698
|
pastRef.current = past;
|
|
3949
4699
|
futureRef.current = future;
|
|
3950
4700
|
baselineRef.current = baseline;
|
|
3951
|
-
|
|
4701
|
+
useEffect12(() => {
|
|
3952
4702
|
if (skipNextExternalSync.current) {
|
|
3953
4703
|
skipNextExternalSync.current = false;
|
|
3954
4704
|
return;
|
|
@@ -3970,7 +4720,7 @@ function useDashboardHistory(initial, onChange, readOnly = false) {
|
|
|
3970
4720
|
setDashboard(next);
|
|
3971
4721
|
}
|
|
3972
4722
|
}, [initial]);
|
|
3973
|
-
|
|
4723
|
+
useEffect12(() => {
|
|
3974
4724
|
if (readOnly) return;
|
|
3975
4725
|
setBaseline(cloneDashboard(presentRef.current));
|
|
3976
4726
|
pastRef.current = [];
|
|
@@ -3978,7 +4728,7 @@ function useDashboardHistory(initial, onChange, readOnly = false) {
|
|
|
3978
4728
|
setPast([]);
|
|
3979
4729
|
setFuture([]);
|
|
3980
4730
|
}, [readOnly]);
|
|
3981
|
-
|
|
4731
|
+
useEffect12(() => {
|
|
3982
4732
|
if (!suppressLayoutWriteRef.current) return;
|
|
3983
4733
|
let inner = 0;
|
|
3984
4734
|
const outer = requestAnimationFrame(() => {
|
|
@@ -4131,9 +4881,7 @@ function useDashboardHistory(initial, onChange, readOnly = false) {
|
|
|
4131
4881
|
}
|
|
4132
4882
|
|
|
4133
4883
|
// src/designer/DashboardDesigner.tsx
|
|
4134
|
-
import "react-
|
|
4135
|
-
import "react-resizable/css/styles.css";
|
|
4136
|
-
import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
4884
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4137
4885
|
function listboxFilterField(widget) {
|
|
4138
4886
|
const override = widget.chartOptions.filterField;
|
|
4139
4887
|
if (typeof override === "string" && override.trim()) return override.trim();
|
|
@@ -4189,25 +4937,25 @@ function WidgetCard({
|
|
|
4189
4937
|
listboxSelection,
|
|
4190
4938
|
onListboxSelectionChange
|
|
4191
4939
|
}) {
|
|
4192
|
-
const { t } =
|
|
4940
|
+
const { t } = useTranslation15();
|
|
4193
4941
|
const { data, error, loading } = useWidgetData(api, widget, globalFilters, refreshKey);
|
|
4194
4942
|
const TypeIcon = chartTypeIcon[widget.type];
|
|
4195
4943
|
const stopDrag = (e) => {
|
|
4196
4944
|
e.stopPropagation();
|
|
4197
4945
|
};
|
|
4198
|
-
return /* @__PURE__ */
|
|
4199
|
-
/* @__PURE__ */
|
|
4200
|
-
/* @__PURE__ */
|
|
4201
|
-
!readOnly && /* @__PURE__ */
|
|
4202
|
-
/* @__PURE__ */
|
|
4946
|
+
return /* @__PURE__ */ jsxs15("div", { className: `dd-widget ${selected ? "selected" : ""}`, onClick: onSelect, role: "presentation", children: [
|
|
4947
|
+
/* @__PURE__ */ jsxs15("div", { className: "dd-widget-header", children: [
|
|
4948
|
+
/* @__PURE__ */ jsxs15("div", { className: readOnly ? "dd-widget-title-wrap" : "dd-widget-drag", children: [
|
|
4949
|
+
!readOnly && /* @__PURE__ */ jsx15("span", { className: "dd-widget-drag-grip", "aria-hidden": true }),
|
|
4950
|
+
/* @__PURE__ */ jsx15("span", { className: "dd-widget-title", children: widget.title })
|
|
4203
4951
|
] }),
|
|
4204
|
-
/* @__PURE__ */
|
|
4205
|
-
/* @__PURE__ */
|
|
4206
|
-
/* @__PURE__ */
|
|
4952
|
+
/* @__PURE__ */ jsxs15("div", { className: "dd-widget-header-actions", children: [
|
|
4953
|
+
/* @__PURE__ */ jsxs15("span", { className: "dd-badge", title: widget.type, children: [
|
|
4954
|
+
/* @__PURE__ */ jsx15(TypeIcon, { size: 12, strokeWidth: 2.25, "aria-hidden": true }),
|
|
4207
4955
|
widget.type
|
|
4208
4956
|
] }),
|
|
4209
|
-
!readOnly && /* @__PURE__ */
|
|
4210
|
-
/* @__PURE__ */
|
|
4957
|
+
!readOnly && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
4958
|
+
/* @__PURE__ */ jsx15(
|
|
4211
4959
|
"button",
|
|
4212
4960
|
{
|
|
4213
4961
|
type: "button",
|
|
@@ -4221,10 +4969,10 @@ function WidgetCard({
|
|
|
4221
4969
|
e.stopPropagation();
|
|
4222
4970
|
onEdit();
|
|
4223
4971
|
},
|
|
4224
|
-
children: /* @__PURE__ */
|
|
4972
|
+
children: /* @__PURE__ */ jsx15(Pencil, { size: ICON_SIZE })
|
|
4225
4973
|
}
|
|
4226
4974
|
),
|
|
4227
|
-
/* @__PURE__ */
|
|
4975
|
+
/* @__PURE__ */ jsx15(
|
|
4228
4976
|
"button",
|
|
4229
4977
|
{
|
|
4230
4978
|
type: "button",
|
|
@@ -4238,13 +4986,13 @@ function WidgetCard({
|
|
|
4238
4986
|
e.stopPropagation();
|
|
4239
4987
|
onDelete();
|
|
4240
4988
|
},
|
|
4241
|
-
children: /* @__PURE__ */
|
|
4989
|
+
children: /* @__PURE__ */ jsx15(Trash25, { size: ICON_SIZE })
|
|
4242
4990
|
}
|
|
4243
4991
|
)
|
|
4244
4992
|
] })
|
|
4245
4993
|
] })
|
|
4246
4994
|
] }),
|
|
4247
|
-
/* @__PURE__ */
|
|
4995
|
+
/* @__PURE__ */ jsxs15(
|
|
4248
4996
|
"div",
|
|
4249
4997
|
{
|
|
4250
4998
|
className: "dd-widget-body",
|
|
@@ -4254,8 +5002,8 @@ function WidgetCard({
|
|
|
4254
5002
|
onEdit();
|
|
4255
5003
|
},
|
|
4256
5004
|
children: [
|
|
4257
|
-
error && /* @__PURE__ */
|
|
4258
|
-
!error && /* @__PURE__ */
|
|
5005
|
+
error && /* @__PURE__ */ jsx15("div", { className: "dd-error", children: error }),
|
|
5006
|
+
!error && /* @__PURE__ */ jsx15(
|
|
4259
5007
|
ChartRenderer,
|
|
4260
5008
|
{
|
|
4261
5009
|
widget,
|
|
@@ -4286,7 +5034,7 @@ function DashboardDesigner({
|
|
|
4286
5034
|
onToggleEdit
|
|
4287
5035
|
}) {
|
|
4288
5036
|
ensureI18n(locale);
|
|
4289
|
-
const { t, i18n: i18n2 } =
|
|
5037
|
+
const { t, i18n: i18n2 } = useTranslation15();
|
|
4290
5038
|
const api = useMemo6(() => new DashboardApiClient(apiBaseUrl, auth), [apiBaseUrl, auth]);
|
|
4291
5039
|
const seed = useMemo6(() => initial ?? createEmptyDashboard(), [initial]);
|
|
4292
5040
|
const {
|
|
@@ -4306,19 +5054,19 @@ function DashboardDesigner({
|
|
|
4306
5054
|
canRedo,
|
|
4307
5055
|
canReset
|
|
4308
5056
|
} = useDashboardHistory(seed, onChange, readOnly);
|
|
4309
|
-
const [editingTitle, setEditingTitle] =
|
|
4310
|
-
const [historyOpen, setHistoryOpen] =
|
|
4311
|
-
const [filtersPanel, setFiltersPanel] =
|
|
4312
|
-
const titleInputRef =
|
|
4313
|
-
const titleFocusSnapshot =
|
|
4314
|
-
|
|
5057
|
+
const [editingTitle, setEditingTitle] = useState12(false);
|
|
5058
|
+
const [historyOpen, setHistoryOpen] = useState12(false);
|
|
5059
|
+
const [filtersPanel, setFiltersPanel] = useState12(DEFAULT_FILTERS_PANEL);
|
|
5060
|
+
const titleInputRef = React13.useRef(null);
|
|
5061
|
+
const titleFocusSnapshot = React13.useRef(null);
|
|
5062
|
+
useEffect13(() => {
|
|
4315
5063
|
if (!editingTitle) return;
|
|
4316
5064
|
const el = titleInputRef.current;
|
|
4317
5065
|
if (!el) return;
|
|
4318
5066
|
el.focus();
|
|
4319
5067
|
el.select();
|
|
4320
5068
|
}, [editingTitle]);
|
|
4321
|
-
|
|
5069
|
+
useEffect13(() => {
|
|
4322
5070
|
if (readOnly) {
|
|
4323
5071
|
setEditingTitle(false);
|
|
4324
5072
|
setHistoryOpen(false);
|
|
@@ -4326,18 +5074,19 @@ function DashboardDesigner({
|
|
|
4326
5074
|
setSettingsOpen(false);
|
|
4327
5075
|
}
|
|
4328
5076
|
}, [readOnly]);
|
|
4329
|
-
const [selectedId, setSelectedId] =
|
|
4330
|
-
const [connections, setConnections] =
|
|
4331
|
-
const [refreshKey, setRefreshKey] =
|
|
4332
|
-
const [width, setWidth] =
|
|
4333
|
-
const [drillTrail, setDrillTrail] =
|
|
4334
|
-
const [modalOpen, setModalOpen] =
|
|
4335
|
-
const [modalMode, setModalMode] =
|
|
4336
|
-
const [editingWidget, setEditingWidget] =
|
|
4337
|
-
const [shareOpen, setShareOpen] =
|
|
4338
|
-
const [
|
|
4339
|
-
const [
|
|
4340
|
-
const [
|
|
5077
|
+
const [selectedId, setSelectedId] = useState12(null);
|
|
5078
|
+
const [connections, setConnections] = useState12([]);
|
|
5079
|
+
const [refreshKey, setRefreshKey] = useState12(0);
|
|
5080
|
+
const [width, setWidth] = useState12(900);
|
|
5081
|
+
const [drillTrail, setDrillTrail] = useState12([]);
|
|
5082
|
+
const [modalOpen, setModalOpen] = useState12(false);
|
|
5083
|
+
const [modalMode, setModalMode] = useState12("add");
|
|
5084
|
+
const [editingWidget, setEditingWidget] = useState12(null);
|
|
5085
|
+
const [shareOpen, setShareOpen] = useState12(false);
|
|
5086
|
+
const [emailOpen, setEmailOpen] = useState12(false);
|
|
5087
|
+
const [settingsOpen, setSettingsOpen] = useState12(false);
|
|
5088
|
+
const [drillError, setDrillError] = useState12(null);
|
|
5089
|
+
const [listboxSelections, setListboxSelections] = useState12({});
|
|
4341
5090
|
const effectiveReadOnly = readOnly || drillTrail.length > 0;
|
|
4342
5091
|
const textDir = resolveDashboardDir(dashboard);
|
|
4343
5092
|
const effectiveLocale = dashboard.locale || locale;
|
|
@@ -4350,7 +5099,7 @@ function DashboardDesigner({
|
|
|
4350
5099
|
const handleExportPdf = () => {
|
|
4351
5100
|
exportDashboardPdf(document.getElementById("dd-canvas"), dashboard.title);
|
|
4352
5101
|
};
|
|
4353
|
-
|
|
5102
|
+
useEffect13(() => {
|
|
4354
5103
|
setListboxSelections({});
|
|
4355
5104
|
}, [dashboard.id]);
|
|
4356
5105
|
const effectiveFiltersFor = (widget) => {
|
|
@@ -4362,13 +5111,13 @@ function DashboardDesigner({
|
|
|
4362
5111
|
const globals = dashboard.globalFilters.filter((f) => !f.id.startsWith("listbox:"));
|
|
4363
5112
|
return [...globals, ...fromListboxes];
|
|
4364
5113
|
};
|
|
4365
|
-
|
|
5114
|
+
useEffect13(() => {
|
|
4366
5115
|
void i18n2.changeLanguage(effectiveLocale);
|
|
4367
5116
|
}, [effectiveLocale, i18n2]);
|
|
4368
|
-
|
|
5117
|
+
useEffect13(() => {
|
|
4369
5118
|
api.listConnections().then((r) => setConnections(r.connections)).catch(() => setConnections([]));
|
|
4370
5119
|
}, [api]);
|
|
4371
|
-
|
|
5120
|
+
useEffect13(() => {
|
|
4372
5121
|
const el = document.getElementById("dd-canvas");
|
|
4373
5122
|
if (!el) return;
|
|
4374
5123
|
const measure = () => {
|
|
@@ -4381,7 +5130,7 @@ function DashboardDesigner({
|
|
|
4381
5130
|
measure();
|
|
4382
5131
|
return () => ro.disconnect();
|
|
4383
5132
|
}, []);
|
|
4384
|
-
|
|
5133
|
+
useEffect13(() => {
|
|
4385
5134
|
if (effectiveReadOnly) return;
|
|
4386
5135
|
const onKeyDown = (e) => {
|
|
4387
5136
|
const target = e.target;
|
|
@@ -4582,16 +5331,16 @@ function DashboardDesigner({
|
|
|
4582
5331
|
}
|
|
4583
5332
|
setRefreshKey((k) => k + 1);
|
|
4584
5333
|
};
|
|
4585
|
-
return /* @__PURE__ */
|
|
5334
|
+
return /* @__PURE__ */ jsxs15(
|
|
4586
5335
|
"div",
|
|
4587
5336
|
{
|
|
4588
5337
|
className: `dd-root ${effectiveReadOnly ? "dd-readonly" : ""} ${filtersPanel.open || filtersPanel.collapsed ? "dd-has-filters-side" : ""} ${filtersPanel.collapsed ? "dd-filters-side-is-collapsed" : ""} ${filtersPanel.pinned ? "dd-filters-side-is-pinned" : ""}`,
|
|
4589
5338
|
dir: textDir,
|
|
4590
5339
|
style: themeStyle,
|
|
4591
5340
|
children: [
|
|
4592
|
-
/* @__PURE__ */
|
|
4593
|
-
/* @__PURE__ */
|
|
4594
|
-
editingTitle && !effectiveReadOnly ? /* @__PURE__ */
|
|
5341
|
+
/* @__PURE__ */ jsxs15("header", { className: "dd-toolbar", children: [
|
|
5342
|
+
/* @__PURE__ */ jsxs15("div", { className: "dd-toolbar-left", children: [
|
|
5343
|
+
editingTitle && !effectiveReadOnly ? /* @__PURE__ */ jsx15(
|
|
4595
5344
|
"input",
|
|
4596
5345
|
{
|
|
4597
5346
|
ref: titleInputRef,
|
|
@@ -4621,7 +5370,7 @@ function DashboardDesigner({
|
|
|
4621
5370
|
}
|
|
4622
5371
|
}
|
|
4623
5372
|
}
|
|
4624
|
-
) : /* @__PURE__ */
|
|
5373
|
+
) : /* @__PURE__ */ jsx15(
|
|
4625
5374
|
"button",
|
|
4626
5375
|
{
|
|
4627
5376
|
type: "button",
|
|
@@ -4635,19 +5384,19 @@ function DashboardDesigner({
|
|
|
4635
5384
|
children: dashboard.title || t("title")
|
|
4636
5385
|
}
|
|
4637
5386
|
),
|
|
4638
|
-
drillTrail.length > 0 && /* @__PURE__ */
|
|
5387
|
+
drillTrail.length > 0 && /* @__PURE__ */ jsxs15("span", { className: "dd-drill-crumb dd-muted", children: [
|
|
4639
5388
|
drillTrail.map((f) => f.title).join(" \u203A "),
|
|
4640
5389
|
" \u203A ",
|
|
4641
5390
|
dashboard.title
|
|
4642
5391
|
] })
|
|
4643
5392
|
] }),
|
|
4644
|
-
/* @__PURE__ */
|
|
4645
|
-
drillError && /* @__PURE__ */
|
|
4646
|
-
drillTrail.length > 0 && /* @__PURE__ */
|
|
4647
|
-
/* @__PURE__ */
|
|
5393
|
+
/* @__PURE__ */ jsxs15("div", { className: "dd-toolbar-right", children: [
|
|
5394
|
+
drillError && /* @__PURE__ */ jsx15("span", { className: "dd-error dd-inline-error", children: drillError }),
|
|
5395
|
+
drillTrail.length > 0 && /* @__PURE__ */ jsxs15("button", { type: "button", className: "dd-btn", onClick: handleDrillBack, children: [
|
|
5396
|
+
/* @__PURE__ */ jsx15(ArrowUpLeft, { size: ICON_SIZE }),
|
|
4648
5397
|
t("drillBack")
|
|
4649
5398
|
] }),
|
|
4650
|
-
/* @__PURE__ */
|
|
5399
|
+
/* @__PURE__ */ jsx15(
|
|
4651
5400
|
GlobalFiltersPopover,
|
|
4652
5401
|
{
|
|
4653
5402
|
filters: dashboard.globalFilters,
|
|
@@ -4657,8 +5406,8 @@ function DashboardDesigner({
|
|
|
4657
5406
|
onPanelChange: setFiltersPanel
|
|
4658
5407
|
}
|
|
4659
5408
|
),
|
|
4660
|
-
(exportOpts.print || exportOpts.pdf) && /* @__PURE__ */
|
|
4661
|
-
exportOpts.print && /* @__PURE__ */
|
|
5409
|
+
(exportOpts.print || exportOpts.pdf || exportOpts.email) && /* @__PURE__ */ jsxs15("div", { className: "dd-toolbar-export", role: "group", "aria-label": t("exportOptions"), children: [
|
|
5410
|
+
exportOpts.print && /* @__PURE__ */ jsxs15(
|
|
4662
5411
|
"button",
|
|
4663
5412
|
{
|
|
4664
5413
|
type: "button",
|
|
@@ -4667,12 +5416,12 @@ function DashboardDesigner({
|
|
|
4667
5416
|
"aria-label": t("printDashboard"),
|
|
4668
5417
|
onClick: handlePrint,
|
|
4669
5418
|
children: [
|
|
4670
|
-
/* @__PURE__ */
|
|
5419
|
+
/* @__PURE__ */ jsx15(Printer, { size: ICON_SIZE }),
|
|
4671
5420
|
t("print")
|
|
4672
5421
|
]
|
|
4673
5422
|
}
|
|
4674
5423
|
),
|
|
4675
|
-
exportOpts.pdf && /* @__PURE__ */
|
|
5424
|
+
exportOpts.pdf && /* @__PURE__ */ jsxs15(
|
|
4676
5425
|
"button",
|
|
4677
5426
|
{
|
|
4678
5427
|
type: "button",
|
|
@@ -4681,13 +5430,27 @@ function DashboardDesigner({
|
|
|
4681
5430
|
"aria-label": t("exportPdf"),
|
|
4682
5431
|
onClick: handleExportPdf,
|
|
4683
5432
|
children: [
|
|
4684
|
-
/* @__PURE__ */
|
|
5433
|
+
/* @__PURE__ */ jsx15(FileDown, { size: ICON_SIZE }),
|
|
4685
5434
|
t("exportPdf")
|
|
4686
5435
|
]
|
|
4687
5436
|
}
|
|
5437
|
+
),
|
|
5438
|
+
exportOpts.email && /* @__PURE__ */ jsxs15(
|
|
5439
|
+
"button",
|
|
5440
|
+
{
|
|
5441
|
+
type: "button",
|
|
5442
|
+
className: "dd-btn",
|
|
5443
|
+
title: t("sendEmail"),
|
|
5444
|
+
"aria-label": t("sendEmail"),
|
|
5445
|
+
onClick: () => setEmailOpen(true),
|
|
5446
|
+
children: [
|
|
5447
|
+
/* @__PURE__ */ jsx15(Mail2, { size: ICON_SIZE }),
|
|
5448
|
+
t("emailAction")
|
|
5449
|
+
]
|
|
5450
|
+
}
|
|
4688
5451
|
)
|
|
4689
5452
|
] }),
|
|
4690
|
-
onToggleEdit && readOnly && drillTrail.length === 0 && /* @__PURE__ */
|
|
5453
|
+
onToggleEdit && readOnly && drillTrail.length === 0 && /* @__PURE__ */ jsxs15(
|
|
4691
5454
|
"button",
|
|
4692
5455
|
{
|
|
4693
5456
|
type: "button",
|
|
@@ -4696,13 +5459,13 @@ function DashboardDesigner({
|
|
|
4696
5459
|
"aria-label": t("edit"),
|
|
4697
5460
|
onClick: onToggleEdit,
|
|
4698
5461
|
children: [
|
|
4699
|
-
/* @__PURE__ */
|
|
5462
|
+
/* @__PURE__ */ jsx15(Pencil, { size: ICON_SIZE }),
|
|
4700
5463
|
t("edit")
|
|
4701
5464
|
]
|
|
4702
5465
|
}
|
|
4703
5466
|
),
|
|
4704
|
-
!effectiveReadOnly && /* @__PURE__ */
|
|
4705
|
-
/* @__PURE__ */
|
|
5467
|
+
!effectiveReadOnly && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
5468
|
+
/* @__PURE__ */ jsxs15(
|
|
4706
5469
|
"button",
|
|
4707
5470
|
{
|
|
4708
5471
|
type: "button",
|
|
@@ -4711,12 +5474,12 @@ function DashboardDesigner({
|
|
|
4711
5474
|
"aria-label": t("shareDashboard"),
|
|
4712
5475
|
onClick: () => setShareOpen(true),
|
|
4713
5476
|
children: [
|
|
4714
|
-
/* @__PURE__ */
|
|
5477
|
+
/* @__PURE__ */ jsx15(Share2, { size: ICON_SIZE }),
|
|
4715
5478
|
t("share")
|
|
4716
5479
|
]
|
|
4717
5480
|
}
|
|
4718
5481
|
),
|
|
4719
|
-
/* @__PURE__ */
|
|
5482
|
+
/* @__PURE__ */ jsx15(
|
|
4720
5483
|
"button",
|
|
4721
5484
|
{
|
|
4722
5485
|
type: "button",
|
|
@@ -4724,10 +5487,10 @@ function DashboardDesigner({
|
|
|
4724
5487
|
title: t("dashboardSettings"),
|
|
4725
5488
|
"aria-label": t("dashboardSettings"),
|
|
4726
5489
|
onClick: () => setSettingsOpen(true),
|
|
4727
|
-
children: /* @__PURE__ */
|
|
5490
|
+
children: /* @__PURE__ */ jsx15(Settings2, { size: ICON_SIZE })
|
|
4728
5491
|
}
|
|
4729
5492
|
),
|
|
4730
|
-
/* @__PURE__ */
|
|
5493
|
+
/* @__PURE__ */ jsxs15(
|
|
4731
5494
|
"button",
|
|
4732
5495
|
{
|
|
4733
5496
|
type: "button",
|
|
@@ -4736,13 +5499,13 @@ function DashboardDesigner({
|
|
|
4736
5499
|
"aria-label": t("versionHistory"),
|
|
4737
5500
|
onClick: () => setHistoryOpen(true),
|
|
4738
5501
|
children: [
|
|
4739
|
-
/* @__PURE__ */
|
|
5502
|
+
/* @__PURE__ */ jsx15(History2, { size: ICON_SIZE }),
|
|
4740
5503
|
t("history")
|
|
4741
5504
|
]
|
|
4742
5505
|
}
|
|
4743
5506
|
),
|
|
4744
|
-
/* @__PURE__ */
|
|
4745
|
-
/* @__PURE__ */
|
|
5507
|
+
/* @__PURE__ */ jsxs15("div", { className: "dd-toolbar-history", role: "group", "aria-label": t("editHistory"), children: [
|
|
5508
|
+
/* @__PURE__ */ jsx15(
|
|
4746
5509
|
"button",
|
|
4747
5510
|
{
|
|
4748
5511
|
type: "button",
|
|
@@ -4751,10 +5514,10 @@ function DashboardDesigner({
|
|
|
4751
5514
|
"aria-label": t("undo"),
|
|
4752
5515
|
disabled: !canUndo,
|
|
4753
5516
|
onClick: handleUndo,
|
|
4754
|
-
children: /* @__PURE__ */
|
|
5517
|
+
children: /* @__PURE__ */ jsx15(Undo2, { size: ICON_SIZE })
|
|
4755
5518
|
}
|
|
4756
5519
|
),
|
|
4757
|
-
/* @__PURE__ */
|
|
5520
|
+
/* @__PURE__ */ jsx15(
|
|
4758
5521
|
"button",
|
|
4759
5522
|
{
|
|
4760
5523
|
type: "button",
|
|
@@ -4763,10 +5526,10 @@ function DashboardDesigner({
|
|
|
4763
5526
|
"aria-label": t("redo"),
|
|
4764
5527
|
disabled: !canRedo,
|
|
4765
5528
|
onClick: handleRedo,
|
|
4766
|
-
children: /* @__PURE__ */
|
|
5529
|
+
children: /* @__PURE__ */ jsx15(Redo2, { size: ICON_SIZE })
|
|
4767
5530
|
}
|
|
4768
5531
|
),
|
|
4769
|
-
/* @__PURE__ */
|
|
5532
|
+
/* @__PURE__ */ jsx15(
|
|
4770
5533
|
"button",
|
|
4771
5534
|
{
|
|
4772
5535
|
type: "button",
|
|
@@ -4775,23 +5538,23 @@ function DashboardDesigner({
|
|
|
4775
5538
|
"aria-label": t("reset"),
|
|
4776
5539
|
disabled: !canReset,
|
|
4777
5540
|
onClick: handleReset,
|
|
4778
|
-
children: /* @__PURE__ */
|
|
5541
|
+
children: /* @__PURE__ */ jsx15(RotateCcw3, { size: ICON_SIZE })
|
|
4779
5542
|
}
|
|
4780
5543
|
)
|
|
4781
5544
|
] }),
|
|
4782
|
-
/* @__PURE__ */
|
|
4783
|
-
/* @__PURE__ */
|
|
5545
|
+
/* @__PURE__ */ jsxs15("button", { type: "button", className: "dd-btn", onClick: openAddModal, children: [
|
|
5546
|
+
/* @__PURE__ */ jsx15(Plus6, { size: ICON_SIZE }),
|
|
4784
5547
|
t("add")
|
|
4785
5548
|
] }),
|
|
4786
|
-
/* @__PURE__ */
|
|
4787
|
-
/* @__PURE__ */
|
|
5549
|
+
/* @__PURE__ */ jsxs15("button", { type: "button", className: "dd-btn dd-btn-primary", onClick: () => void handleSave(), children: [
|
|
5550
|
+
/* @__PURE__ */ jsx15(Save2, { size: ICON_SIZE }),
|
|
4788
5551
|
t("save")
|
|
4789
5552
|
] })
|
|
4790
5553
|
] })
|
|
4791
5554
|
] })
|
|
4792
5555
|
] }),
|
|
4793
|
-
/* @__PURE__ */
|
|
4794
|
-
/* @__PURE__ */
|
|
5556
|
+
/* @__PURE__ */ jsxs15("div", { className: "dd-workspace", children: [
|
|
5557
|
+
/* @__PURE__ */ jsx15(
|
|
4795
5558
|
GlobalFiltersSidePanel,
|
|
4796
5559
|
{
|
|
4797
5560
|
filters: dashboard.globalFilters,
|
|
@@ -4801,15 +5564,15 @@ function DashboardDesigner({
|
|
|
4801
5564
|
onPanelChange: setFiltersPanel
|
|
4802
5565
|
}
|
|
4803
5566
|
),
|
|
4804
|
-
/* @__PURE__ */
|
|
4805
|
-
dashboard.widgets.length === 0 && !effectiveReadOnly && /* @__PURE__ */
|
|
4806
|
-
/* @__PURE__ */
|
|
4807
|
-
/* @__PURE__ */
|
|
4808
|
-
/* @__PURE__ */
|
|
5567
|
+
/* @__PURE__ */ jsx15("div", { className: "dd-main dd-main-canvas-only", children: /* @__PURE__ */ jsxs15("div", { id: "dd-canvas", className: "dd-canvas", children: [
|
|
5568
|
+
dashboard.widgets.length === 0 && !effectiveReadOnly && /* @__PURE__ */ jsxs15("div", { className: "dd-canvas-empty", children: [
|
|
5569
|
+
/* @__PURE__ */ jsx15("p", { children: t("emptyCanvas") }),
|
|
5570
|
+
/* @__PURE__ */ jsxs15("button", { type: "button", className: "dd-btn dd-btn-primary", onClick: openAddModal, children: [
|
|
5571
|
+
/* @__PURE__ */ jsx15(Plus6, { size: ICON_SIZE }),
|
|
4809
5572
|
t("addWidget")
|
|
4810
5573
|
] })
|
|
4811
5574
|
] }),
|
|
4812
|
-
/* @__PURE__ */
|
|
5575
|
+
/* @__PURE__ */ jsx15(
|
|
4813
5576
|
GridLayout,
|
|
4814
5577
|
{
|
|
4815
5578
|
className: "layout",
|
|
@@ -4829,7 +5592,7 @@ function DashboardDesigner({
|
|
|
4829
5592
|
draggableHandle: ".dd-widget-drag",
|
|
4830
5593
|
draggableCancel: ".dd-widget-edit, .dd-widget-delete, .dd-widget-header-actions, .dd-chart-fill, .recharts-wrapper, .dd-listbox",
|
|
4831
5594
|
compactType: "vertical",
|
|
4832
|
-
children: dashboard.widgets.map((widget) => /* @__PURE__ */
|
|
5595
|
+
children: dashboard.widgets.map((widget) => /* @__PURE__ */ jsx15("div", { children: /* @__PURE__ */ jsx15(
|
|
4833
5596
|
WidgetCard,
|
|
4834
5597
|
{
|
|
4835
5598
|
widget,
|
|
@@ -4857,7 +5620,7 @@ function DashboardDesigner({
|
|
|
4857
5620
|
)
|
|
4858
5621
|
] }) })
|
|
4859
5622
|
] }),
|
|
4860
|
-
!effectiveReadOnly && /* @__PURE__ */
|
|
5623
|
+
!effectiveReadOnly && /* @__PURE__ */ jsx15(
|
|
4861
5624
|
WidgetEditorModal,
|
|
4862
5625
|
{
|
|
4863
5626
|
open: modalOpen,
|
|
@@ -4875,7 +5638,7 @@ function DashboardDesigner({
|
|
|
4875
5638
|
}
|
|
4876
5639
|
}
|
|
4877
5640
|
),
|
|
4878
|
-
/* @__PURE__ */
|
|
5641
|
+
/* @__PURE__ */ jsx15(
|
|
4879
5642
|
HistoryPanel,
|
|
4880
5643
|
{
|
|
4881
5644
|
open: historyOpen && !effectiveReadOnly,
|
|
@@ -4892,7 +5655,7 @@ function DashboardDesigner({
|
|
|
4892
5655
|
}
|
|
4893
5656
|
}
|
|
4894
5657
|
),
|
|
4895
|
-
/* @__PURE__ */
|
|
5658
|
+
/* @__PURE__ */ jsx15(
|
|
4896
5659
|
SharePanel,
|
|
4897
5660
|
{
|
|
4898
5661
|
open: shareOpen && !effectiveReadOnly,
|
|
@@ -4901,7 +5664,16 @@ function DashboardDesigner({
|
|
|
4901
5664
|
api
|
|
4902
5665
|
}
|
|
4903
5666
|
),
|
|
4904
|
-
/* @__PURE__ */
|
|
5667
|
+
/* @__PURE__ */ jsx15(
|
|
5668
|
+
EmailComposePanel,
|
|
5669
|
+
{
|
|
5670
|
+
open: emailOpen,
|
|
5671
|
+
onClose: () => setEmailOpen(false),
|
|
5672
|
+
dashboard,
|
|
5673
|
+
api
|
|
5674
|
+
}
|
|
5675
|
+
),
|
|
5676
|
+
/* @__PURE__ */ jsx15(
|
|
4905
5677
|
DashboardSettingsPanel,
|
|
4906
5678
|
{
|
|
4907
5679
|
open: settingsOpen && !effectiveReadOnly,
|
|
@@ -4916,9 +5688,9 @@ function DashboardDesigner({
|
|
|
4916
5688
|
}
|
|
4917
5689
|
|
|
4918
5690
|
// src/viewer/DashboardViewer.tsx
|
|
4919
|
-
import { jsx as
|
|
5691
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
4920
5692
|
function DashboardViewer({ dashboard, apiBaseUrl, auth, locale }) {
|
|
4921
|
-
return /* @__PURE__ */
|
|
5693
|
+
return /* @__PURE__ */ jsx16(
|
|
4922
5694
|
DashboardDesigner,
|
|
4923
5695
|
{
|
|
4924
5696
|
dashboard,
|