Skip to content

Ux analytics plugin #3044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 47 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
225a350
skeleton for UXA plugin
daykin Apr 22, 2024
2f52353
Working ToolkitListener for tab containers
daykin May 23, 2024
89d2aa0
sort-of fixed duplicate listener issue
daykin May 29, 2024
8e41348
Listening hierarchy works, but doesn't do anything interesting yet
daykin May 29, 2024
46927ce
begin backend connection reference implementations
daykin Jun 10, 2024
34ea9b3
update pom versions and remove a test MRE
daykin Jun 10, 2024
f0ffc99
dumb sort-of working example after rebase
daykin Jun 11, 2024
738cefc
connect listeners to backends
daykin Jun 12, 2024
2ae938a
add ResourceOpenedListener so interested parties can find out what ca…
daykin Jun 18, 2024
b8ce07b
Revert "add ResourceOpenedListener so interested parties can find out…
daykin Jun 18, 2024
c39bb26
static file helpers
daykin Jun 19, 2024
921fa8a
Plugin now knows who opened a given display
daykin Jun 19, 2024
c992200
plugin knows about nav buttons, action buttons, reload, file browser,…
daykin Jun 20, 2024
76ac188
In case of action buttons, reliably know about source and destination…
daykin Jun 20, 2024
f5d5aad
path normalization utils
daykin Jul 2, 2024
4239306
mostly-working end-to-end neo4j connection
daykin Jul 2, 2024
511ace7
Implement image clients, default to storing screencaps in base-64 mon…
daykin Jul 10, 2024
aa27613
reorganize
daykin Jul 10, 2024
e2dbbb4
begin using credentials manager
daykin Jul 10, 2024
5743354
try to auto-login on startup
daykin Jul 15, 2024
558d528
catch correct method when display opened via action
daykin Dec 9, 2024
e4eaa8f
catch correct method when display opened via file browser
daykin Dec 10, 2024
88c1b7c
use 'x.class.getName()' so IDEs catch package refactoring
daykin Dec 10, 2024
22ded17
connect to a middleware application instead of directly to the server…
daykin Mar 26, 2025
9236c9e
Keep file extensions
daykin Apr 10, 2025
ad3d192
don't log repeated errors, to avoid spamming the log
daykin Apr 10, 2025
43ed7d2
don't force runLater in serviceLayerConnection, caller can do so if n…
daykin Apr 14, 2025
622bca1
don't force runLater in serviceLayerConnection, caller can do so if n…
daykin Apr 14, 2025
479a4a7
tests for UXA service layer connection
daykin Apr 14, 2025
ca24f2f
add accessors for 'mangled' analytics name and mouse listener
daykin Apr 25, 2025
448fe44
remove duplicate addEventFilter from UXAMouseMonitor EventHandler
daykin Apr 25, 2025
6d2e199
more robust null rejection for things outside of a meaningful tree th…
daykin Apr 25, 2025
133709e
clear and reinitialize if tracking (re)starts after application startup
daykin Apr 25, 2025
87c3754
Mouse handler needs to know about tab
daykin Apr 25, 2025
b6ea694
FileUtils improvements: LRU cache for SHA256 sums, correctly handle b…
daykin Apr 25, 2025
dcfb6fd
Unit tests for service layer connection
daykin Apr 25, 2025
948b40e
Unit tests for FileUtils helper
daykin Apr 25, 2025
54574d5
Unit tests for ActiveTab wrapper
daykin Apr 25, 2025
f221807
update dependencies
daykin Apr 25, 2025
ffea9ec
properly handle removal of a tab - can't use ListChangeListener becau…
daykin Apr 28, 2025
c9e4a2f
UXAToolkitListener method-call handler only cares when monitor.getPho…
daykin Apr 28, 2025
1610e68
update existing tests to reflect ActiveTab revision
daykin Apr 28, 2025
ca9487f
tests for ActiveWindowsService tab hierarchy tracker
daykin Apr 28, 2025
c5256c8
ensure all tests can be run together (avoid IllegalStateException fro…
daykin Apr 28, 2025
61b24e3
ignore tabs that aren't DockItemWithInput
daykin Apr 29, 2025
13453b9
move analytics consent persistent file to `Locations.user()`
daykin Apr 29, 2025
c72e036
Merge branch 'ControlSystemStudio:master' into ux-analytics-plugin
daykin Apr 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import java.util.Optional;
import java.util.concurrent.FutureTask;

import java.util.Optional;
import java.util.concurrent.FutureTask;

/** Listener to a widget representation
*
* <p>Provides notification of events (action invoked, ..)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ public static DisplayRuntimeInstance ofDisplayModel(final DisplayModel model)
layout.addEventFilter(KeyEvent.KEY_PRESSED, this::handleKeys);

dock_item.addClosedNotification(this::onClosed);
representation_init.run();
}

@Override
Expand Down Expand Up @@ -530,6 +531,11 @@ public void onClosed()
navigation.dispose();
}

DisplayModel getActiveModel()
{
return active_model;
}

public void addListener(ToolkitListener listener){
this.getRepresentation().removeListener(listener);
this.getRepresentation().addListener(listener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import org.csstudio.display.builder.model.DisplayModel;
import org.csstudio.display.builder.model.Widget;
import org.csstudio.display.builder.representation.ToolkitListener;
import org.csstudio.display.builder.representation.ToolkitRepresentation;
import org.csstudio.display.builder.representation.javafx.JFXRepresentation;
import org.phoebus.framework.workbench.ApplicationService;
Expand Down
1 change: 1 addition & 0 deletions app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@
<module>imageviewer</module>
<module>credentials-management</module>
<module>eslog</module>
<module>ux-analytics</module>
</modules>
</project>
186 changes: 186 additions & 0 deletions app/ux-analytics/monitor/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<parent>
<groupId>org.phoebus</groupId>
<artifactId>app-ux-analytics</artifactId>
<version>4.7.4-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-analytics-monitor</artifactId>

<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-framework</artifactId>
<version>4.7.4-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>5.19.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-ui</artifactId>
<version>4.7.4-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>app-display-model</artifactId>
<version>4.7.4-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>app-display-runtime</artifactId>
<version>4.7.4-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.4.0</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.jersey.contribs/jersey-multipart -->
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.22.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>app-filebrowser</artifactId>
<version>4.7.4-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testfx</groupId>
<artifactId>testfx-junit</artifactId>
<version>4.0.13-alpha</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.fxml</include>
</includes>
</resource>
</resources>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.phoebus.applications.uxanalytics.monitor;


import java.util.ArrayList;
import java.util.concurrent.ExecutorService;

import javafx.stage.Stage;
import org.csstudio.display.builder.runtime.RuntimeUtil;
import org.phoebus.applications.uxanalytics.monitor.backend.database.BackendConnection;
import org.phoebus.applications.uxanalytics.monitor.representation.ActiveWindowsService;

/**
* Singleton Class to capture UI events (clicks, PV Writes, Display open/close)
* and dispatch them to backend connections
*/
public class UXAMonitor{
private static final UXAMonitor instance = new UXAMonitor();
private ArrayList<Stage> activeStages;
private static ActiveWindowsService activeWindowsService = ActiveWindowsService.getInstance();
private static final ExecutorService executor = RuntimeUtil.getExecutor();

//This dispatcher has exactly one phoebus related connection and one JFX related connection
//If you want to broadcast to multiple back-ends, subclass BackendConnection to notify them.
private BackendConnection phoebusConnection;
private BackendConnection jfxConnection;

private UXAMonitor(){
}

public BackendConnection getJfxConnection() {return jfxConnection;}

public BackendConnection getPhoebusConnection() { return phoebusConnection;}

public static synchronized UXAMonitor getInstance() {
return instance;
}

public void notifyConnectionChange(BackendConnection connection){
jfxConnection = connection;
phoebusConnection = connection;
}

public void setPhoebusConnection(BackendConnection phoebusConnection) {
this.phoebusConnection = phoebusConnection;
}

public void disableTracking(){
activeWindowsService.stop();
}

public void enableTracking(){
activeWindowsService.start();
}

public void setJfxConnection(BackendConnection jfxConnection) {
this.jfxConnection = jfxConnection;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.phoebus.applications.uxanalytics.monitor;

import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import org.phoebus.applications.uxanalytics.monitor.representation.ActiveTab;

public class UXAMouseMonitor implements EventHandler<MouseEvent>{

private final UXAMonitor monitor = UXAMonitor.getInstance();
private final ActiveTab tab;

public UXAMouseMonitor(ActiveTab tab){
this.tab = tab;
}

@Override
public void handle(MouseEvent event) {
if(event.getEventType().equals(MouseEvent.MOUSE_CLICKED)){
monitor.getJfxConnection().handleClick(tab, (int) event.getX(), (int) event.getY());
}
}
}
Loading
Loading