Client-side UI widget for long running processes.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@16 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
86f8c630ad
commit
06b5373151
@ -20,6 +20,7 @@ import com.metaweb.gridlock.commands.CreateProjectFromUploadCommand;
|
||||
import com.metaweb.gridlock.commands.DoTextTransformCommand;
|
||||
import com.metaweb.gridlock.commands.GetColumnModelCommand;
|
||||
import com.metaweb.gridlock.commands.GetHistoryCommand;
|
||||
import com.metaweb.gridlock.commands.GetProcessesCommand;
|
||||
import com.metaweb.gridlock.commands.GetProjectMetadataCommand;
|
||||
import com.metaweb.gridlock.commands.GetRowsCommand;
|
||||
import com.metaweb.gridlock.commands.UndoRedoCommand;
|
||||
@ -31,12 +32,15 @@ public class GridlockServlet extends HttpServlet {
|
||||
|
||||
static {
|
||||
_commands.put("create-project-from-upload", new CreateProjectFromUploadCommand());
|
||||
|
||||
_commands.put("get-project-metadata", new GetProjectMetadataCommand());
|
||||
_commands.put("get-column-model", new GetColumnModelCommand());
|
||||
_commands.put("get-rows", new GetRowsCommand());
|
||||
_commands.put("get-processes", new GetProcessesCommand());
|
||||
_commands.put("get-history", new GetHistoryCommand());
|
||||
_commands.put("compute-facets", new ComputeFacetsCommand());
|
||||
|
||||
_commands.put("undo-redo", new UndoRedoCommand());
|
||||
_commands.put("compute-facets", new ComputeFacetsCommand());
|
||||
_commands.put("do-text-transform", new DoTextTransformCommand());
|
||||
}
|
||||
|
||||
|
@ -30,14 +30,13 @@ public class DoTextTransformCommand extends Command {
|
||||
Project project = getProject(request);
|
||||
int cellIndex = Integer.parseInt(request.getParameter("cell"));
|
||||
|
||||
String columnName = null;
|
||||
for (Column column : project.columnModel.columns) {
|
||||
if (column.cellIndex == cellIndex) {
|
||||
columnName = column.headerLabel;
|
||||
break;
|
||||
}
|
||||
Column column = project.columnModel.getColumnByCellIndex(cellIndex);
|
||||
if (column == null) {
|
||||
respond(response, "{ \"code\" : \"error\", \"message\" : \"No such column\" }");
|
||||
return;
|
||||
}
|
||||
|
||||
String columnName = column.headerLabel;
|
||||
String expression = request.getParameter("expression");
|
||||
|
||||
try {
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.metaweb.gridlock.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.metaweb.gridlock.model.Project;
|
||||
|
||||
public class GetProcessesCommand extends Command {
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
Project project = getProject(request);
|
||||
|
||||
try {
|
||||
Properties options = new Properties();
|
||||
|
||||
respondJSON(response, project.processManager.getJSON(options));
|
||||
} catch (JSONException e) {
|
||||
respondException(response, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package com.metaweb.gridlock.history;
|
||||
|
||||
import com.metaweb.gridlock.model.Project;
|
||||
import com.metaweb.gridlock.process.Process;
|
||||
import com.metaweb.gridlock.process.ProcessManager;
|
||||
|
||||
public class HistoryProcess extends Process {
|
||||
final protected Project _project;
|
||||
@ -27,6 +28,6 @@ public class HistoryProcess extends Process {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPerforming() {
|
||||
public void startPerforming(ProcessManager manager) {
|
||||
}
|
||||
}
|
||||
|
@ -37,4 +37,13 @@ public class ColumnModel implements Serializable {
|
||||
}
|
||||
return _nameToColumn.get(name);
|
||||
}
|
||||
|
||||
public Column getColumnByCellIndex(int cellIndex) {
|
||||
for (Column column : columns) {
|
||||
if (column.cellIndex == cellIndex) {
|
||||
return column;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package com.metaweb.gridlock.process;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
abstract public class LongRunningProcess extends Process {
|
||||
final protected String _description;
|
||||
protected ProcessManager _manager;
|
||||
protected Thread _thread;
|
||||
protected int _progress; // out of 100
|
||||
|
||||
protected LongRunningProcess(String description) {
|
||||
_description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
JSONObject getJSON(Properties options) throws JSONException {
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
o.put("description", _description);
|
||||
o.put("immediate", false);
|
||||
o.put("status", _thread == null ? "pending" : (_thread.isAlive() ? "running" : "done"));
|
||||
o.put("progress", _progress);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImmediate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performImmediate() {
|
||||
throw new RuntimeException("Not an immediate process");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPerforming(ProcessManager manager) {
|
||||
if (_thread == null) {
|
||||
_manager = manager;
|
||||
|
||||
_thread = new Thread(getRunnable());
|
||||
_thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected Runnable getRunnable();
|
||||
}
|
@ -1,10 +1,20 @@
|
||||
package com.metaweb.gridlock.process;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class Process {
|
||||
abstract public boolean isImmediate();
|
||||
|
||||
abstract public boolean isRunning();
|
||||
abstract public boolean isDone();
|
||||
|
||||
abstract public void performImmediate();
|
||||
|
||||
abstract public void startPerforming();
|
||||
abstract public void startPerforming(ProcessManager manager);
|
||||
abstract public void cancel();
|
||||
|
||||
abstract JSONObject getJSON(Properties options) throws JSONException;
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
package com.metaweb.gridlock.process;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class ProcessManager {
|
||||
protected List<Process> _processes = new LinkedList<Process>();
|
||||
@ -10,6 +15,18 @@ public class ProcessManager {
|
||||
|
||||
}
|
||||
|
||||
public JSONObject getJSON(Properties options) throws JSONException {
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
List<JSONObject> a = new ArrayList<JSONObject>(_processes.size());
|
||||
for (Process p : _processes) {
|
||||
a.add(p.getJSON(options));
|
||||
}
|
||||
o.put("processes", a);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public boolean queueProcess(Process process) {
|
||||
if (process.isImmediate() && _processes.size() == 0) {
|
||||
process.performImmediate();
|
||||
@ -19,4 +36,25 @@ public class ProcessManager {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onDoneProcess(Process p) {
|
||||
update();
|
||||
}
|
||||
|
||||
protected void update() {
|
||||
while (_processes.size() > 0) {
|
||||
Process p = _processes.get(0);
|
||||
if (p.isImmediate()) {
|
||||
p.performImmediate();
|
||||
_processes.remove(0);
|
||||
} else if (p.isDone()) {
|
||||
_processes.remove(0);
|
||||
} else {
|
||||
if (!p.isRunning()) {
|
||||
p.startPerforming(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package com.metaweb.gridlock.process;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.metaweb.gridlock.history.HistoryEntry;
|
||||
import com.metaweb.gridlock.model.Project;
|
||||
|
||||
public class QuickHistoryEntryProcess extends Process {
|
||||
final protected Project _project;
|
||||
final protected HistoryEntry _historyEntry;
|
||||
boolean _done = false;
|
||||
|
||||
public QuickHistoryEntryProcess(Project project, HistoryEntry historyEntry) {
|
||||
_project = project;
|
||||
@ -14,6 +20,7 @@ public class QuickHistoryEntryProcess extends Process {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
throw new RuntimeException("Not a long-running process");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -22,11 +29,34 @@ public class QuickHistoryEntryProcess extends Process {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performImmediate() {
|
||||
_project.history.addEntry(_historyEntry);
|
||||
public boolean isRunning() {
|
||||
throw new RuntimeException("Not a long-running process");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPerforming() {
|
||||
public void performImmediate() {
|
||||
_project.history.addEntry(_historyEntry);
|
||||
_done = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPerforming(ProcessManager manager) {
|
||||
throw new RuntimeException("Not a long-running process");
|
||||
}
|
||||
|
||||
@Override
|
||||
JSONObject getJSON(Properties options) throws JSONException {
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
o.put("description", _historyEntry.description);
|
||||
o.put("immediate", true);
|
||||
o.put("status", _done ? "done" : "pending");
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return _done;
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
<html>
<head>
<title>Gridlock</title>
<link rel="stylesheet" href="/styles/common.css" />
<link rel="stylesheet" href="/styles/project.css" />
<link rel="stylesheet" href="/styles/history.css" />
<link rel="stylesheet" href="/styles/browsing.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript" src="scripts/util/misc.js"></script>
<script type="text/javascript" src="scripts/util/url.js"></script>
<script type="text/javascript" src="scripts/util/string.js"></script>
<script type="text/javascript" src="scripts/util/ajax.js"></script>
<script type="text/javascript" src="scripts/util/menu.js"></script>
<script type="text/javascript" src="scripts/project.js"></script>
<script type="text/javascript" src="scripts/project/list-facet.js"></script>
<script type="text/javascript" src="scripts/project/browsing-engine.js"></script>
<script type="text/javascript" src="scripts/project/data-table-view.js"></script>
<script type="text/javascript" src="scripts/project/history-widget.js"></script>
</head>
<body>
<div id="header">
<h1 id="title">Gridlock</h1>
</div>
<div id="body">
Loading ...
</div>
</body>
</html>
|
||||
<html>
<head>
<title>Gridlock</title>
<link rel="stylesheet" href="/styles/common.css" />
<link rel="stylesheet" href="/styles/project.css" />
<link rel="stylesheet" href="/styles/history.css" />
<link rel="stylesheet" href="/styles/browsing.css" />
<link rel="stylesheet" href="/styles/process.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript" src="scripts/util/misc.js"></script>
<script type="text/javascript" src="scripts/util/url.js"></script>
<script type="text/javascript" src="scripts/util/string.js"></script>
<script type="text/javascript" src="scripts/util/ajax.js"></script>
<script type="text/javascript" src="scripts/util/menu.js"></script>
<script type="text/javascript" src="scripts/project.js"></script>
<script type="text/javascript" src="scripts/project/list-facet.js"></script>
<script type="text/javascript" src="scripts/project/browsing-engine.js"></script>
<script type="text/javascript" src="scripts/project/data-table-view.js"></script>
<script type="text/javascript" src="scripts/project/history-widget.js"></script>
<script type="text/javascript" src="scripts/project/process-widget.js"></script>
</head>
<body>
<div id="header">
<h1 id="title">Gridlock</h1>
</div>
<div id="body">
Loading ...
</div>
</body>
</html>
|
@ -48,8 +48,10 @@ function initializeUI() {
|
||||
ui.viewPanel = $('<div></div>').appendTo(tdLeft).css("width", tdLeft.offsetWidth + "px").css("overflow-x", "auto");
|
||||
ui.facetPanel = $('<div></div>').appendTo(tdRight);
|
||||
ui.historyPanel = $('<div></div>').addClass("history-panel").appendTo(document.body);
|
||||
ui.processPanel = $('<div></div>').addClass("process-panel").appendTo(document.body);
|
||||
|
||||
ui.browsingEngine = new BrowsingEngine(ui.facetPanel);
|
||||
ui.processWidget = new ProcessWidget(ui.processPanel);
|
||||
ui.historyWidget = new HistoryWidget(ui.historyPanel);
|
||||
ui.dataTableView = new DataTableView(ui.viewPanel);
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ DataTableView.prototype._doTextTransform = function(column, expression) {
|
||||
self.update();
|
||||
ui.historyWidget.update();
|
||||
} else {
|
||||
// update process UI
|
||||
ui.processWidget.update();
|
||||
}
|
||||
},
|
||||
"json"
|
||||
|
58
src/main/webapp/scripts/project/process-widget.js
Normal file
58
src/main/webapp/scripts/project/process-widget.js
Normal file
@ -0,0 +1,58 @@
|
||||
function ProcessWidget(div) {
|
||||
this._div = div;
|
||||
this._timerID = null;
|
||||
this.update();
|
||||
}
|
||||
|
||||
ProcessWidget.prototype.update = function() {
|
||||
if (this._timerID != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
Ajax.chainGetJSON(
|
||||
"/command/get-processes?" + $.param({ project: theProject.id }), null,
|
||||
function(data) {
|
||||
self._data = data;
|
||||
self._render();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
ProcessWidget.prototype._render = function() {
|
||||
var self = this;
|
||||
|
||||
this._div.empty();
|
||||
|
||||
var bodyDiv = $('<div></div>').addClass("process-panel-inner").text("Testing").appendTo(this._div);
|
||||
if (this._data.processes.length == 0) {
|
||||
this._div.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
this._div.show();
|
||||
|
||||
var hasPending = false;
|
||||
var renderProcess = function(process) {
|
||||
var div = $('<div></div>').addClass("process-panel-entry").appendTo(bodyDiv);
|
||||
|
||||
if (process.status == "pending") {
|
||||
div.text(process.description + " (pending)");
|
||||
} else {
|
||||
div.text(process.description + " (" + process.progress + "%)");
|
||||
hasPending = true;
|
||||
}
|
||||
};
|
||||
|
||||
var processes = this._data.processes;
|
||||
for (var i = 0; i < processes.length; i++) {
|
||||
renderProcess(processes[i]);
|
||||
}
|
||||
|
||||
if (hasPending && this._timerID == null) {
|
||||
this._timerID = window.setTimeout(function() {
|
||||
self._timerID = null;
|
||||
self.update();
|
||||
}, 500);
|
||||
}
|
||||
};
|
15
src/main/webapp/styles/process.css
Normal file
15
src/main/webapp/styles/process.css
Normal file
@ -0,0 +1,15 @@
|
||||
.process-panel {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.process-panel-inner {
|
||||
border: 1px solid #ccc;
|
||||
width: 500px;
|
||||
padding: 10px;
|
||||
background: #fffee0;
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
}
|
Loading…
Reference in New Issue
Block a user