@lvce-editor/chat-view 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chatViewWorkerMain.js +729 -253
- package/package.json +2 -1
|
@@ -972,9 +972,10 @@ const Span = 8;
|
|
|
972
972
|
const Text = 12;
|
|
973
973
|
const P = 50;
|
|
974
974
|
const TextArea = 62;
|
|
975
|
-
const Strong = 70;
|
|
976
975
|
const Reference = 100;
|
|
977
976
|
|
|
977
|
+
const ClientX = 'event.clientX';
|
|
978
|
+
const ClientY = 'event.clientY';
|
|
978
979
|
const Key = 'event.key';
|
|
979
980
|
const ShiftKey = 'event.shiftKey';
|
|
980
981
|
const TargetName = 'event.target.name';
|
|
@@ -983,8 +984,10 @@ const TargetValue = 'event.target.value';
|
|
|
983
984
|
const ExtensionHostWorker = 44;
|
|
984
985
|
const RendererWorker = 1;
|
|
985
986
|
|
|
987
|
+
const FocusSelector = 'Viewlet.focusSelector';
|
|
986
988
|
const SetCss = 'Viewlet.setCss';
|
|
987
989
|
const SetDom2 = 'Viewlet.setDom2';
|
|
990
|
+
const SetValueByName = 'Viewlet.setValueByName';
|
|
988
991
|
const SetPatches = 'Viewlet.setPatches';
|
|
989
992
|
|
|
990
993
|
const createMockRpc = ({
|
|
@@ -1189,27 +1192,72 @@ const terminate = () => {
|
|
|
1189
1192
|
globalThis.close();
|
|
1190
1193
|
};
|
|
1191
1194
|
|
|
1195
|
+
const clearInput = async state => {
|
|
1196
|
+
return {
|
|
1197
|
+
...state,
|
|
1198
|
+
composerValue: ''
|
|
1199
|
+
};
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
const emptyObject = {};
|
|
1203
|
+
const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
|
|
1204
|
+
const i18nString = (key, placeholders = emptyObject) => {
|
|
1205
|
+
if (placeholders === emptyObject) {
|
|
1206
|
+
return key;
|
|
1207
|
+
}
|
|
1208
|
+
const replacer = (match, rest) => {
|
|
1209
|
+
return placeholders[rest];
|
|
1210
|
+
};
|
|
1211
|
+
return key.replaceAll(RE_PLACEHOLDER, replacer);
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
const chatTitle = i18nString('Chat');
|
|
1215
|
+
const chats = i18nString('Chats');
|
|
1216
|
+
const newChat = i18nString('New Chat');
|
|
1217
|
+
const backToChats = i18nString('Back to chats');
|
|
1218
|
+
const settings = i18nString('Settings');
|
|
1219
|
+
const closeChat = i18nString('Close Chat');
|
|
1220
|
+
const clickToOpenNewChat = i18nString('Click the + button to open a new chat.');
|
|
1221
|
+
const startConversation = i18nString('Start a conversation by typing below.');
|
|
1222
|
+
const you = i18nString('You');
|
|
1223
|
+
const assistant = i18nString('Assistant');
|
|
1224
|
+
const composePlaceholder = i18nString('Type your message. Enter to send, Shift+Enter for newline.');
|
|
1225
|
+
const sendMessage = i18nString('Send message');
|
|
1226
|
+
const send = i18nString('Send');
|
|
1227
|
+
const deleteChatSession = i18nString('Delete chat session');
|
|
1228
|
+
const defaultSessionTitle = i18nString('Chat 1');
|
|
1229
|
+
const dummyChatA = i18nString('Dummy Chat A');
|
|
1230
|
+
const dummyChatB = i18nString('Dummy Chat B');
|
|
1231
|
+
const dummyChatC = i18nString('Dummy Chat C');
|
|
1232
|
+
|
|
1192
1233
|
const createDefaultState = () => {
|
|
1193
1234
|
const defaultSessionId = 'session-1';
|
|
1194
1235
|
return {
|
|
1195
1236
|
assetDir: '',
|
|
1196
1237
|
composerValue: '',
|
|
1197
1238
|
errorCount: 0,
|
|
1198
|
-
|
|
1239
|
+
focus: 'composer',
|
|
1240
|
+
focused: false,
|
|
1241
|
+
height: 0,
|
|
1199
1242
|
initial: true,
|
|
1243
|
+
inputSource: 'script',
|
|
1200
1244
|
lastSubmittedSessionId: '',
|
|
1245
|
+
listItemHeight: 40,
|
|
1201
1246
|
nextMessageId: 1,
|
|
1202
|
-
nextSessionId: 2,
|
|
1203
1247
|
platform: 0,
|
|
1204
1248
|
renamingSessionId: '',
|
|
1205
1249
|
selectedSessionId: defaultSessionId,
|
|
1206
1250
|
sessions: [{
|
|
1207
1251
|
id: defaultSessionId,
|
|
1208
1252
|
messages: [],
|
|
1209
|
-
title:
|
|
1253
|
+
title: defaultSessionTitle
|
|
1210
1254
|
}],
|
|
1211
1255
|
uid: 0,
|
|
1212
|
-
|
|
1256
|
+
viewMode: 'list',
|
|
1257
|
+
warningCount: 0,
|
|
1258
|
+
width: 0,
|
|
1259
|
+
x: 0,
|
|
1260
|
+
y: 0
|
|
1213
1261
|
};
|
|
1214
1262
|
};
|
|
1215
1263
|
|
|
@@ -1222,12 +1270,16 @@ const {
|
|
|
1222
1270
|
wrapGetter
|
|
1223
1271
|
} = create$1();
|
|
1224
1272
|
|
|
1225
|
-
const create = (uid,
|
|
1273
|
+
const create = (uid, _uri, x, y, width, height, platform, assetDir) => {
|
|
1226
1274
|
const state = {
|
|
1227
1275
|
...createDefaultState(),
|
|
1228
1276
|
assetDir,
|
|
1277
|
+
height,
|
|
1229
1278
|
platform,
|
|
1230
|
-
uid
|
|
1279
|
+
uid,
|
|
1280
|
+
width,
|
|
1281
|
+
x,
|
|
1282
|
+
y
|
|
1231
1283
|
};
|
|
1232
1284
|
set(uid, state, state);
|
|
1233
1285
|
};
|
|
@@ -1236,16 +1288,32 @@ const isEqual$1 = (oldState, newState) => {
|
|
|
1236
1288
|
return oldState.initial === newState.initial;
|
|
1237
1289
|
};
|
|
1238
1290
|
|
|
1291
|
+
const diffFocus = (oldState, newState) => {
|
|
1292
|
+
if (!newState.focused) {
|
|
1293
|
+
return true;
|
|
1294
|
+
}
|
|
1295
|
+
return oldState.focus === newState.focus && oldState.focused === newState.focused;
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1239
1298
|
const isEqual = (oldState, newState) => {
|
|
1240
|
-
return oldState.composerValue === newState.composerValue && oldState.
|
|
1299
|
+
return oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.viewMode === newState.viewMode;
|
|
1241
1300
|
};
|
|
1242
1301
|
|
|
1243
1302
|
const RenderItems = 4;
|
|
1303
|
+
const RenderFocus = 6;
|
|
1304
|
+
const RenderValue = 8;
|
|
1244
1305
|
const RenderCss = 10;
|
|
1245
1306
|
const RenderIncremental = 11;
|
|
1246
1307
|
|
|
1247
|
-
const
|
|
1248
|
-
|
|
1308
|
+
const diffValue = (oldState, newState) => {
|
|
1309
|
+
if (oldState.composerValue === newState.composerValue) {
|
|
1310
|
+
return true;
|
|
1311
|
+
}
|
|
1312
|
+
return newState.inputSource !== 'script';
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
const modules = [isEqual, diffValue, diffFocus, isEqual$1];
|
|
1316
|
+
const numbers = [RenderIncremental, RenderValue, RenderFocus, RenderCss];
|
|
1249
1317
|
|
|
1250
1318
|
const diff = (oldState, newState) => {
|
|
1251
1319
|
const diffResult = [];
|
|
@@ -1271,117 +1339,186 @@ const getKeyBindings = () => {
|
|
|
1271
1339
|
return [];
|
|
1272
1340
|
};
|
|
1273
1341
|
|
|
1274
|
-
const
|
|
1342
|
+
const SESSION_PREFIX$1 = 'session:';
|
|
1343
|
+
const CHAT_LIST_ITEM_CONTEXT_MENU = 'ChatListItemContextMenu';
|
|
1344
|
+
const handleChatListContextMenu = async (name, x, y) => {
|
|
1345
|
+
if (!name || !name.startsWith(SESSION_PREFIX$1)) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const sessionId = name.slice(SESSION_PREFIX$1.length);
|
|
1349
|
+
// @ts-ignore
|
|
1350
|
+
await invoke('ContextMenu.show', x, y, CHAT_LIST_ITEM_CONTEXT_MENU, sessionId);
|
|
1351
|
+
};
|
|
1352
|
+
|
|
1353
|
+
const generateSessionId = () => {
|
|
1354
|
+
return crypto.randomUUID();
|
|
1355
|
+
};
|
|
1356
|
+
|
|
1357
|
+
const createSession = state => {
|
|
1358
|
+
const id = generateSessionId();
|
|
1359
|
+
const session = {
|
|
1360
|
+
id,
|
|
1361
|
+
messages: [],
|
|
1362
|
+
title: `Chat ${state.sessions.length + 1}`
|
|
1363
|
+
};
|
|
1364
|
+
return {
|
|
1365
|
+
...state,
|
|
1366
|
+
renamingSessionId: '',
|
|
1367
|
+
selectedSessionId: id,
|
|
1368
|
+
sessions: [...state.sessions, session]
|
|
1369
|
+
};
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
const getNextSelectedSessionId = (sessions, deletedId) => {
|
|
1373
|
+
if (sessions.length === 0) {
|
|
1374
|
+
return '';
|
|
1375
|
+
}
|
|
1376
|
+
const index = sessions.findIndex(session => session.id === deletedId);
|
|
1377
|
+
if (index === -1) {
|
|
1378
|
+
return sessions[0].id;
|
|
1379
|
+
}
|
|
1380
|
+
const nextIndex = Math.min(index, sessions.length - 1);
|
|
1381
|
+
return sessions[nextIndex].id;
|
|
1382
|
+
};
|
|
1383
|
+
|
|
1384
|
+
const deleteSession = (state, id) => {
|
|
1275
1385
|
const {
|
|
1276
|
-
composerValue,
|
|
1277
1386
|
renamingSessionId,
|
|
1278
1387
|
sessions
|
|
1279
1388
|
} = state;
|
|
1280
|
-
const
|
|
1281
|
-
if (
|
|
1389
|
+
const filtered = sessions.filter(session => session.id !== id);
|
|
1390
|
+
if (filtered.length === sessions.length) {
|
|
1391
|
+
return state;
|
|
1392
|
+
}
|
|
1393
|
+
if (filtered.length === 0) {
|
|
1282
1394
|
return {
|
|
1283
1395
|
...state,
|
|
1284
|
-
renamingSessionId: ''
|
|
1396
|
+
renamingSessionId: '',
|
|
1397
|
+
selectedSessionId: '',
|
|
1398
|
+
sessions: [],
|
|
1399
|
+
viewMode: 'list'
|
|
1285
1400
|
};
|
|
1286
1401
|
}
|
|
1287
|
-
const updatedSessions = sessions.map(session => {
|
|
1288
|
-
if (session.id !== renamingSessionId) {
|
|
1289
|
-
return session;
|
|
1290
|
-
}
|
|
1291
|
-
return {
|
|
1292
|
-
...session,
|
|
1293
|
-
title
|
|
1294
|
-
};
|
|
1295
|
-
});
|
|
1296
1402
|
return {
|
|
1297
1403
|
...state,
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
sessions: updatedSessions
|
|
1404
|
+
renamingSessionId: renamingSessionId === id ? '' : renamingSessionId,
|
|
1405
|
+
selectedSessionId: getNextSelectedSessionId(filtered, id),
|
|
1406
|
+
sessions: filtered
|
|
1302
1407
|
};
|
|
1303
1408
|
};
|
|
1304
|
-
|
|
1409
|
+
|
|
1410
|
+
const focusInput = state => {
|
|
1411
|
+
return {
|
|
1412
|
+
...state,
|
|
1413
|
+
focus: 'composer',
|
|
1414
|
+
focused: true
|
|
1415
|
+
};
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
const delay = async ms => {
|
|
1419
|
+
await new Promise(resolve => setTimeout(resolve, ms));
|
|
1420
|
+
};
|
|
1421
|
+
const getMockAiResponse = userMessage => {
|
|
1422
|
+
return `Mock AI response: I received "${userMessage}".`;
|
|
1423
|
+
};
|
|
1424
|
+
const handleSubmit = async state => {
|
|
1305
1425
|
const {
|
|
1306
1426
|
composerValue,
|
|
1307
1427
|
nextMessageId,
|
|
1308
1428
|
selectedSessionId,
|
|
1309
|
-
sessions
|
|
1429
|
+
sessions,
|
|
1430
|
+
viewMode
|
|
1310
1431
|
} = state;
|
|
1311
|
-
const
|
|
1312
|
-
if (!
|
|
1313
|
-
return
|
|
1314
|
-
|
|
1315
|
-
|
|
1432
|
+
const userText = composerValue.trim();
|
|
1433
|
+
if (!userText) {
|
|
1434
|
+
return state;
|
|
1435
|
+
}
|
|
1436
|
+
const userTime = new Date().toLocaleTimeString([], {
|
|
1437
|
+
hour: '2-digit',
|
|
1438
|
+
minute: '2-digit'
|
|
1439
|
+
});
|
|
1440
|
+
const userMessage = {
|
|
1441
|
+
id: `message-${nextMessageId}`,
|
|
1442
|
+
role: 'user',
|
|
1443
|
+
text: userText,
|
|
1444
|
+
time: userTime
|
|
1445
|
+
};
|
|
1446
|
+
let optimisticState;
|
|
1447
|
+
if (viewMode === 'list') {
|
|
1448
|
+
const newSessionId = generateSessionId();
|
|
1449
|
+
const newSession = {
|
|
1450
|
+
id: newSessionId,
|
|
1451
|
+
messages: [userMessage],
|
|
1452
|
+
title: `Chat ${sessions.length + 1}`
|
|
1316
1453
|
};
|
|
1454
|
+
optimisticState = focusInput({
|
|
1455
|
+
...state,
|
|
1456
|
+
composerValue: '',
|
|
1457
|
+
inputSource: 'script',
|
|
1458
|
+
lastSubmittedSessionId: newSessionId,
|
|
1459
|
+
nextMessageId: nextMessageId + 1,
|
|
1460
|
+
selectedSessionId: newSessionId,
|
|
1461
|
+
sessions: [...sessions, newSession],
|
|
1462
|
+
viewMode: 'detail'
|
|
1463
|
+
});
|
|
1464
|
+
} else {
|
|
1465
|
+
const updatedSessions = sessions.map(session => {
|
|
1466
|
+
if (session.id !== selectedSessionId) {
|
|
1467
|
+
return session;
|
|
1468
|
+
}
|
|
1469
|
+
return {
|
|
1470
|
+
...session,
|
|
1471
|
+
messages: [...session.messages, userMessage]
|
|
1472
|
+
};
|
|
1473
|
+
});
|
|
1474
|
+
optimisticState = focusInput({
|
|
1475
|
+
...state,
|
|
1476
|
+
composerValue: '',
|
|
1477
|
+
inputSource: 'script',
|
|
1478
|
+
lastSubmittedSessionId: selectedSessionId,
|
|
1479
|
+
nextMessageId: nextMessageId + 1,
|
|
1480
|
+
sessions: updatedSessions
|
|
1481
|
+
});
|
|
1317
1482
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1483
|
+
set(state.uid, state, optimisticState);
|
|
1484
|
+
// @ts-ignore
|
|
1485
|
+
await invoke('Chat.rerender');
|
|
1486
|
+
await delay(800);
|
|
1487
|
+
const assistantTime = new Date().toLocaleTimeString([], {
|
|
1488
|
+
hour: '2-digit',
|
|
1489
|
+
minute: '2-digit'
|
|
1490
|
+
});
|
|
1491
|
+
const assistantMessage = {
|
|
1492
|
+
id: `message-${optimisticState.nextMessageId}`,
|
|
1493
|
+
role: 'assistant',
|
|
1494
|
+
text: getMockAiResponse(userText),
|
|
1495
|
+
time: assistantTime
|
|
1496
|
+
};
|
|
1497
|
+
const updatedSessions = optimisticState.sessions.map(session => {
|
|
1498
|
+
if (session.id !== optimisticState.selectedSessionId) {
|
|
1320
1499
|
return session;
|
|
1321
1500
|
}
|
|
1322
|
-
const message = {
|
|
1323
|
-
id: `message-${nextMessageId}`,
|
|
1324
|
-
role: 'user',
|
|
1325
|
-
text
|
|
1326
|
-
};
|
|
1327
1501
|
return {
|
|
1328
1502
|
...session,
|
|
1329
|
-
messages: [...session.messages,
|
|
1503
|
+
messages: [...session.messages, assistantMessage]
|
|
1330
1504
|
};
|
|
1331
1505
|
});
|
|
1332
|
-
return {
|
|
1333
|
-
...
|
|
1334
|
-
|
|
1335
|
-
ignoreNextInput: true,
|
|
1336
|
-
lastSubmittedSessionId: selectedSessionId,
|
|
1337
|
-
nextMessageId: nextMessageId + 1,
|
|
1506
|
+
return focusInput({
|
|
1507
|
+
...optimisticState,
|
|
1508
|
+
nextMessageId: optimisticState.nextMessageId + 1,
|
|
1338
1509
|
sessions: updatedSessions
|
|
1339
|
-
};
|
|
1340
|
-
};
|
|
1341
|
-
const handleKeyDown = async (state, key, shiftKey) => {
|
|
1342
|
-
if (key !== 'Enter' || shiftKey) {
|
|
1343
|
-
return state;
|
|
1344
|
-
}
|
|
1345
|
-
if (state.renamingSessionId) {
|
|
1346
|
-
return submitRename(state);
|
|
1347
|
-
}
|
|
1348
|
-
return submitMessage(state);
|
|
1510
|
+
});
|
|
1349
1511
|
};
|
|
1350
1512
|
|
|
1351
|
-
const CREATE_SESSION = 'create-session';
|
|
1352
|
-
const SESSION_PREFIX = 'session:';
|
|
1353
|
-
const RENAME_PREFIX = 'session-rename:';
|
|
1354
|
-
const DELETE_PREFIX = 'session-delete:';
|
|
1355
|
-
const SEND = 'send';
|
|
1356
1513
|
const handleClickSend = async state => {
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
const getNextSelectedSessionId = (sessions, deletedId) => {
|
|
1360
|
-
if (sessions.length === 0) {
|
|
1361
|
-
return '';
|
|
1362
|
-
}
|
|
1363
|
-
const index = sessions.findIndex(session => session.id === deletedId);
|
|
1364
|
-
if (index === -1) {
|
|
1365
|
-
return sessions[0].id;
|
|
1366
|
-
}
|
|
1367
|
-
const nextIndex = Math.min(index, sessions.length - 1);
|
|
1368
|
-
return sessions[nextIndex].id;
|
|
1369
|
-
};
|
|
1370
|
-
const createSession = state => {
|
|
1371
|
-
const id = `session-${state.nextSessionId}`;
|
|
1372
|
-
const session = {
|
|
1373
|
-
id,
|
|
1374
|
-
messages: [],
|
|
1375
|
-
title: `Chat ${state.nextSessionId}`
|
|
1376
|
-
};
|
|
1377
|
-
return {
|
|
1514
|
+
const hasSelectedSession = state.sessions.some(session => session.id === state.selectedSessionId);
|
|
1515
|
+
const submitState = state.viewMode === 'list' && hasSelectedSession ? {
|
|
1378
1516
|
...state,
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
sessions: [...state.sessions, session]
|
|
1383
|
-
};
|
|
1517
|
+
viewMode: 'detail'
|
|
1518
|
+
} : state;
|
|
1519
|
+
return handleSubmit(submitState);
|
|
1384
1520
|
};
|
|
1521
|
+
|
|
1385
1522
|
const selectSession = (state, id) => {
|
|
1386
1523
|
const exists = state.sessions.some(session => session.id === id);
|
|
1387
1524
|
if (!exists) {
|
|
@@ -1390,9 +1527,11 @@ const selectSession = (state, id) => {
|
|
|
1390
1527
|
return {
|
|
1391
1528
|
...state,
|
|
1392
1529
|
renamingSessionId: '',
|
|
1393
|
-
selectedSessionId: id
|
|
1530
|
+
selectedSessionId: id,
|
|
1531
|
+
viewMode: 'detail'
|
|
1394
1532
|
};
|
|
1395
1533
|
};
|
|
1534
|
+
|
|
1396
1535
|
const startRename = (state, id) => {
|
|
1397
1536
|
const session = state.sessions.find(item => item.id === id);
|
|
1398
1537
|
if (!session) {
|
|
@@ -1401,38 +1540,47 @@ const startRename = (state, id) => {
|
|
|
1401
1540
|
return {
|
|
1402
1541
|
...state,
|
|
1403
1542
|
composerValue: session.title,
|
|
1543
|
+
inputSource: 'script',
|
|
1404
1544
|
renamingSessionId: id,
|
|
1405
1545
|
selectedSessionId: id
|
|
1406
1546
|
};
|
|
1407
1547
|
};
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1548
|
+
|
|
1549
|
+
const HEADER_HEIGHT = 40;
|
|
1550
|
+
const handleClickList = async (state, eventX, eventY) => {
|
|
1551
|
+
const {
|
|
1552
|
+
height,
|
|
1553
|
+
listItemHeight,
|
|
1554
|
+
sessions,
|
|
1555
|
+
width,
|
|
1556
|
+
x,
|
|
1557
|
+
y
|
|
1558
|
+
} = state;
|
|
1559
|
+
if (eventX < x || eventY < y) {
|
|
1411
1560
|
return state;
|
|
1412
1561
|
}
|
|
1413
|
-
if (
|
|
1414
|
-
|
|
1415
|
-
const fallback = {
|
|
1416
|
-
id: fallbackId,
|
|
1417
|
-
messages: [],
|
|
1418
|
-
title: `Chat ${state.nextSessionId}`
|
|
1419
|
-
};
|
|
1420
|
-
return {
|
|
1421
|
-
...state,
|
|
1422
|
-
nextSessionId: state.nextSessionId + 1,
|
|
1423
|
-
renamingSessionId: '',
|
|
1424
|
-
selectedSessionId: fallbackId,
|
|
1425
|
-
sessions: [fallback]
|
|
1426
|
-
};
|
|
1562
|
+
if (eventX >= x + width || eventY >= y + height) {
|
|
1563
|
+
return state;
|
|
1427
1564
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1565
|
+
const listY = eventY - y - HEADER_HEIGHT;
|
|
1566
|
+
if (listY < 0) {
|
|
1567
|
+
return state;
|
|
1568
|
+
}
|
|
1569
|
+
const itemHeight = listItemHeight > 0 ? listItemHeight : 40;
|
|
1570
|
+
const index = Math.floor(listY / itemHeight);
|
|
1571
|
+
const session = sessions[index];
|
|
1572
|
+
if (!session) {
|
|
1573
|
+
return state;
|
|
1574
|
+
}
|
|
1575
|
+
return selectSession(state, session.id);
|
|
1434
1576
|
};
|
|
1435
|
-
|
|
1577
|
+
|
|
1578
|
+
const CREATE_SESSION = 'create-session';
|
|
1579
|
+
const SESSION_PREFIX = 'session:';
|
|
1580
|
+
const RENAME_PREFIX = 'session-rename:';
|
|
1581
|
+
const SESSION_DELETE = 'SessionDelete';
|
|
1582
|
+
const SEND = 'send';
|
|
1583
|
+
const handleClick = async (state, name, id = '') => {
|
|
1436
1584
|
if (!name) {
|
|
1437
1585
|
return state;
|
|
1438
1586
|
}
|
|
@@ -1447,8 +1595,7 @@ const handleClick = async (state, name) => {
|
|
|
1447
1595
|
const id = name.slice(RENAME_PREFIX.length);
|
|
1448
1596
|
return startRename(state, id);
|
|
1449
1597
|
}
|
|
1450
|
-
if (name
|
|
1451
|
-
const id = name.slice(DELETE_PREFIX.length);
|
|
1598
|
+
if (name === SESSION_DELETE) {
|
|
1452
1599
|
return deleteSession(state, id);
|
|
1453
1600
|
}
|
|
1454
1601
|
if (name === SEND) {
|
|
@@ -1457,26 +1604,124 @@ const handleClick = async (state, name) => {
|
|
|
1457
1604
|
return state;
|
|
1458
1605
|
};
|
|
1459
1606
|
|
|
1607
|
+
const handleClickBack = async state => {
|
|
1608
|
+
return {
|
|
1609
|
+
...state,
|
|
1610
|
+
renamingSessionId: '',
|
|
1611
|
+
viewMode: 'list'
|
|
1612
|
+
};
|
|
1613
|
+
};
|
|
1614
|
+
|
|
1460
1615
|
const handleClickClose = async () => {
|
|
1461
1616
|
// @ts-ignore
|
|
1462
|
-
await invoke('
|
|
1617
|
+
await invoke('Layout.hideSecondarySideBar');
|
|
1618
|
+
};
|
|
1619
|
+
|
|
1620
|
+
const handleClickDelete = async (state, sessionId = '') => {
|
|
1621
|
+
return deleteSession(state, sessionId);
|
|
1622
|
+
};
|
|
1623
|
+
|
|
1624
|
+
const handleClickNew = async state => {
|
|
1625
|
+
return createSession(state);
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1628
|
+
const handleClickSettings = async () => {
|
|
1629
|
+
// TODO
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1632
|
+
const handleInput = async (state, value, inputSource = 'user') => {
|
|
1633
|
+
return {
|
|
1634
|
+
...state,
|
|
1635
|
+
composerValue: value,
|
|
1636
|
+
inputSource
|
|
1637
|
+
};
|
|
1463
1638
|
};
|
|
1464
1639
|
|
|
1465
|
-
const
|
|
1640
|
+
const handleInputFocus = async (state, name) => {
|
|
1641
|
+
if (name === 'composer') {
|
|
1642
|
+
return focusInput(state);
|
|
1643
|
+
}
|
|
1644
|
+
if (name === 'send') {
|
|
1645
|
+
return {
|
|
1646
|
+
...state,
|
|
1647
|
+
focus: 'send-button',
|
|
1648
|
+
focused: true
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
if (name.startsWith('session:') || name === 'SessionDelete') {
|
|
1652
|
+
return {
|
|
1653
|
+
...state,
|
|
1654
|
+
focus: 'list',
|
|
1655
|
+
focused: true
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
if (name === 'create-session' || name === 'settings' || name === 'close-chat' || name === 'back') {
|
|
1659
|
+
return {
|
|
1660
|
+
...state,
|
|
1661
|
+
focus: 'header',
|
|
1662
|
+
focused: true
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1665
|
+
return {
|
|
1666
|
+
...state,
|
|
1667
|
+
focused: false
|
|
1668
|
+
};
|
|
1669
|
+
};
|
|
1466
1670
|
|
|
1467
|
-
const
|
|
1468
|
-
|
|
1671
|
+
const submitRename = state => {
|
|
1672
|
+
const {
|
|
1673
|
+
composerValue,
|
|
1674
|
+
renamingSessionId,
|
|
1675
|
+
sessions
|
|
1676
|
+
} = state;
|
|
1677
|
+
const title = composerValue.trim();
|
|
1678
|
+
if (!renamingSessionId || !title) {
|
|
1469
1679
|
return {
|
|
1470
1680
|
...state,
|
|
1471
|
-
|
|
1681
|
+
renamingSessionId: ''
|
|
1472
1682
|
};
|
|
1473
1683
|
}
|
|
1684
|
+
const updatedSessions = sessions.map(session => {
|
|
1685
|
+
if (session.id !== renamingSessionId) {
|
|
1686
|
+
return session;
|
|
1687
|
+
}
|
|
1688
|
+
return {
|
|
1689
|
+
...session,
|
|
1690
|
+
title
|
|
1691
|
+
};
|
|
1692
|
+
});
|
|
1474
1693
|
return {
|
|
1475
1694
|
...state,
|
|
1476
|
-
composerValue:
|
|
1695
|
+
composerValue: '',
|
|
1696
|
+
inputSource: 'script',
|
|
1697
|
+
renamingSessionId: '',
|
|
1698
|
+
sessions: updatedSessions
|
|
1477
1699
|
};
|
|
1478
1700
|
};
|
|
1479
1701
|
|
|
1702
|
+
const handleKeyDown = async (state, key, shiftKey) => {
|
|
1703
|
+
const {
|
|
1704
|
+
composerValue,
|
|
1705
|
+
renamingSessionId,
|
|
1706
|
+
selectedSessionId,
|
|
1707
|
+
sessions,
|
|
1708
|
+
viewMode
|
|
1709
|
+
} = state;
|
|
1710
|
+
if (key !== 'Enter' || shiftKey) {
|
|
1711
|
+
return state;
|
|
1712
|
+
}
|
|
1713
|
+
if (renamingSessionId) {
|
|
1714
|
+
return submitRename(state);
|
|
1715
|
+
}
|
|
1716
|
+
const hasInput = composerValue.trim().length > 0;
|
|
1717
|
+
const hasSelectedSession = sessions.some(session => session.id === selectedSessionId);
|
|
1718
|
+
const submitState = viewMode === 'list' && hasInput && hasSelectedSession ? {
|
|
1719
|
+
...state,
|
|
1720
|
+
viewMode: 'detail'
|
|
1721
|
+
} : state;
|
|
1722
|
+
return handleSubmit(submitState);
|
|
1723
|
+
};
|
|
1724
|
+
|
|
1480
1725
|
const id = 7201;
|
|
1481
1726
|
const sendMessagePortToExtensionHostWorker = async port => {
|
|
1482
1727
|
await sendMessagePortToExtensionHostWorker$1(port, id);
|
|
@@ -1499,26 +1744,79 @@ const initialize = async () => {
|
|
|
1499
1744
|
set$2(rpc);
|
|
1500
1745
|
};
|
|
1501
1746
|
|
|
1502
|
-
const
|
|
1503
|
-
|
|
1504
|
-
|
|
1747
|
+
const isObject = value => {
|
|
1748
|
+
return typeof value === 'object' && value !== null;
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1751
|
+
const getSavedBounds = savedState => {
|
|
1752
|
+
if (!isObject(savedState)) {
|
|
1753
|
+
return undefined;
|
|
1505
1754
|
}
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
}
|
|
1755
|
+
const {
|
|
1756
|
+
height,
|
|
1757
|
+
width,
|
|
1758
|
+
x,
|
|
1759
|
+
y
|
|
1760
|
+
} = savedState;
|
|
1761
|
+
if (typeof x !== 'number') {
|
|
1762
|
+
return undefined;
|
|
1763
|
+
}
|
|
1764
|
+
if (typeof y !== 'number') {
|
|
1765
|
+
return undefined;
|
|
1766
|
+
}
|
|
1767
|
+
if (typeof width !== 'number') {
|
|
1768
|
+
return undefined;
|
|
1769
|
+
}
|
|
1770
|
+
if (typeof height !== 'number') {
|
|
1771
|
+
return undefined;
|
|
1772
|
+
}
|
|
1773
|
+
return {
|
|
1774
|
+
height,
|
|
1775
|
+
width,
|
|
1776
|
+
x,
|
|
1777
|
+
y
|
|
1778
|
+
};
|
|
1512
1779
|
};
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1780
|
+
|
|
1781
|
+
const getSavedSelectedSessionId = savedState => {
|
|
1782
|
+
if (!isObject(savedState)) {
|
|
1783
|
+
return undefined;
|
|
1784
|
+
}
|
|
1785
|
+
const {
|
|
1786
|
+
selectedSessionId
|
|
1787
|
+
} = savedState;
|
|
1788
|
+
if (typeof selectedSessionId !== 'string') {
|
|
1789
|
+
return undefined;
|
|
1790
|
+
}
|
|
1791
|
+
return selectedSessionId;
|
|
1792
|
+
};
|
|
1793
|
+
|
|
1794
|
+
const getSavedSessions = savedState => {
|
|
1795
|
+
if (!isObject(savedState)) {
|
|
1796
|
+
return undefined;
|
|
1797
|
+
}
|
|
1798
|
+
const {
|
|
1799
|
+
sessions
|
|
1800
|
+
} = savedState;
|
|
1801
|
+
if (!Array.isArray(sessions)) {
|
|
1802
|
+
return undefined;
|
|
1803
|
+
}
|
|
1804
|
+
return sessions;
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1807
|
+
const loadContent = async (state, savedState) => {
|
|
1808
|
+
const savedBounds = getSavedBounds(savedState);
|
|
1809
|
+
const sessions = getSavedSessions(savedState) || state.sessions;
|
|
1810
|
+
const preferredSessionId = getSavedSelectedSessionId(savedState) || state.selectedSessionId;
|
|
1811
|
+
const selectedSessionId = sessions.some(session => session.id === preferredSessionId) ? preferredSessionId : sessions[0]?.id || '';
|
|
1812
|
+
const viewMode = sessions.length === 0 ? 'list' : state.viewMode === 'detail' ? 'detail' : 'list';
|
|
1516
1813
|
return {
|
|
1517
1814
|
...state,
|
|
1815
|
+
...savedBounds,
|
|
1518
1816
|
initial: false,
|
|
1519
|
-
nextSessionId: state.sessions.length === 0 ? state.nextSessionId + 1 : state.nextSessionId,
|
|
1520
1817
|
selectedSessionId,
|
|
1521
|
-
sessions
|
|
1818
|
+
sessions,
|
|
1819
|
+
viewMode
|
|
1522
1820
|
};
|
|
1523
1821
|
};
|
|
1524
1822
|
|
|
@@ -1530,6 +1828,30 @@ const renderCss = (oldState, newState) => {
|
|
|
1530
1828
|
return [SetCss, newState.uid, css];
|
|
1531
1829
|
};
|
|
1532
1830
|
|
|
1831
|
+
const getFocusSelector = focus => {
|
|
1832
|
+
switch (focus) {
|
|
1833
|
+
case 'composer':
|
|
1834
|
+
case 'input':
|
|
1835
|
+
return '[name="composer"]';
|
|
1836
|
+
case 'header':
|
|
1837
|
+
return '[name="create-session"]';
|
|
1838
|
+
case 'list':
|
|
1839
|
+
return '[name^="session:"]';
|
|
1840
|
+
case 'send-button':
|
|
1841
|
+
return '[name="send"]';
|
|
1842
|
+
default:
|
|
1843
|
+
return '[name="composer"]';
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
const renderFocus = (oldState, newState) => {
|
|
1847
|
+
const selector = getFocusSelector(newState.focus);
|
|
1848
|
+
return [FocusSelector, selector];
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
const mergeClassNames = (...classNames) => {
|
|
1852
|
+
return classNames.filter(Boolean).join(' ');
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1533
1855
|
const text = data => {
|
|
1534
1856
|
return {
|
|
1535
1857
|
childCount: 0,
|
|
@@ -1827,168 +2149,261 @@ const diffTree = (oldNodes, newNodes) => {
|
|
|
1827
2149
|
};
|
|
1828
2150
|
|
|
1829
2151
|
const ChatActions = 'ChatActions';
|
|
2152
|
+
const ChatName = 'ChatName';
|
|
2153
|
+
const ChatSendArea = 'ChatSendArea';
|
|
2154
|
+
const Chat = 'Chat';
|
|
1830
2155
|
const ChatHeader = 'ChatHeader';
|
|
1831
2156
|
const Button = 'Button';
|
|
1832
|
-
const
|
|
1833
|
-
const
|
|
2157
|
+
const ButtonDisabled = 'ButtonDisabled';
|
|
2158
|
+
const ButtonPrimary = 'ButtonPrimary';
|
|
1834
2159
|
const IconButton = 'IconButton';
|
|
1835
2160
|
const Label = 'Label';
|
|
1836
2161
|
const ChatList = 'ChatList';
|
|
2162
|
+
const ChatListItem = 'ChatListItem';
|
|
2163
|
+
const ChatListItemLabel = 'ChatListItemLabel';
|
|
1837
2164
|
const Markdown = 'Markdown';
|
|
1838
2165
|
const Message = 'Message';
|
|
1839
2166
|
const MultilineInputBox = 'MultilineInputBox';
|
|
1840
2167
|
const Viewlet = 'Viewlet';
|
|
1841
2168
|
const ChatWelcomeMessage = 'ChatWelcomeMessage';
|
|
1842
2169
|
|
|
2170
|
+
const HandleContextMenu = 2;
|
|
2171
|
+
const HandleFocus = 3;
|
|
1843
2172
|
const HandleInput = 4;
|
|
1844
2173
|
const HandleClick = 11;
|
|
1845
2174
|
const HandleKeyDown = 12;
|
|
1846
2175
|
const HandleClickClose = 13;
|
|
1847
2176
|
const HandleClickSettings = 14;
|
|
1848
|
-
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
}
|
|
1857
|
-
return messages.flatMap(message => {
|
|
1858
|
-
return [{
|
|
1859
|
-
childCount: 2,
|
|
1860
|
-
className: Message,
|
|
1861
|
-
type: Div
|
|
1862
|
-
}, {
|
|
1863
|
-
childCount: 1,
|
|
1864
|
-
className: Label,
|
|
1865
|
-
type: Strong
|
|
1866
|
-
}, text(message.role === 'user' ? 'You' : 'Assistant'), {
|
|
1867
|
-
childCount: 1,
|
|
1868
|
-
className: Markdown,
|
|
1869
|
-
type: P
|
|
1870
|
-
}, text(message.text)];
|
|
1871
|
-
});
|
|
1872
|
-
};
|
|
1873
|
-
|
|
1874
|
-
const getSessionDom = (session, _selectedSessionId) => {
|
|
1875
|
-
const sessionClassName = ChatList;
|
|
2177
|
+
const HandleClickNew = 15;
|
|
2178
|
+
const HandleClickBack = 16;
|
|
2179
|
+
const HandleClickList = 17;
|
|
2180
|
+
const HandleClickDelete = 18;
|
|
2181
|
+
const HandleSubmit = 19;
|
|
2182
|
+
|
|
2183
|
+
const getChatSendAreaDom = composerValue => {
|
|
2184
|
+
const isSendDisabled = composerValue.trim() === '';
|
|
2185
|
+
const sendButtonClassName = isSendDisabled ? `${Button} ${ButtonPrimary} ${ButtonDisabled}` : `${Button} ${ButtonPrimary}`;
|
|
1876
2186
|
return [{
|
|
1877
2187
|
childCount: 2,
|
|
1878
|
-
className:
|
|
2188
|
+
className: ChatSendArea,
|
|
1879
2189
|
type: Div
|
|
2190
|
+
}, {
|
|
2191
|
+
childCount: 0,
|
|
2192
|
+
className: MultilineInputBox,
|
|
2193
|
+
name: 'composer',
|
|
2194
|
+
onInput: HandleInput,
|
|
2195
|
+
placeholder: composePlaceholder,
|
|
2196
|
+
rows: 4,
|
|
2197
|
+
type: TextArea,
|
|
2198
|
+
value: composerValue
|
|
1880
2199
|
}, {
|
|
1881
2200
|
childCount: 1,
|
|
1882
|
-
className:
|
|
1883
|
-
|
|
2201
|
+
className: sendButtonClassName,
|
|
2202
|
+
disabled: isSendDisabled,
|
|
2203
|
+
name: 'send',
|
|
2204
|
+
onClick: HandleSubmit,
|
|
1884
2205
|
role: Button$2,
|
|
1885
|
-
|
|
2206
|
+
title: sendMessage,
|
|
1886
2207
|
type: Button$1
|
|
1887
|
-
}, text(
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
2208
|
+
}, text(send)];
|
|
2209
|
+
};
|
|
2210
|
+
|
|
2211
|
+
const getHeaderActionVirtualDom = item => {
|
|
2212
|
+
return [{
|
|
1892
2213
|
childCount: 1,
|
|
1893
2214
|
className: IconButton,
|
|
1894
|
-
name:
|
|
2215
|
+
name: item.name,
|
|
2216
|
+
onClick: item.onClick,
|
|
1895
2217
|
role: Button$2,
|
|
1896
|
-
|
|
1897
|
-
title: 'Rename chat session',
|
|
2218
|
+
title: item.title,
|
|
1898
2219
|
type: Button$1
|
|
1899
|
-
}, text(
|
|
2220
|
+
}, text(item.icon)];
|
|
2221
|
+
};
|
|
2222
|
+
|
|
2223
|
+
const getChatHeaderActionsDom = () => {
|
|
2224
|
+
const items = [{
|
|
2225
|
+
icon: '+',
|
|
2226
|
+
name: 'create-session',
|
|
2227
|
+
onClick: HandleClickNew,
|
|
2228
|
+
title: newChat
|
|
2229
|
+
}, {
|
|
2230
|
+
icon: '⚙',
|
|
2231
|
+
name: 'settings',
|
|
2232
|
+
onClick: HandleClickSettings,
|
|
2233
|
+
title: settings
|
|
2234
|
+
}, {
|
|
2235
|
+
icon: '×',
|
|
2236
|
+
name: 'close-chat',
|
|
2237
|
+
onClick: HandleClickClose,
|
|
2238
|
+
title: closeChat
|
|
2239
|
+
}];
|
|
2240
|
+
return [{
|
|
2241
|
+
childCount: items.length,
|
|
2242
|
+
className: ChatActions,
|
|
2243
|
+
type: Div
|
|
2244
|
+
}, ...items.flatMap(getHeaderActionVirtualDom)];
|
|
2245
|
+
};
|
|
2246
|
+
|
|
2247
|
+
const getChatHeaderBackButtonVirtualDom = () => {
|
|
2248
|
+
return [{
|
|
1900
2249
|
childCount: 1,
|
|
1901
2250
|
className: IconButton,
|
|
1902
|
-
name:
|
|
2251
|
+
name: 'back',
|
|
2252
|
+
onClick: HandleClickBack,
|
|
1903
2253
|
role: Button$2,
|
|
1904
|
-
|
|
1905
|
-
title: 'Delete chat session',
|
|
2254
|
+
title: backToChats,
|
|
1906
2255
|
type: Button$1
|
|
1907
|
-
}, text('
|
|
2256
|
+
}, text('←')];
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
const getChatHeaderDomDetailMode = selectedSessionTitle => {
|
|
2260
|
+
return [{
|
|
2261
|
+
childCount: 2,
|
|
2262
|
+
className: ChatHeader,
|
|
2263
|
+
type: Div
|
|
2264
|
+
}, {
|
|
2265
|
+
childCount: 2,
|
|
2266
|
+
className: ChatName,
|
|
2267
|
+
type: Div
|
|
2268
|
+
}, ...getChatHeaderBackButtonVirtualDom(), {
|
|
2269
|
+
childCount: 1,
|
|
2270
|
+
className: Label,
|
|
2271
|
+
type: Span
|
|
2272
|
+
}, text(selectedSessionTitle), ...getChatHeaderActionsDom()];
|
|
2273
|
+
};
|
|
2274
|
+
|
|
2275
|
+
const getChatMessageDom = message => {
|
|
2276
|
+
return [{
|
|
2277
|
+
childCount: 2,
|
|
2278
|
+
className: Message,
|
|
2279
|
+
type: Div
|
|
2280
|
+
}, {
|
|
2281
|
+
childCount: 1,
|
|
2282
|
+
className: Label,
|
|
2283
|
+
type: Div
|
|
2284
|
+
}, text(`${message.role === 'user' ? you : assistant} · ${message.time}`), {
|
|
2285
|
+
childCount: 1,
|
|
2286
|
+
className: Markdown,
|
|
2287
|
+
type: P
|
|
2288
|
+
}, text(message.text)];
|
|
1908
2289
|
};
|
|
1909
2290
|
|
|
1910
|
-
const
|
|
2291
|
+
const getMessagesDom = messages => {
|
|
2292
|
+
if (messages.length === 0) {
|
|
2293
|
+
return [{
|
|
2294
|
+
childCount: 1,
|
|
2295
|
+
className: ChatWelcomeMessage,
|
|
2296
|
+
type: Div
|
|
2297
|
+
}, text(startConversation)];
|
|
2298
|
+
}
|
|
2299
|
+
return [{
|
|
2300
|
+
childCount: messages.length,
|
|
2301
|
+
className: 'ChatMessages',
|
|
2302
|
+
type: Div
|
|
2303
|
+
}, ...messages.flatMap(getChatMessageDom)];
|
|
2304
|
+
};
|
|
2305
|
+
|
|
2306
|
+
const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue) => {
|
|
1911
2307
|
const selectedSession = sessions.find(session => session.id === selectedSessionId);
|
|
2308
|
+
const selectedSessionTitle = selectedSession?.title || chatTitle;
|
|
1912
2309
|
const messages = selectedSession ? selectedSession.messages : [];
|
|
1913
|
-
|
|
1914
|
-
const messagesNodes = getMessagesDom(messages);
|
|
1915
|
-
const dom = [{
|
|
2310
|
+
return [{
|
|
1916
2311
|
childCount: 3,
|
|
1917
|
-
className: Viewlet
|
|
1918
|
-
onClick: HandleClick,
|
|
1919
|
-
onInput: HandleInput,
|
|
1920
|
-
onKeyDown: HandleKeyDown,
|
|
2312
|
+
className: mergeClassNames(Viewlet, Chat),
|
|
1921
2313
|
type: Div
|
|
1922
|
-
},
|
|
2314
|
+
}, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages), ...getChatSendAreaDom(composerValue)];
|
|
2315
|
+
};
|
|
2316
|
+
|
|
2317
|
+
const getChatHeaderListModeDom = () => {
|
|
2318
|
+
return [{
|
|
1923
2319
|
childCount: 2,
|
|
1924
2320
|
className: ChatHeader,
|
|
1925
2321
|
type: Div
|
|
1926
|
-
}, {
|
|
1927
|
-
childCount: 4,
|
|
1928
|
-
className: ChatActions,
|
|
1929
|
-
type: Div
|
|
1930
2322
|
}, {
|
|
1931
2323
|
childCount: 1,
|
|
1932
2324
|
className: Label,
|
|
1933
2325
|
type: Span
|
|
1934
|
-
}, text(
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
tabIndex: 0,
|
|
1940
|
-
title: 'New Chat',
|
|
1941
|
-
type: Button$1
|
|
1942
|
-
}, text('+'), {
|
|
1943
|
-
childCount: 1,
|
|
1944
|
-
className: IconButton,
|
|
1945
|
-
onClick: HandleClickSettings,
|
|
1946
|
-
role: Button$2,
|
|
1947
|
-
tabIndex: 0,
|
|
1948
|
-
title: 'Settings',
|
|
1949
|
-
type: Button$1
|
|
1950
|
-
}, text('⚙'), {
|
|
2326
|
+
}, text(chats), ...getChatHeaderActionsDom()];
|
|
2327
|
+
};
|
|
2328
|
+
|
|
2329
|
+
const getEmptyChatSessionsDom = () => {
|
|
2330
|
+
return [{
|
|
1951
2331
|
childCount: 1,
|
|
1952
|
-
className: IconButton,
|
|
1953
|
-
onClick: HandleClickClose,
|
|
1954
|
-
role: Button$2,
|
|
1955
|
-
tabIndex: 0,
|
|
1956
|
-
title: 'Close Chat',
|
|
1957
|
-
type: Button$1
|
|
1958
|
-
}, text('×'), {
|
|
1959
|
-
childCount: sessions.length,
|
|
1960
2332
|
className: ChatList,
|
|
1961
2333
|
type: Div
|
|
1962
|
-
},
|
|
2334
|
+
}, {
|
|
2335
|
+
childCount: 1,
|
|
2336
|
+
className: Label,
|
|
2337
|
+
type: Div
|
|
2338
|
+
}, text(clickToOpenNewChat)];
|
|
2339
|
+
};
|
|
2340
|
+
|
|
2341
|
+
const getSessionDom = session => {
|
|
2342
|
+
const sessionClassName = ChatListItem;
|
|
2343
|
+
return [{
|
|
1963
2344
|
childCount: 2,
|
|
1964
|
-
className:
|
|
2345
|
+
className: sessionClassName,
|
|
1965
2346
|
type: Div
|
|
1966
2347
|
}, {
|
|
1967
|
-
childCount:
|
|
1968
|
-
className:
|
|
2348
|
+
childCount: 1,
|
|
2349
|
+
className: ChatListItemLabel,
|
|
2350
|
+
name: `session:${session.id}`,
|
|
2351
|
+
onContextMenu: HandleContextMenu,
|
|
2352
|
+
tabIndex: 0,
|
|
1969
2353
|
type: Div
|
|
1970
|
-
},
|
|
1971
|
-
childCount:
|
|
2354
|
+
}, text(session.title), {
|
|
2355
|
+
childCount: 1,
|
|
1972
2356
|
className: ChatActions,
|
|
1973
2357
|
type: Div
|
|
1974
|
-
}, {
|
|
1975
|
-
childCount: 0,
|
|
1976
|
-
className: MultilineInputBox,
|
|
1977
|
-
name: 'composer',
|
|
1978
|
-
placeholder: 'Type your message. Enter to send, Shift+Enter for newline.',
|
|
1979
|
-
rows: 4,
|
|
1980
|
-
type: TextArea,
|
|
1981
|
-
value: composerValue
|
|
1982
2358
|
}, {
|
|
1983
2359
|
childCount: 1,
|
|
1984
|
-
className:
|
|
1985
|
-
|
|
2360
|
+
className: IconButton,
|
|
2361
|
+
'data-id': session.id,
|
|
2362
|
+
name: 'SessionDelete',
|
|
2363
|
+
onClick: HandleClickDelete,
|
|
1986
2364
|
role: Button$2,
|
|
1987
2365
|
tabIndex: 0,
|
|
1988
|
-
title:
|
|
2366
|
+
title: deleteChatSession,
|
|
1989
2367
|
type: Button$1
|
|
1990
|
-
}, text('
|
|
1991
|
-
|
|
2368
|
+
}, text('🗑')];
|
|
2369
|
+
};
|
|
2370
|
+
|
|
2371
|
+
const getChatListDom = (sessions, selectedSessionId) => {
|
|
2372
|
+
if (sessions.length === 0) {
|
|
2373
|
+
return getEmptyChatSessionsDom();
|
|
2374
|
+
}
|
|
2375
|
+
return [{
|
|
2376
|
+
childCount: sessions.length,
|
|
2377
|
+
className: ChatList,
|
|
2378
|
+
onClick: HandleClickList,
|
|
2379
|
+
type: Div
|
|
2380
|
+
}, ...sessions.flatMap(getSessionDom)];
|
|
2381
|
+
};
|
|
2382
|
+
|
|
2383
|
+
const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue) => {
|
|
2384
|
+
return [{
|
|
2385
|
+
childCount: 3,
|
|
2386
|
+
className: mergeClassNames(Viewlet, Chat),
|
|
2387
|
+
type: Div
|
|
2388
|
+
}, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue)];
|
|
2389
|
+
};
|
|
2390
|
+
|
|
2391
|
+
const getChatModeUnsupportedVirtualDom = () => {
|
|
2392
|
+
return [{
|
|
2393
|
+
childCount: 1,
|
|
2394
|
+
type: Div
|
|
2395
|
+
}, text('Unknown view mode')];
|
|
2396
|
+
};
|
|
2397
|
+
|
|
2398
|
+
const getChatVirtualDom = (sessions, selectedSessionId, composerValue, viewMode) => {
|
|
2399
|
+
switch (viewMode) {
|
|
2400
|
+
case 'detail':
|
|
2401
|
+
return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue);
|
|
2402
|
+
case 'list':
|
|
2403
|
+
return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue);
|
|
2404
|
+
default:
|
|
2405
|
+
return getChatModeUnsupportedVirtualDom();
|
|
2406
|
+
}
|
|
1992
2407
|
};
|
|
1993
2408
|
|
|
1994
2409
|
const renderItems = (oldState, newState) => {
|
|
@@ -1997,12 +2412,13 @@ const renderItems = (oldState, newState) => {
|
|
|
1997
2412
|
initial,
|
|
1998
2413
|
selectedSessionId,
|
|
1999
2414
|
sessions,
|
|
2000
|
-
uid
|
|
2415
|
+
uid,
|
|
2416
|
+
viewMode
|
|
2001
2417
|
} = newState;
|
|
2002
2418
|
if (initial) {
|
|
2003
2419
|
return [SetDom2, uid, []];
|
|
2004
2420
|
}
|
|
2005
|
-
const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue);
|
|
2421
|
+
const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, viewMode);
|
|
2006
2422
|
return [SetDom2, uid, dom];
|
|
2007
2423
|
};
|
|
2008
2424
|
|
|
@@ -2013,14 +2429,25 @@ const renderIncremental = (oldState, newState) => {
|
|
|
2013
2429
|
return [SetPatches, newState.uid, patches];
|
|
2014
2430
|
};
|
|
2015
2431
|
|
|
2432
|
+
const renderValue = (oldState, newState) => {
|
|
2433
|
+
const {
|
|
2434
|
+
composerValue
|
|
2435
|
+
} = newState;
|
|
2436
|
+
return [SetValueByName, newState.uid, 'composer', composerValue];
|
|
2437
|
+
};
|
|
2438
|
+
|
|
2016
2439
|
const getRenderer = diffType => {
|
|
2017
2440
|
switch (diffType) {
|
|
2018
2441
|
case RenderCss:
|
|
2019
2442
|
return renderCss;
|
|
2443
|
+
case RenderFocus:
|
|
2444
|
+
return renderFocus;
|
|
2020
2445
|
case RenderIncremental:
|
|
2021
2446
|
return renderIncremental;
|
|
2022
2447
|
case RenderItems:
|
|
2023
2448
|
return renderItems;
|
|
2449
|
+
case RenderValue:
|
|
2450
|
+
return renderValue;
|
|
2024
2451
|
default:
|
|
2025
2452
|
throw new Error('unknown renderer');
|
|
2026
2453
|
}
|
|
@@ -2050,23 +2477,55 @@ const render2 = (uid, diffResult) => {
|
|
|
2050
2477
|
|
|
2051
2478
|
const renderEventListeners = () => {
|
|
2052
2479
|
return [{
|
|
2480
|
+
name: HandleContextMenu,
|
|
2481
|
+
params: ['handleChatListContextMenu', TargetName, ClientX, ClientY],
|
|
2482
|
+
preventDefault: true
|
|
2483
|
+
}, {
|
|
2053
2484
|
name: HandleClick,
|
|
2054
|
-
params: ['handleClick', TargetName]
|
|
2485
|
+
params: ['handleClick', TargetName, 'event.target.dataset.id']
|
|
2486
|
+
}, {
|
|
2487
|
+
name: HandleClickDelete,
|
|
2488
|
+
params: ['handleClickDelete', 'event.target.dataset.id']
|
|
2055
2489
|
}, {
|
|
2056
2490
|
name: HandleClickClose,
|
|
2057
2491
|
params: ['handleClickClose']
|
|
2058
2492
|
}, {
|
|
2059
2493
|
name: HandleClickSettings,
|
|
2060
2494
|
params: ['handleClickSettings']
|
|
2495
|
+
}, {
|
|
2496
|
+
name: HandleClickNew,
|
|
2497
|
+
params: ['handleClickNew']
|
|
2498
|
+
}, {
|
|
2499
|
+
name: HandleClickBack,
|
|
2500
|
+
params: ['handleClickBack']
|
|
2501
|
+
}, {
|
|
2502
|
+
name: HandleClickList,
|
|
2503
|
+
params: ['handleClickList', ClientX, ClientY]
|
|
2061
2504
|
}, {
|
|
2062
2505
|
name: HandleInput,
|
|
2063
2506
|
params: ['handleInput', TargetValue]
|
|
2507
|
+
}, {
|
|
2508
|
+
name: HandleFocus,
|
|
2509
|
+
params: ['handleInputFocus', TargetName]
|
|
2064
2510
|
}, {
|
|
2065
2511
|
name: HandleKeyDown,
|
|
2066
2512
|
params: ['handleKeyDown', Key, ShiftKey]
|
|
2513
|
+
}, {
|
|
2514
|
+
name: HandleSubmit,
|
|
2515
|
+
params: ['handleSubmit']
|
|
2067
2516
|
}];
|
|
2068
2517
|
};
|
|
2069
2518
|
|
|
2519
|
+
const reset = async state => {
|
|
2520
|
+
return {
|
|
2521
|
+
...state,
|
|
2522
|
+
composerValue: '',
|
|
2523
|
+
selectedSessionId: '',
|
|
2524
|
+
sessions: [],
|
|
2525
|
+
viewMode: 'list'
|
|
2526
|
+
};
|
|
2527
|
+
};
|
|
2528
|
+
|
|
2070
2529
|
const resize = (state, dimensions) => {
|
|
2071
2530
|
return {
|
|
2072
2531
|
...state,
|
|
@@ -2077,59 +2536,76 @@ const resize = (state, dimensions) => {
|
|
|
2077
2536
|
const saveState = state => {
|
|
2078
2537
|
const {
|
|
2079
2538
|
composerValue,
|
|
2539
|
+
height,
|
|
2080
2540
|
nextMessageId,
|
|
2081
|
-
nextSessionId,
|
|
2082
2541
|
renamingSessionId,
|
|
2083
2542
|
selectedSessionId,
|
|
2084
|
-
sessions
|
|
2543
|
+
sessions,
|
|
2544
|
+
viewMode,
|
|
2545
|
+
width,
|
|
2546
|
+
x,
|
|
2547
|
+
y
|
|
2085
2548
|
} = state;
|
|
2086
2549
|
return {
|
|
2087
2550
|
composerValue,
|
|
2551
|
+
height,
|
|
2088
2552
|
nextMessageId,
|
|
2089
|
-
nextSessionId,
|
|
2090
2553
|
renamingSessionId,
|
|
2091
2554
|
selectedSessionId,
|
|
2092
|
-
sessions
|
|
2555
|
+
sessions,
|
|
2556
|
+
viewMode,
|
|
2557
|
+
width,
|
|
2558
|
+
x,
|
|
2559
|
+
y
|
|
2093
2560
|
};
|
|
2094
2561
|
};
|
|
2095
2562
|
|
|
2096
2563
|
const dummySessions = [{
|
|
2097
2564
|
id: 'session-a',
|
|
2098
2565
|
messages: [],
|
|
2099
|
-
title:
|
|
2566
|
+
title: dummyChatA
|
|
2100
2567
|
}, {
|
|
2101
2568
|
id: 'session-b',
|
|
2102
2569
|
messages: [],
|
|
2103
|
-
title:
|
|
2570
|
+
title: dummyChatB
|
|
2104
2571
|
}, {
|
|
2105
2572
|
id: 'session-c',
|
|
2106
2573
|
messages: [],
|
|
2107
|
-
title:
|
|
2574
|
+
title: dummyChatC
|
|
2108
2575
|
}];
|
|
2109
2576
|
const setChatList = state => {
|
|
2110
2577
|
return {
|
|
2111
2578
|
...state,
|
|
2112
|
-
nextSessionId: dummySessions.length + 1,
|
|
2113
2579
|
selectedSessionId: dummySessions[0].id,
|
|
2114
|
-
sessions: dummySessions
|
|
2580
|
+
sessions: dummySessions,
|
|
2581
|
+
viewMode: 'detail'
|
|
2115
2582
|
};
|
|
2116
2583
|
};
|
|
2117
2584
|
|
|
2118
2585
|
const commandMap = {
|
|
2586
|
+
'Chat.clearInput': wrapCommand(clearInput),
|
|
2119
2587
|
'Chat.create': create,
|
|
2120
2588
|
'Chat.diff2': diff2,
|
|
2121
2589
|
'Chat.getCommandIds': getCommandIds,
|
|
2122
2590
|
'Chat.getKeyBindings': getKeyBindings,
|
|
2591
|
+
'Chat.handleChatListContextMenu': handleChatListContextMenu,
|
|
2123
2592
|
'Chat.handleClick': wrapCommand(handleClick),
|
|
2593
|
+
'Chat.handleClickBack': wrapCommand(handleClickBack),
|
|
2124
2594
|
'Chat.handleClickClose': handleClickClose,
|
|
2595
|
+
'Chat.handleClickDelete': wrapCommand(handleClickDelete),
|
|
2596
|
+
'Chat.handleClickList': wrapCommand(handleClickList),
|
|
2597
|
+
'Chat.handleClickNew': wrapCommand(handleClickNew),
|
|
2125
2598
|
'Chat.handleClickSettings': handleClickSettings,
|
|
2126
2599
|
'Chat.handleInput': wrapCommand(handleInput),
|
|
2600
|
+
'Chat.handleInputFocus': wrapCommand(handleInputFocus),
|
|
2127
2601
|
'Chat.handleKeyDown': wrapCommand(handleKeyDown),
|
|
2602
|
+
'Chat.handleSubmit': wrapCommand(handleSubmit),
|
|
2128
2603
|
'Chat.initialize': initialize,
|
|
2129
2604
|
'Chat.loadContent': wrapCommand(loadContent),
|
|
2130
2605
|
'Chat.loadContent2': wrapCommand(loadContent),
|
|
2131
2606
|
'Chat.render2': render2,
|
|
2132
2607
|
'Chat.renderEventListeners': renderEventListeners,
|
|
2608
|
+
'Chat.reset': wrapCommand(reset),
|
|
2133
2609
|
'Chat.resize': wrapCommand(resize),
|
|
2134
2610
|
'Chat.saveState': wrapGetter(saveState),
|
|
2135
2611
|
'Chat.setChatList': wrapCommand(setChatList),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/chat-view",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Chat View Worker",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"type": "module",
|
|
12
12
|
"main": "dist/chatViewWorkerMain.js",
|
|
13
13
|
"dependencies": {
|
|
14
|
+
"@lvce-editor/i18n": "^2.1.0",
|
|
14
15
|
"@lvce-editor/virtual-dom-worker": "^8.9.0"
|
|
15
16
|
}
|
|
16
17
|
}
|