Skip to content
Merged
Changes from all commits
Commits
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
398 changes: 398 additions & 0 deletions src/main/java/org/carlmontrobotics/lib199/vendorLibs/Elastic.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,398 @@
// Copyright (c) 2023-2025 Gold87 and other Elastic contributors
// This software can be modified and/or shared under the terms
// defined by the Elastic license:
// https://github.com/Gold872/elastic-dashboard/blob/main/LICENSE

// From: https://frc-elastic.gitbook.io/docs/additional-features-and-references/robot-notifications-with-elasticlib and https://github.com/Gold872/elastic-dashboard/blob/main/elasticlib/Elastic.java

package org.carlmontrobotics.lib199.vendorLibs;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.PubSubOption;
import edu.wpi.first.networktables.StringPublisher;
import edu.wpi.first.networktables.StringTopic;
/**
* A class that provides methods for interacting with the Elastic dashboard, including sending
* notifications and selecting tabs. This taken straight from the official Elastic documentation
* (see https://frc-elastic.gitbook.io/docs/additional-features-and-references/robot-notifications-with-elasticlib for documentation
* and for original code https://github.com/Gold872/elastic-dashboard/blob/main/elasticlib/Elastic.java)
*/

public final class Elastic {
private static final StringTopic notificationTopic =
NetworkTableInstance.getDefault().getStringTopic("/Elastic/RobotNotifications");
private static final StringPublisher notificationPublisher =
notificationTopic.publish(PubSubOption.sendAll(true), PubSubOption.keepDuplicates(true));
private static final StringTopic selectedTabTopic =
NetworkTableInstance.getDefault().getStringTopic("/Elastic/SelectedTab");
private static final StringPublisher selectedTabPublisher =
selectedTabTopic.publish(PubSubOption.keepDuplicates(true));
private static final ObjectMapper objectMapper = new ObjectMapper();

/**
* Represents the possible levels of notifications for the Elastic dashboard. These levels are
* used to indicate the severity or type of notification.
*/
public enum NotificationLevel {
/** Informational Message */
INFO,
/** Warning message */
WARNING,
/** Error message */
ERROR
}

/**
* Sends an notification to the Elastic dashboard. The notification is serialized as a JSON string
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phrase "Sends an notification" contains a grammatical error. The article "an" should be "a" since "notification" starts with a consonant sound.

Suggested change
* Sends an notification to the Elastic dashboard. The notification is serialized as a JSON string
* Sends a notification to the Elastic dashboard. The notification is serialized as a JSON string

Copilot uses AI. Check for mistakes.
* before being published.
*
* @param notification the {@link Notification} object containing notification details
*/
public static void sendNotification(Notification notification) {
try {
notificationPublisher.set(objectMapper.writeValueAsString(notification));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}

/**
* Selects the tab of the dashboard with the given name. If no tab matches the name, this will
* have no effect on the widgets or tabs in view.
*
* <p>If the given name is a number, Elastic will select the tab whose index equals the number
* provided.
*
* @param tabName the name of the tab to select
*/
public static void selectTab(String tabName) {
selectedTabPublisher.set(tabName);
}

/**
* Selects the tab of the dashboard at the given index. If this index is greater than or equal to
* the number of tabs, this will have no effect.
*
* @param tabIndex the index of the tab to select.
*/
public static void selectTab(int tabIndex) {
selectTab(Integer.toString(tabIndex));
}

/**
* Represents an notification object to be sent to the Elastic dashboard. This object holds
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phrase "Represents an notification object" contains a grammatical error. The article "an" should be "a" since "notification" starts with a consonant sound.

Copilot uses AI. Check for mistakes.
* properties such as level, title, description, display time, and dimensions to control how the
* notification is displayed on the dashboard.
*/
public static class Notification {
@JsonProperty("level")
private NotificationLevel level;

@JsonProperty("title")
private String title;

@JsonProperty("description")
private String description;

@JsonProperty("displayTime")
private int displayTimeMillis;

@JsonProperty("width")
private double width;

@JsonProperty("height")
private double height;

/**
* Creates a new Notification with all default parameters. This constructor is intended to be
* used with the chainable decorator methods
*
* <p>Title and description fields are empty.
*/
public Notification() {
this(NotificationLevel.INFO, "", "");
}

/**
* Creates a new Notification with all properties specified.
*
* @param level the level of the notification (e.g., INFO, WARNING, ERROR)
* @param title the title text of the notification
* @param description the descriptive text of the notification
* @param displayTimeMillis the time in milliseconds for which the notification is displayed
* @param width the width of the notification display area
* @param height the height of the notification display area, inferred if below zero
*/
public Notification(
NotificationLevel level,
String title,
String description,
int displayTimeMillis,
double width,
double height) {
this.level = level;
this.title = title;
this.displayTimeMillis = displayTimeMillis;
this.description = description;
this.height = height;
this.width = width;
}

/**
* Creates a new Notification with default display time and dimensions.
*
* @param level the level of the notification
* @param title the title text of the notification
* @param description the descriptive text of the notification
*/
public Notification(NotificationLevel level, String title, String description) {
this(level, title, description, 3000, 350, -1);
}

/**
* Creates a new Notification with a specified display time and default dimensions.
*
* @param level the level of the notification
* @param title the title text of the notification
* @param description the descriptive text of the notification
* @param displayTimeMillis the display time in milliseconds
*/
public Notification(
NotificationLevel level, String title, String description, int displayTimeMillis) {
this(level, title, description, displayTimeMillis, 350, -1);
}

/**
* Creates a new Notification with specified dimensions and default display time. If the height
* is below zero, it is automatically inferred based on screen size.
*
* @param level the level of the notification
* @param title the title text of the notification
* @param description the descriptive text of the notification
* @param width the width of the notification display area
* @param height the height of the notification display area, inferred if below zero
*/
public Notification(
NotificationLevel level, String title, String description, double width, double height) {
this(level, title, description, 3000, width, height);
}

/**
* Updates the level of this notification
*
* @param level the level to set the notification to
*/
public void setLevel(NotificationLevel level) {
this.level = level;
}

/**
* @return the level of this notification
*/
public NotificationLevel getLevel() {
return level;
}

/**
* Updates the title of this notification
*
* @param title the title to set the notification to
*/
public void setTitle(String title) {
this.title = title;
}

/**
* Gets the title of this notification
*
* @return the title of this notification
*/
public String getTitle() {
return title;
}

/**
* Updates the description of this notification
*
* @param description the description to set the notification to
*/
public void setDescription(String description) {
this.description = description;
}

Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method getDescription() is missing a Javadoc comment, while all other getter methods in the class have documentation. This creates inconsistency in the API documentation.

Suggested change
/**
* Gets the description of this notification
*
* @return the description of this notification
*/

Copilot uses AI. Check for mistakes.
public String getDescription() {
return description;
}

/**
* Updates the display time of the notification
*
* @param seconds the number of seconds to display the notification for
*/
public void setDisplayTimeSeconds(double seconds) {
setDisplayTimeMillis((int) Math.round(seconds * 1000));
}

/**
* Updates the display time of the notification in milliseconds
*
* @param displayTimeMillis the number of milliseconds to display the notification for
*/
public void setDisplayTimeMillis(int displayTimeMillis) {
this.displayTimeMillis = displayTimeMillis;
}

/**
* Gets the display time of the notification in milliseconds
*
* @return the number of milliseconds the notification is displayed for
*/
public int getDisplayTimeMillis() {
return displayTimeMillis;
}

/**
* Updates the width of the notification
*
* @param width the width to set the notification to
*/
public void setWidth(double width) {
this.width = width;
}

/**
* Gets the width of the notification
*
* @return the width of the notification
*/
public double getWidth() {
return width;
}

/**
* Updates the height of the notification
*
* <p>If the height is set to -1, the height will be determined automatically by the dashboard
*
* @param height the height to set the notification to
*/
public void setHeight(double height) {
this.height = height;
}

/**
* Gets the height of the notification
*
* @return the height of the notification
*/
public double getHeight() {
return height;
}

/**
* Modifies the notification's level and returns itself to allow for method chaining
*
* @param level the level to set the notification to
* @return the current notification
*/
public Notification withLevel(NotificationLevel level) {
this.level = level;
return this;
}

/**
* Modifies the notification's title and returns itself to allow for method chaining
*
* @param title the title to set the notification to
* @return the current notification
*/
public Notification withTitle(String title) {
setTitle(title);
return this;
}

/**
* Modifies the notification's description and returns itself to allow for method chaining
*
* @param description the description to set the notification to
* @return the current notification
*/
public Notification withDescription(String description) {
setDescription(description);
return this;
}

/**
* Modifies the notification's display time and returns itself to allow for method chaining
*
* @param seconds the number of seconds to display the notification for
* @return the current notification
*/
public Notification withDisplaySeconds(double seconds) {
return withDisplayMilliseconds((int) Math.round(seconds * 1000));
}

/**
* Modifies the notification's display time and returns itself to allow for method chaining
*
* @param displayTimeMillis the number of milliseconds to display the notification for
* @return the current notification
*/
public Notification withDisplayMilliseconds(int displayTimeMillis) {
setDisplayTimeMillis(displayTimeMillis);
return this;
}

/**
* Modifies the notification's width and returns itself to allow for method chaining
*
* @param width the width to set the notification to
* @return the current notification
*/
public Notification withWidth(double width) {
setWidth(width);
return this;
}

/**
* Modifies the notification's height and returns itself to allow for method chaining
*
* @param height the height to set the notification to
* @return the current notification
*/
public Notification withHeight(double height) {
setHeight(height);
return this;
}

/**
* Modifies the notification's height and returns itself to allow for method chaining
*
* <p>This will set the height to -1 to have it automatically determined by the dashboard
*
* @return the current notification
*/
public Notification withAutomaticHeight() {
setHeight(-1);
return this;
}

/**
* Modifies the notification to disable the auto dismiss behavior
*
* <p>This sets the display time to 0 milliseconds
*
* <p>The auto dismiss behavior can be re-enabled by setting the display time to a number
* greater than 0
*
* @return the current notification
*/
public Notification withNoAutoDismiss() {
setDisplayTimeMillis(0);
return this;
}
}
}
Comment on lines +24 to +398
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Elastic class lacks test coverage. Similar utility classes in this project (e.g., Limelight, LinearInterpolation) have comprehensive unit tests. Consider adding tests to verify notification serialization, NetworkTable publishing behavior, and the various Notification builder methods work correctly.

Copilot uses AI. Check for mistakes.