From 9fded5c2eb884e907fd171614d7bf273e0101f99 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 6 Aug 2026 07:57:05 +0000 Subject: [PATCH] :sparkles: Emit open-workspace-file audit event with file statistics Add a new audit event that fires once when the workspace is fully loaded and all libraries are resolved. The event includes file statistics: number of pages, total shapes, average and max shapes per page, number of components, number of linked libraries, whether the file is a shared library, and number of design tokens. Closes #11106 AI-assisted-by: mimo-v2.5-pro --- frontend/src/app/main/data/workspace.cljs | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index cedfad1d96..dac5a5564e 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -22,6 +22,7 @@ [app.common.types.component :as ctc] [app.common.types.components-list :as ctkl] [app.common.types.shape :as cts] + [app.common.types.tokens-lib :as ctob] [app.common.types.variant :as ctv] [app.common.uuid :as uuid] [app.config :as cf] @@ -266,6 +267,46 @@ (rx/map (fn [_] (mcp/init)))) (rx/empty)))))) +(defn- emit-workspace-file-stats + [file-id] + (letfn [(count-shapes-per-page [file-data] + (let [pages-index (:pages-index file-data)] + (mapv #(count (:objects (val %))) pages-index))) + + (compute-stats [state] + (let [file (dsh/lookup-file state file-id) + file-data (:data file) + libraries (dsh/lookup-libraries state) + shapes (count-shapes-per-page file-data) + n-pages (count (:pages file-data)) + n-shapes (reduce + 0 shapes) + n-components (count (ctkl/components-seq file-data)) + n-linked-libs (dec (count libraries)) + tokens-lib (:tokens-lib file-data) + n-tokens (if (some? tokens-lib) + (count (ctob/get-all-tokens tokens-lib)) + 0)] + + {::ev/name "open-workspace-file" + ::ev/origin "workspace" + :num-pages n-pages + :num-shapes n-shapes + :avg-shapes-per-page (if (pos? n-pages) + (Math/round (/ n-shapes n-pages)) + 0) + :max-shapes-per-page (if (seq shapes) + (apply max shapes) + 0) + :num-components n-components + :num-linked-libraries (max 0 n-linked-libs) + :is-library (:is-shared file) + :num-tokens n-tokens}))] + (ptk/reify ::emit-workspace-file-stats + ptk/WatchEvent + (watch [_ state _] + (let [stats (compute-stats state)] + (rx/of (ev/event stats))))))) + (defn- bundle-fetched [{:keys [file file-id thumbnails] :as bundle}] (ptk/reify ::bundle-fetched @@ -420,6 +461,12 @@ (rx/take 1) (rx/map dwc/set-workspace-visited)) + ;; Emit audit event with file statistics once all libraries are resolved + (->> stream + (rx/filter (ptk/type? ::all-libraries-resolved)) + (rx/take 1) + (rx/map #(emit-workspace-file-stats file-id))) + (when-let [component-id (some-> rparams :component-id uuid/parse)] (->> stream (rx/filter (ptk/type? ::workspace-initialized))