Andrey Antukh c74d415ddd
🐛 Stop oversized audit events from wedging the archive queue (#12252)
* 🐛 Stop the export-shapes modal event from dumping all exports

The `:export-shapes` modal event carried the full `:exports` vector,
each export embedding its shape (path data, geometry, text content).
One event reached 1.7 MB, which made the audit archive cron POST a
chunk past the proxy body limit and wedge the queue.

Build a compact body for that modal instead: total exports, distinct
shapes and one count per export type, plus the page name. Other modals
keep their props unchanged.

Move the modal `:origin` prop to `::ev/origin` so `make-proto-event`
records it on the event context as `:event-origin`; the UI still reads
the plain prop from the raw state.

Add tests for the summary and for the modal origin.

AI-assisted-by: deepseek-v4.1-flash

* 🐛 Bound exception messages in reports and audit events

A frontend crash whose message embeds a whole payload (a serialized
file) produced a 9.4 MB audit event: the message was repeated in the
`:hint` prop, in the report context and in the stack trace. A single
event that big wedged the audit archive queue.

Bound exception messages at the source: `get-hint` clamps to
`max-message-length` (1000 chars), and the CLJS `format-throwable`
clamps the message line of the stack trace and honors `:trace-length`
(parity with the CLJ version). `report-context` now prints `get-hint`
instead of the raw `:hint` from `ex-data`.

Fix `first-line` on the JVM: `cuerdas/index-of` returns nil when the
substring is missing and `(pos? nil)` throws there (it is false in
CLJS), so single-line messages crashed the backend path.

AI-assisted-by: deepseek-v4.1-flash
2026-10-15 10:19:26 +02:00

56 lines
2.0 KiB
Clojure

;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS SUBSIDIARY SL
(ns frontend-tests.data.modal-test
(:require
[app.common.uuid :as uuid]
[app.main.data.event :as ev]
[app.main.data.modal :as modal]
[cljs.test :as t :include-macros true]))
(t/deftest export-shapes-modal-event-carries-a-summary
(let [shape-a (uuid/next)
shape-b (uuid/next)
exports [{:object-id shape-a :type :png}
{:object-id shape-a :type :svg}
{:object-id shape-b :type :png}]
event (modal/show :export-shapes
{:exports exports
:origin "workspace:sidebar"
:name "Page 1"})
data (ev/-data event)]
(t/testing "the raw exports never leak into the event"
(t/is (not (contains? data :exports))))
(t/testing "the event carries counters instead"
(t/is (= 3 (:num-exports data)))
(t/is (= 2 (:num-shapes data)))
(t/is (= 2 (:png data)))
(t/is (= 1 (:svg data))))
(t/testing "the modal context is preserved"
(t/is (= "Page 1" (:page data)))
(t/is (= :export-shapes (:name data))))
(t/testing "origin is emitted as event metadata, not as a prop"
(t/is (= "workspace:sidebar" (::ev/origin data)))
(t/is (not (contains? data :origin))))))
(t/deftest other-modals-keep-their-props
(let [event (modal/show :some-modal {:foo "bar" :items [1 2 3]})
data (ev/-data event)]
(t/is (= "bar" (:foo data)))
(t/is (= [1 2 3] (:items data)))
(t/is (= :some-modal (:name data)))))
(t/deftest modal-origin-becomes-event-metadata
(let [event (modal/show :some-modal {:foo "bar" :origin "dashboard"})
data (ev/-data event)]
(t/is (= "dashboard" (::ev/origin data)))
(t/is (not (contains? data :origin)))
(t/is (= "bar" (:foo data)))))