Skip to content
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.gradle
.idea
build
.DS_Store
.DS_Store
video/
*.avi
1 change: 0 additions & 1 deletion src/main/java/com/checkmarx/intellij/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ private Constants() {
public static final String CONFIRMED = "CONFIRMED";
public static final String TO_VERIFY = "TO_VERIFY";
public static final String URGENT = "URGENT";
public static final String ERROR = "Error";


public static final String USE_LOCAL_BRANCH = "scan my local branch";
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/com/checkmarx/intellij/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public final class Utils {
private static Project cxProject;
private static MessageBus messageBus;

// Flag to prevent duplicate "Session Expired" notifications
private static volatile boolean sessionExpiredNotificationShown = false;

private static Project getCxProject() {
if (cxProject == null && ApplicationManager.getApplication() != null) {
cxProject = ProjectManager.getInstance().getDefaultProject();
Expand Down Expand Up @@ -370,9 +373,16 @@ public static LocalDateTime convertToLocalDateTime(Long duration, ZoneId zoneId)
}

/**
* Notify on user session expired and publish new state
* Notify on user session expired and publish new state.
* Uses a flag to prevent duplicate notifications when multiple services detect session expiry.
*/
public static void notifySessionExpired() {
// Prevent duplicate notifications - only show once per session expiry
if (sessionExpiredNotificationShown) {
return;
}
sessionExpiredNotificationShown = true;

ApplicationManager.getApplication().invokeLater(() ->
Utils.showNotification(Bundle.message(Resource.SESSION_EXPIRED_TITLE),
Bundle.message(Resource.ERROR_SESSION_EXPIRED),
Expand All @@ -384,6 +394,14 @@ public static void notifySessionExpired() {
);
}

/**
* Resets the session expired notification flag.
* Should be called when user logs in successfully or explicitly logs out.
*/
public static void resetSessionExpiredNotificationFlag() {
sessionExpiredNotificationShown = false;
}

/**
* Checking the requested filter is enabled or not by the user
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,34 @@
import java.util.*;

/**
* Toolbar actions for the Ignored Findings tab.
* Provides filter dropdown (vulnerability types), sort dropdown, and severity filters.
* Uses independent state from CxFindingsWindow to avoid cross-tab interference.
* Toolbar actions for the Ignored Findings tab in the Checkmarx tool window.
*
* <p>This class provides:
* <ul>
* <li><b>Severity filters</b> - Toggle buttons for MALICIOUS, CRITICAL, HIGH, MEDIUM, LOW</li>
* <li><b>Type filter dropdown</b> - Filter by vulnerability type (SAST, SCA, Secrets, IaC, Containers)</li>
* <li><b>Sort dropdown</b> - Sort by severity or last updated date</li>
* </ul>
*
* <p>Uses independent state from CxFindingsWindow to avoid cross-tab filter interference.
* State is managed by singleton instances: {@link TypeFilterState}, {@link SortState},
* and {@link IgnoredFindingsSeverityFilterState}.
*
* @see com.checkmarx.intellij.devassist.ui.findings.window.CxIgnoredFindings
*/
public class IgnoredFindingsToolbarActions {

// ========== Message Topics ==========
// ========== Message Topics for Filter/Sort Changes ==========

/** Topic for vulnerability type filter changes. */
public static final Topic<TypeFilterChanged> TYPE_FILTER_TOPIC =
Topic.create("Type Filter Changed", TypeFilterChanged.class);

/** Topic for sort order changes. */
public static final Topic<SortChanged> SORT_TOPIC =
Topic.create("Sort Changed", SortChanged.class);

/** Topic for severity filter changes (independent from CxFindingsWindow). */
public static final Topic<SeverityFilterChanged> SEVERITY_FILTER_TOPIC =
Topic.create("Ignored Findings Severity Filter Changed", SeverityFilterChanged.class);

Expand Down Expand Up @@ -286,33 +302,43 @@ public static class IgnoredLowFilter extends IgnoredFindingsSeverityFilter {
@Override protected Filterable getFilterable() { return Severity.LOW; }
}

// ========== State Managers ==========
// ========== State Managers (Singleton Pattern) ==========

/** State manager for vulnerability type filters */
/**
* Singleton state manager for vulnerability type filters.
* Tracks which scan engines (SAST, SCA, Secrets, etc.) are selected.
* Thread-safe via synchronized set.
*/
public static class TypeFilterState {
private static final TypeFilterState INSTANCE = new TypeFilterState();
private final Set<ScanEngine> selectedEngines = Collections.synchronizedSet(EnumSet.allOf(ScanEngine.class));

private TypeFilterState() { selectedEngines.remove(ScanEngine.ALL); }

public static TypeFilterState getInstance() { return INSTANCE; }

public boolean isSelected(ScanEngine engine) { return selectedEngines.contains(engine); }

public void setSelected(ScanEngine engine, boolean selected) {
if (selected) selectedEngines.add(engine);
else selectedEngines.remove(engine);
}

/** Returns a copy of currently selected engines. */
public Set<ScanEngine> getSelectedEngines() { return new HashSet<>(selectedEngines); }

/** Returns true if any engine is deselected (i.e., filtering is active). */
public boolean hasActiveFilters() {
Set<ScanEngine> allRealEngines = EnumSet.allOf(ScanEngine.class);
allRealEngines.remove(ScanEngine.ALL);
return !selectedEngines.containsAll(allRealEngines);
}
}

/** State manager for sort settings */
/**
* Singleton state manager for sort settings.
* Tracks the current sort field and date order.
*/
public static class SortState {
private static final SortState INSTANCE = new SortState();
private SortField sortField = SortField.SEVERITY_HIGH_TO_LOW;
Expand All @@ -329,7 +355,11 @@ private SortState() {}
public void setDateOrder(DateOrder dateOrder) { this.dateOrder = dateOrder; }
}

/** State manager for severity filters - is independent of CxFindingsWindow */
/**
* Singleton state manager for severity filters.
* Independent from CxFindingsWindow to prevent cross-tab interference.
* Thread-safe via synchronized set.
*/
public static class IgnoredFindingsSeverityFilterState {
private static final IgnoredFindingsSeverityFilterState INSTANCE = new IgnoredFindingsSeverityFilterState();
private final Set<Filterable> selectedFilters = Collections.synchronizedSet(new HashSet<>());
Expand All @@ -338,6 +368,7 @@ public static class IgnoredFindingsSeverityFilterState {

public static IgnoredFindingsSeverityFilterState getInstance() { return INSTANCE; }

/** Returns selected filters, restoring defaults if empty. */
public Set<Filterable> getFilters() {
if (selectedFilters.isEmpty()) selectedFilters.addAll(Severity.DEFAULT_SEVERITIES);
return selectedFilters;
Expand All @@ -353,7 +384,12 @@ public void setSelected(Filterable filterable, boolean selected) {

// ========== Listener Interfaces ==========

/** Listener for vulnerability type filter changes. */
public interface TypeFilterChanged { void filterChanged(); }

/** Listener for sort order changes. */
public interface SortChanged { void sortChanged(); }

/** Listener for severity filter changes. */
public interface SeverityFilterChanged { void filterChanged(); }
}
Loading
Loading