Skip to content

Commit 0f047a2

Browse files
authored
Merge pull request #203 from jumpserver/pr@new_terminal@feat_dataview_editable
feat:support dataview edit
2 parents 5f33ccb + 831be00 commit 0f047a2

109 files changed

Lines changed: 7330 additions & 363 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/framework/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,4 @@
6060
</dependencies>
6161

6262

63-
</project>
63+
</project>

backend/framework/src/main/java/org/jumpserver/chen/framework/console/AbstractConsole.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.jumpserver.chen.framework.datasource.Datasource;
66
import org.jumpserver.chen.framework.console.component.Logger;
77
import org.jumpserver.chen.framework.console.component.Messager;
8+
import org.jumpserver.chen.framework.console.context.ConsoleContext;
89
import org.jumpserver.chen.framework.ws.io.PacketIO;
910
import org.jumpserver.chen.framework.console.entity.request.Connect;
1011
import org.springframework.web.socket.WebSocketSession;
@@ -20,7 +21,7 @@ public abstract class AbstractConsole implements Console {
2021
private final PacketIO packetIO;
2122
private final Messager messager;
2223
private String title;
23-
private String nodeKey;
24+
private final ConsoleContext context;
2425

2526
public String getTitle() {
2627
return this.title;
@@ -30,8 +31,12 @@ public void onInit(Connect connect) {
3031
this.packetIO.sendPacket("init", Map.of("title", this.title));
3132
}
3233

33-
protected AbstractConsole(Datasource datasource, WebSocketSession ws, String nodeKey) {
34-
this.nodeKey = nodeKey;
34+
public String getNodeKey() {
35+
return this.context.nodeKey();
36+
}
37+
38+
protected AbstractConsole(Datasource datasource, WebSocketSession ws, ConsoleContext context) {
39+
this.context = context;
3540
this.datasource = datasource;
3641
this.packetIO = new PacketIO(ws);
3742
this.consoleLogger = new Logger(this.packetIO);

backend/framework/src/main/java/org/jumpserver/chen/framework/console/Console.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
import org.jumpserver.chen.framework.ws.io.Packet;
55
import org.jumpserver.chen.framework.console.entity.request.Connect;
6+
import org.jumpserver.chen.framework.console.context.ConsoleContext;
67

78
public interface Console {
89
String getTitle();
910
String getNodeKey();
11+
ConsoleContext getContext();
1012
void onInit(Connect connect);
1113

1214
void handle(Packet packet);

backend/framework/src/main/java/org/jumpserver/chen/framework/console/DataViewConsole.java

Lines changed: 126 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,77 @@
11
package org.jumpserver.chen.framework.console;
22

33
import com.google.gson.Gson;
4-
import org.apache.commons.lang3.StringUtils;
4+
import lombok.Getter;
55
import org.jumpserver.chen.framework.console.action.DataViewAction;
6+
import org.jumpserver.chen.framework.console.context.ConsoleContext;
67
import org.jumpserver.chen.framework.console.dataview.DataView;
78
import org.jumpserver.chen.framework.console.dataview.UpdateDataView;
89
import org.jumpserver.chen.framework.console.entity.request.Connect;
10+
import org.jumpserver.chen.framework.console.entity.request.SaveChangesRequest;
911
import org.jumpserver.chen.framework.console.entity.response.Message;
1012
import org.jumpserver.chen.framework.console.state.State;
1113
import org.jumpserver.chen.framework.console.state.StateManager;
1214
import org.jumpserver.chen.framework.datasource.Datasource;
15+
import org.jumpserver.chen.framework.datasource.edit.TableBrowseSaveExecutionContext;
16+
import org.jumpserver.chen.framework.datasource.edit.TableChangesPreviewService;
17+
import org.jumpserver.chen.framework.datasource.edit.TableChangesSaveService;
18+
import org.jumpserver.chen.framework.datasource.edit.TableEditContext;
1319
import org.jumpserver.chen.framework.i18n.MessageUtils;
1420
import org.jumpserver.chen.framework.jms.entity.CommandRecord;
1521
import org.jumpserver.chen.framework.session.SessionManager;
22+
import org.jumpserver.chen.framework.session.controller.DialogHandle;
1623
import org.jumpserver.chen.framework.session.controller.dialog.Button;
1724
import org.jumpserver.chen.framework.session.controller.dialog.Dialog;
18-
import org.jumpserver.chen.framework.utils.TreeUtils;
1925
import org.jumpserver.chen.framework.ws.io.Packet;
2026
import org.jumpserver.wisp.Common;
2127
import org.springframework.web.socket.WebSocketSession;
2228

2329
import java.sql.SQLException;
2430
import java.util.Map;
2531
import java.util.concurrent.CountDownLatch;
32+
import java.util.concurrent.TimeUnit;
2633
import java.util.concurrent.atomic.AtomicBoolean;
34+
import java.util.concurrent.locks.ReentrantLock;
2735

2836
public class DataViewConsole extends AbstractConsole {
37+
private static final String PACKET_SAVE_CHANGES_PREVIEW_RESULT = "save_changes_preview_result";
38+
private static final String PACKET_SAVE_CHANGES_RESULT = "save_changes_result";
39+
private static final long WARNING_DIALOG_TIMEOUT_SECONDS = 300;
40+
private final TableChangesPreviewService tableChangesPreviewService = new TableChangesPreviewService();
41+
private final TableChangesSaveService tableChangesSaveService = new TableChangesSaveService();
2942

3043
private DataView tableDataView;
3144
private StateManager<State> stateManager;
45+
private final AtomicBoolean closed = new AtomicBoolean(false);
46+
private final ReentrantLock executionLock = new ReentrantLock();
3247

33-
private String schema;
34-
private String table;
48+
@Getter
49+
private final String schema;
50+
@Getter
51+
private final String table;
3552

3653
private static final Gson GSON = new Gson();
3754

38-
public DataViewConsole(Datasource datasource, WebSocketSession ws, String nodeKey) {
39-
super(datasource, ws, nodeKey);
55+
public DataViewConsole(Datasource datasource, WebSocketSession ws, ConsoleContext context) {
56+
super(datasource, ws, context);
57+
this.schema = context.schema();
58+
this.table = context.table();
4059
}
4160

4261

4362
@Override
4463
public void onInit(Connect connect) {
45-
this.schema = TreeUtils.getValue(connect.getNodeKey(), "schema");
46-
this.table = StringUtils.isEmpty(TreeUtils.getValue(connect.getNodeKey(), "table")) ?
47-
TreeUtils.getValue(connect.getNodeKey(), "view") : TreeUtils.getValue(connect.getNodeKey(), "table");
64+
if (!this.beginExecution()) {
65+
return;
66+
}
67+
try {
68+
this.initialize(connect);
69+
} finally {
70+
this.executionLock.unlock();
71+
}
72+
}
4873

74+
private void initialize(Connect connect) {
4975
var title = "";
5076
try {
5177
title = this.generateConsoleName();
@@ -72,13 +98,32 @@ private String generateConsoleName() {
7298

7399
@Override
74100
public void handle(Packet packet) {
75-
switch (packet.getType()) {
76-
case "ping" -> this.getPacketIO().sendPacket("pong", null);
77-
case Packet.TYPE_DATA_VIEW_ACTION -> {
78-
var action = GSON.fromJson(GSON.toJson(packet.getData()), DataViewAction.class);
79-
this.onDataViewAction(action);
101+
if (!this.beginExecution()) {
102+
return;
103+
}
104+
try {
105+
switch (packet.getType()) {
106+
case "ping" -> this.getPacketIO().sendPacket("pong", null);
107+
case Packet.TYPE_DATA_VIEW_ACTION -> {
108+
var action = GSON.fromJson(GSON.toJson(packet.getData()), DataViewAction.class);
109+
this.onDataViewAction(action);
110+
}
80111
}
112+
} finally {
113+
this.executionLock.unlock();
114+
}
115+
}
116+
117+
private boolean beginExecution() {
118+
if (this.closed.get()) {
119+
return false;
81120
}
121+
this.executionLock.lock();
122+
if (this.closed.get()) {
123+
this.executionLock.unlock();
124+
return false;
125+
}
126+
return true;
82127
}
83128

84129
public void onConnect(Connect connect) {
@@ -145,21 +190,31 @@ public void createDataView(String schemaName, String tableName) {
145190
this.getConsoleLogger().warn(MessageUtils.get("ExecutionCanceled"));
146191
}));
147192

148-
SessionManager.getCurrentSession().getController().showDialog(dialog);
193+
var controller = SessionManager.getCurrentSession().getController();
194+
DialogHandle dialogHandle = controller.showDialog(dialog, () -> {
195+
hasNext.set(false);
196+
countDownLatch.countDown();
197+
});
149198

150199
try {
151-
countDownLatch.await();
200+
if (!countDownLatch.await(WARNING_DIALOG_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
201+
hasNext.set(false);
202+
dialogHandle.cancel();
203+
}
152204

153205
if (!hasNext.get()) {
154206
throw new SQLException(MessageUtils.get("ExecutionCanceled"));
155207
}
156208

157209
} catch (InterruptedException e) {
210+
Thread.currentThread().interrupt();
211+
hasNext.set(false);
158212
this.stateManager.commit();
159213

160214
this.getConsoleLogger().error("get result error");
215+
throw new SQLException(MessageUtils.get("ExecutionCanceled"), e);
161216
} finally {
162-
SessionManager.getCurrentSession().getController().closeDialog();
217+
dialogHandle.close();
163218
}
164219
}
165220

@@ -181,6 +236,41 @@ public void createDataView(String schemaName, String tableName) {
181236

182237

183238
public void onDataViewAction(DataViewAction action) {
239+
if (DataViewAction.ACTION_SAVE_CHANGES_PREVIEW.equals(action.getAction())) {
240+
var request = GSON.fromJson(GSON.toJson(action.getData()), SaveChangesRequest.class);
241+
var context = new TableEditContext(
242+
this.tableDataView.getTitle(),
243+
this.schema,
244+
this.table,
245+
this.tableDataView.getData().getFields(),
246+
this.getDatasource().getDruidDbType(),
247+
true
248+
);
249+
var result = this.tableChangesPreviewService.preview(context, action.getDataView(), request);
250+
this.getPacketIO().sendPacket(PACKET_SAVE_CHANGES_PREVIEW_RESULT, result);
251+
return;
252+
}
253+
if (DataViewAction.ACTION_SAVE_CHANGES.equals(action.getAction())) {
254+
var request = GSON.fromJson(GSON.toJson(action.getData()), SaveChangesRequest.class);
255+
var context = new TableEditContext(
256+
this.tableDataView.getTitle(),
257+
this.schema,
258+
this.table,
259+
this.tableDataView.getData().getFields(),
260+
this.getDatasource().getDruidDbType(),
261+
true
262+
);
263+
var result = this.tableChangesSaveService.save(
264+
context,
265+
action.getDataView(),
266+
request,
267+
new TableBrowseSaveExecutionContext(this.getDatasource().getConnectionManager()),
268+
SessionManager.getCurrentSession()
269+
);
270+
this.getPacketIO().sendPacket(PACKET_SAVE_CHANGES_RESULT, result);
271+
return;
272+
}
273+
184274
try {
185275
this.tableDataView.getStateManager().getState().setLoading(true);
186276
this.tableDataView.getStateManager().commit();
@@ -199,5 +289,24 @@ public void onDataViewAction(DataViewAction action) {
199289

200290
@Override
201291
public void close() {
292+
if (!this.closed.compareAndSet(false, true)) {
293+
return;
294+
}
295+
var currentSession = SessionManager.getCurrentSession();
296+
if (currentSession == null && this.getPacketIO().getWsSession().getAttributes() != null) {
297+
Object token = this.getPacketIO().getWsSession().getAttributes().get("token");
298+
if (token instanceof String sessionToken) {
299+
currentSession = SessionManager.getSession(sessionToken);
300+
}
301+
}
302+
if (currentSession != null && currentSession.getController() != null) {
303+
currentSession.getController().cancelDialogs(this.getPacketIO().getWsSession().getId());
304+
}
305+
this.executionLock.lock();
306+
try {
307+
// Wait for admitted work to observe cancellation and leave the execution section.
308+
} finally {
309+
this.executionLock.unlock();
310+
}
202311
}
203312
}

0 commit comments

Comments
 (0)