Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -77,37 +77,52 @@ private void setupGUI() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

this.topMenu = new JPanel();
BoxLayout layout = new BoxLayout(topMenu, BoxLayout.X_AXIS);
topMenu.setLayout(layout);
topMenu.setLayout(new BoxLayout(topMenu, BoxLayout.Y_AXIS)); // Main panel with vertical layout

// First row with "Users" and "Groups"
JPanel row1 = new JPanel();
row1.setLayout(new BoxLayout(row1, BoxLayout.X_AXIS));
// top level buttons
JButton listUsersButton = new JButton(UIUtils.getClasspathImage(this.getClass(), "/org/janelia/workstation/admin/images/user.png"));
listUsersButton.setText("Users");
listUsersButton.setToolTipText("Show all users");
listUsersButton.setVerticalTextPosition(SwingConstants.BOTTOM);
listUsersButton.setHorizontalTextPosition(SwingConstants.CENTER);
listUsersButton.addActionListener(event -> viewUserList());
topMenu.add(listUsersButton);
row1.add(listUsersButton);

topMenu.add(Box.createHorizontalStrut(20));
row1.add(Box.createHorizontalStrut(20)); // Add space between buttons

JButton listGroupsButton = new JButton(UIUtils.getClasspathImage(this.getClass(), "/org/janelia/workstation/admin/images/group.png"));
listGroupsButton.setText("Groups");
listGroupsButton.addActionListener(event -> viewGroupList());
listGroupsButton.setToolTipText("Show all groups");
listGroupsButton.setVerticalTextPosition(SwingConstants.BOTTOM);
listGroupsButton.setHorizontalTextPosition(SwingConstants.CENTER);
topMenu.add(listGroupsButton);

topMenu.add(Box.createHorizontalStrut(20));
listGroupsButton.addActionListener(event -> viewGroupList());
row1.add(listGroupsButton);

row1.add(Box.createHorizontalStrut(20));
JButton getLogsButton = new JButton(UIUtils.getClasspathImage(this.getClass(), "/org/janelia/workstation/admin/images/logs.png"));
getLogsButton.setText("Logs");
getLogsButton.setToolTipText("Retrieve Logs");
getLogsButton.addActionListener(event -> getLogs());
getLogsButton.setVerticalTextPosition(SwingConstants.BOTTOM);
getLogsButton.setHorizontalTextPosition(SwingConstants.CENTER);
topMenu.add(getLogsButton);
row1.add(getLogsButton);

row1.add(Box.createHorizontalStrut(20));

JButton workspaceCleanupButton = new JButton(UIUtils.getClasspathImage(this.getClass(), "/org/janelia/workstation/admin/images/clean.png"));
workspaceCleanupButton.setText("Cleanup Db");
workspaceCleanupButton.setToolTipText("Manage and delete large workspaces");
workspaceCleanupButton.setVerticalTextPosition(SwingConstants.BOTTOM);
workspaceCleanupButton.setHorizontalTextPosition(SwingConstants.CENTER);
workspaceCleanupButton.addActionListener(event -> databaseCleanup());
row1.add(workspaceCleanupButton);

// Add both rows to the main menu
topMenu.add(row1);

add(topMenu);
add(Box.createVerticalGlue());
Expand All @@ -127,6 +142,15 @@ public void objectsInvalidated(DomainObjectInvalidationEvent event) {
}
}

void databaseCleanup() {
DatabaseCleanupPanel panel = new DatabaseCleanupPanel(this);
removeAll();
add(panel);
revalidate();
repaint();
this.currentView = panel;
}

void viewUserList() {
UserManagementPanel panel = new UserManagementPanel(this);
removeAll();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package org.janelia.workstation.admin;

import org.janelia.model.domain.tiledMicroscope.TmWorkspace;
import org.janelia.model.domain.tiledMicroscope.TmWorkspaceInfo;
import org.janelia.workstation.common.gui.support.DesktopApi;
import org.janelia.workstation.controller.access.TiledMicroscopeDomainMgr;
import org.janelia.workstation.core.util.Refreshable;
import org.janelia.workstation.core.workers.BackgroundWorker;
import org.janelia.workstation.core.workers.SimpleWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

public class DatabaseCleanupPanel extends JPanel implements Refreshable {
private static final Logger log = LoggerFactory.getLogger(DatabaseCleanupPanel.class);
private final AdministrationTopComponent parent;
private JTable workspaceTable;
private WorkspaceTableModel tableModel;

public DatabaseCleanupPanel(AdministrationTopComponent parent) {
this.parent = parent;
refresh();
}

private void setupUI() {
setLayout(new BorderLayout());
removeAll();

JPanel titlePanel = new TitlePanel("Manage Workspaces", "Return To Top Menu",
event -> refresh(),
event -> returnHome());
add(titlePanel, BorderLayout.NORTH);

tableModel = new WorkspaceTableModel();
workspaceTable = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(workspaceTable);
add(scrollPane, BorderLayout.CENTER);

JButton refreshButton = new JButton("Load Largest Workspaces");
refreshButton.addActionListener(e -> loadLargestWorkspaces());

JButton deleteButton = new JButton("Delete Selected Workspaces");
deleteButton.addActionListener(e -> deleteSelectedWorkspaces());

JPanel buttonPanel = new JPanel();
buttonPanel.add(refreshButton);
buttonPanel.add(deleteButton);
add(buttonPanel, BorderLayout.SOUTH);

revalidate();
}

private void loadLargestWorkspaces() {
SimpleWorker worker = new SimpleWorker() {
private List<TmWorkspaceInfo> workspaceResults;

@Override
protected void doStuff() {
TiledMicroscopeDomainMgr domainMgr = TiledMicroscopeDomainMgr.getDomainMgr();
workspaceResults = domainMgr.getLargestWorkspaces();
}

@Override
protected void hadSuccess() {
tableModel.clear();
tableModel.setWorkspaces(workspaceResults);
}

@Override
protected void hadError(Throwable error) {
log.error("Error loading workspaces", error);
JOptionPane.showMessageDialog(DatabaseCleanupPanel.this,
"Failed to load workspaces: " + error.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
};
worker.execute();
}

private void deleteSelectedWorkspaces() {
List<Long> selectedWorkspaces = tableModel.getSelectedWorkspaces();
if (selectedWorkspaces.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select at least one workspace to delete.", "No Selection", JOptionPane.WARNING_MESSAGE);
return;
}

int confirmation = JOptionPane.showConfirmDialog(this,
"Are you sure you want to delete the selected workspaces?",
"Confirm Deletion", JOptionPane.YES_NO_OPTION);

if (confirmation == JOptionPane.YES_OPTION) {

BackgroundWorker deleter = new BackgroundWorker() {
@Override
public String getName() {
return "Deleting TmWorkspaces";
}

@Override
protected void doStuff() {
TiledMicroscopeDomainMgr domainMgr = TiledMicroscopeDomainMgr.getDomainMgr();
domainMgr.removeWorkspaces(selectedWorkspaces);
}

@Override
protected void hadSuccess() {
loadLargestWorkspaces();
JOptionPane.showMessageDialog(DatabaseCleanupPanel.this,
"Selected workspaces deleted successfully.", "Success", JOptionPane.INFORMATION_MESSAGE);
}

@Override
protected void hadError(Throwable error) {
log.error("Error deleting workspaces", error);
JOptionPane.showMessageDialog(DatabaseCleanupPanel.this,
"Failed to delete workspaces: " + error.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
};
deleter.executeWithEvents();
}
}

@Override
public void refresh() {
setupUI();
}

private void returnHome() {
parent.viewTopMenu();
}
}

class WorkspaceTableModel extends AbstractTableModel {
private final String[] columnNames = {"Select", "Name", "Owner", "Date Created", "Size"};
private List<TmWorkspaceInfo> workspaceResults = new ArrayList<>();
private final List<Boolean> selected = new ArrayList<>();

public void setWorkspaces(List<TmWorkspaceInfo> workspaceResults) {
this.workspaceResults = workspaceResults;
selected.clear();
for (int i = 0; i < workspaceResults.size(); i++) {
selected.add(false); // Initialize selection state
}
fireTableDataChanged();
}

@Override
public int getRowCount() {
return workspaceResults.size();
}

@Override
public int getColumnCount() {
return columnNames.length;
}

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
TmWorkspaceInfo workspaceInfo = workspaceResults.get(rowIndex);
switch (columnIndex) {
case 0:
return selected.get(rowIndex); // Boolean checkbox
case 1:
return workspaceInfo.getWorkspaceName();
case 2:
return workspaceInfo.getOwnerKey();
case 3:
return workspaceInfo.getDateCreated();
case 4:
return workspaceInfo.getTotalSize();
default:
return null;
}
}

@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0; // Allow only checkboxes to be editable
}

@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0 && aValue instanceof Boolean) {
selected.set(rowIndex, (Boolean) aValue);
fireTableCellUpdated(rowIndex, columnIndex); // Notify JTable of the change
}
}

public void clear() {
workspaceResults.clear();
selected.clear();
fireTableDataChanged(); // Notify the table UI that the data has changed
}

@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Boolean.class : String.class;
}

public List<Long> getSelectedWorkspaces() {
List<Long> selectedWorkspaces = new ArrayList<>();
for (int i = 0; i < workspaceResults.size(); i++) {
if (selected.get(i)) {
selectedWorkspaces.add(workspaceResults.get(i).getWorkspaceId());
}
}
return selectedWorkspaces;
}

@Override
public String getColumnName(int column) {
return columnNames[column];
}
}

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.janelia.workstation.core.events.Events;
import org.janelia.workstation.core.events.lifecycle.ConsolePropsLoaded;
import org.janelia.model.domain.tiledMicroscope.BoundingBox3d;
import org.janelia.model.domain.tiledMicroscope.TmWorkspaceInfo;
import org.janelia.workstation.integration.util.FrameworkAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -153,6 +154,11 @@ public Collection<BoundingBox3d> getWorkspaceBoundingBoxes(Long workspaceId) thr
return client.getWorkspaceBoundingBoxes(workspaceId);
}

public List<TmWorkspaceInfo> getLargestWorkspaces () {
LOG.debug("getLargestWorkspaces()");
return client.getLargestWorkspaces(AccessManager.getSubjectKey());
}

public List<TmOperation> getOperationLogs (Long workspaceId, Long neuronId, Date startTime, Date endTime,
String subjectKey) {
LOG.debug("getOperationLogs(workspaceId={}, neuronId={}, startTime={}, endTime={})",
Expand Down Expand Up @@ -231,6 +237,11 @@ public void remove(TmWorkspace workspace) throws Exception {
getModel().notifyDomainObjectRemoved(workspace);
}

public void removeWorkspaces(List<Long> selectedWorkspaces) {
LOG.debug("removeWorkspaces({})", selectedWorkspaces);
client.removeWorkspaces(selectedWorkspaces);
}

class RetrieveNeuronsTask extends RecursiveTask<Stream<TmNeuronMetadata>> {
double defaultLength = 50000.0;
int start;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.ByteStreams;

Expand Down Expand Up @@ -118,6 +119,27 @@ public TmSample create(TmSample tmSample, Map<String, Object> storageAttributes)
return response.readEntity(TmSample.class);
}

public List<TmWorkspaceInfo> getLargestWorkspaces(String subjectKey ) {
WebTarget target = getMouselightDataEndpoint("/workspace/largest")
.queryParam("username", subjectKey);
Response response = target
.request("application/json")
.get();
checkBadResponse(target, response);
try {
String jsonResponse = response.readEntity(String.class);


ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(jsonResponse, new TypeReference<List<TmWorkspaceInfo>>() {
});
} catch (Exception e) {
FrameworkAccess.handleException(e);
LOG.error ("Problems returning the largest workspaces in the db");
throw new RemoteServiceException("Client had problems retrieving largest workspaces");
}
}

public List<TmOperation> getOperationLogs(Long workspaceId, Long neuronId,
Date startTime, Date endTime,
String subjectKey ) {
Expand Down Expand Up @@ -501,4 +523,13 @@ public boolean isServerPathAvailable(String serverPath, boolean directoryOnly, M
int responseStatus = response.getStatus();
return responseStatus == 200;
}

public void removeWorkspaces(List<Long> selectedWorkspaces) {
WebTarget target = getMouselightDataEndpoint("/workspaces/remove");

Response response = target
.request("application/json")
.put(Entity.json(selectedWorkspaces));
checkBadResponse(target, response);
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@

<janeliaws.jetty.version>9.4.46.v20220331</janeliaws.jetty.version>

<janeliaws.jacs-model.version>3.3.0</janeliaws.jacs-model.version>
<janeliaws.jacs-model.version>3.3.4</janeliaws.jacs-model.version>

<janeliaws.jacs-messaging.version>2.5.0</janeliaws.jacs-messaging.version>

Expand Down