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.DoTextTransformCommand;
|
||||||
import com.metaweb.gridlock.commands.GetColumnModelCommand;
|
import com.metaweb.gridlock.commands.GetColumnModelCommand;
|
||||||
import com.metaweb.gridlock.commands.GetHistoryCommand;
|
import com.metaweb.gridlock.commands.GetHistoryCommand;
|
||||||
|
import com.metaweb.gridlock.commands.GetProcessesCommand;
|
||||||
import com.metaweb.gridlock.commands.GetProjectMetadataCommand;
|
import com.metaweb.gridlock.commands.GetProjectMetadataCommand;
|
||||||
import com.metaweb.gridlock.commands.GetRowsCommand;
|
import com.metaweb.gridlock.commands.GetRowsCommand;
|
||||||
import com.metaweb.gridlock.commands.UndoRedoCommand;
|
import com.metaweb.gridlock.commands.UndoRedoCommand;
|
||||||
@ -31,12 +32,15 @@ public class GridlockServlet extends HttpServlet {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
_commands.put("create-project-from-upload", new CreateProjectFromUploadCommand());
|
_commands.put("create-project-from-upload", new CreateProjectFromUploadCommand());
|
||||||
|
|
||||||
_commands.put("get-project-metadata", new GetProjectMetadataCommand());
|
_commands.put("get-project-metadata", new GetProjectMetadataCommand());
|
||||||
_commands.put("get-column-model", new GetColumnModelCommand());
|
_commands.put("get-column-model", new GetColumnModelCommand());
|
||||||
_commands.put("get-rows", new GetRowsCommand());
|
_commands.put("get-rows", new GetRowsCommand());
|
||||||
|
_commands.put("get-processes", new GetProcessesCommand());
|
||||||
_commands.put("get-history", new GetHistoryCommand());
|
_commands.put("get-history", new GetHistoryCommand());
|
||||||
_commands.put("compute-facets", new ComputeFacetsCommand());
|
|
||||||
_commands.put("undo-redo", new UndoRedoCommand());
|
_commands.put("undo-redo", new UndoRedoCommand());
|
||||||
|
_commands.put("compute-facets", new ComputeFacetsCommand());
|
||||||
_commands.put("do-text-transform", new DoTextTransformCommand());
|
_commands.put("do-text-transform", new DoTextTransformCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,14 +30,13 @@ public class DoTextTransformCommand extends Command {
|
|||||||
Project project = getProject(request);
|
Project project = getProject(request);
|
||||||
int cellIndex = Integer.parseInt(request.getParameter("cell"));
|
int cellIndex = Integer.parseInt(request.getParameter("cell"));
|
||||||
|
|
||||||
String columnName = null;
|
Column column = project.columnModel.getColumnByCellIndex(cellIndex);
|
||||||
for (Column column : project.columnModel.columns) {
|
if (column == null) {
|
||||||
if (column.cellIndex == cellIndex) {
|
respond(response, "{ \"code\" : \"error\", \"message\" : \"No such column\" }");
|
||||||
columnName = column.headerLabel;
|
return;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String columnName = column.headerLabel;
|
||||||
String expression = request.getParameter("expression");
|
String expression = request.getParameter("expression");
|
||||||
|
|
||||||
try {
|
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.model.Project;
|
||||||
import com.metaweb.gridlock.process.Process;
|
import com.metaweb.gridlock.process.Process;
|
||||||
|
import com.metaweb.gridlock.process.ProcessManager;
|
||||||
|
|
||||||
public class HistoryProcess extends Process {
|
public class HistoryProcess extends Process {
|
||||||
final protected Project _project;
|
final protected Project _project;
|
||||||
@ -27,6 +28,6 @@ public class HistoryProcess extends Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startPerforming() {
|
public void startPerforming(ProcessManager manager) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,4 +37,13 @@ public class ColumnModel implements Serializable {
|
|||||||
}
|
}
|
||||||
return _nameToColumn.get(name);
|
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;
|
package com.metaweb.gridlock.process;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public abstract class Process {
|
public abstract class Process {
|
||||||
abstract public boolean isImmediate();
|
abstract public boolean isImmediate();
|
||||||
|
|
||||||
|
abstract public boolean isRunning();
|
||||||
|
abstract public boolean isDone();
|
||||||
|
|
||||||
abstract public void performImmediate();
|
abstract public void performImmediate();
|
||||||
|
|
||||||
abstract public void startPerforming();
|
abstract public void startPerforming(ProcessManager manager);
|
||||||
abstract public void cancel();
|
abstract public void cancel();
|
||||||
|
|
||||||
|
abstract JSONObject getJSON(Properties options) throws JSONException;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
package com.metaweb.gridlock.process;
|
package com.metaweb.gridlock.process;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class ProcessManager {
|
public class ProcessManager {
|
||||||
protected List<Process> _processes = new LinkedList<Process>();
|
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) {
|
public boolean queueProcess(Process process) {
|
||||||
if (process.isImmediate() && _processes.size() == 0) {
|
if (process.isImmediate() && _processes.size() == 0) {
|
||||||
process.performImmediate();
|
process.performImmediate();
|
||||||
@ -19,4 +36,25 @@ public class ProcessManager {
|
|||||||
return false;
|
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;
|
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.history.HistoryEntry;
|
||||||
import com.metaweb.gridlock.model.Project;
|
import com.metaweb.gridlock.model.Project;
|
||||||
|
|
||||||
public class QuickHistoryEntryProcess extends Process {
|
public class QuickHistoryEntryProcess extends Process {
|
||||||
final protected Project _project;
|
final protected Project _project;
|
||||||
final protected HistoryEntry _historyEntry;
|
final protected HistoryEntry _historyEntry;
|
||||||
|
boolean _done = false;
|
||||||
|
|
||||||
public QuickHistoryEntryProcess(Project project, HistoryEntry historyEntry) {
|
public QuickHistoryEntryProcess(Project project, HistoryEntry historyEntry) {
|
||||||
_project = project;
|
_project = project;
|
||||||
@ -14,19 +20,43 @@ public class QuickHistoryEntryProcess extends Process {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
|
throw new RuntimeException("Not a long-running process");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isImmediate() {
|
public boolean isImmediate() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
throw new RuntimeException("Not a long-running process");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performImmediate() {
|
public void performImmediate() {
|
||||||
_project.history.addEntry(_historyEntry);
|
_project.history.addEntry(_historyEntry);
|
||||||
|
_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startPerforming() {
|
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.viewPanel = $('<div></div>').appendTo(tdLeft).css("width", tdLeft.offsetWidth + "px").css("overflow-x", "auto");
|
||||||
ui.facetPanel = $('<div></div>').appendTo(tdRight);
|
ui.facetPanel = $('<div></div>').appendTo(tdRight);
|
||||||
ui.historyPanel = $('<div></div>').addClass("history-panel").appendTo(document.body);
|
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.browsingEngine = new BrowsingEngine(ui.facetPanel);
|
||||||
|
ui.processWidget = new ProcessWidget(ui.processPanel);
|
||||||
ui.historyWidget = new HistoryWidget(ui.historyPanel);
|
ui.historyWidget = new HistoryWidget(ui.historyPanel);
|
||||||
ui.dataTableView = new DataTableView(ui.viewPanel);
|
ui.dataTableView = new DataTableView(ui.viewPanel);
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,7 @@ DataTableView.prototype._doTextTransform = function(column, expression) {
|
|||||||
self.update();
|
self.update();
|
||||||
ui.historyWidget.update();
|
ui.historyWidget.update();
|
||||||
} else {
|
} else {
|
||||||
// update process UI
|
ui.processWidget.update();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"json"
|
"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