Skip to content

Commit a98c983

Browse files
committed
fix: still recevie message after reply end
1 parent f76df7b commit a98c983

File tree

8 files changed

+82
-154
lines changed

8 files changed

+82
-154
lines changed

docker/app/Dockerfile

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ ENV CI=true
1616
USER root
1717
WORKDIR /repo
1818

19-
COPY --from=source-tree /repo/pnpm-lock.yaml /repo/pnpm-lock.yaml
20-
COPY --from=source-tree /repo/.npmrc /repo/.npmrc
19+
COPY --from=source-tree /repo/pnpm-lock.yaml /repo/.npmrc /repo/
2120

2221
RUN pnpm fetch
2322

packages/secretnote/src/components/dropdown-menu/index.less

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
}
3232

3333
.ant-upload {
34+
padding-left: 30px;
35+
margin-left: -30px;
3436
color: var(--mana-secretnote-text-color);
3537
font-size: 12px;
3638
}

packages/secretnote/src/modules/editor/cell/view.tsx

+66-81
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
KernelError,
1111
ILSPDocumentConnectionManager,
1212
CodeEditorManager,
13-
CodeEditorSettings,
1413
} from '@difizen/libro-jupyter';
1514
import {
1615
getOrigin,
@@ -25,6 +24,7 @@ import {
2524
} from '@difizen/mana-app';
2625
import { l10n } from '@difizen/mana-l10n';
2726
import { message } from 'antd';
27+
import { isUndefined } from 'lodash-es';
2828
import { forwardRef } from 'react';
2929

3030
import { Ribbon } from '@/components/ribbon';
@@ -36,15 +36,15 @@ import type { SecretNoteModel } from '../model';
3636

3737
const SecretNoteCodeCellComponent = forwardRef<HTMLDivElement>((props, ref) => {
3838
const instance = useInject<SecretNoteCodeCellView>(ViewInstance);
39-
const { allExecutionParty, executionParty } = instance;
39+
const { partyList, parties } = instance;
4040

4141
return (
4242
<div className={instance.className} ref={ref} tabIndex={10} onBlur={instance.blur}>
4343
<Ribbon
44-
items={allExecutionParty}
45-
value={executionParty}
44+
items={partyList.map((name) => ({ label: name, key: name }))}
45+
value={parties}
4646
onChange={(val) => {
47-
instance.changeExecutionParty(val);
47+
instance.onPartiesChange(val);
4848
}}
4949
>
5050
<CellEditorMemo />
@@ -54,6 +54,8 @@ const SecretNoteCodeCellComponent = forwardRef<HTMLDivElement>((props, ref) => {
5454
});
5555
SecretNoteCodeCellComponent.displayName = 'SecretNoteCodeCellComponent';
5656

57+
let lastParties: string[] = []; // store last parties for new cell
58+
5759
@transient()
5860
@view('secretnote-code-cell-view')
5961
export class SecretNoteCodeCellView extends JupyterCodeCellView {
@@ -63,13 +65,10 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
6365
view = SecretNoteCodeCellComponent;
6466

6567
@prop()
66-
executionParty: string[] = [];
68+
parties: string[] = [];
6769

68-
get allExecutionParty() {
69-
return this.serverManager.servers.map((server) => ({
70-
key: server.id,
71-
label: server.name,
72-
}));
70+
get partyList() {
71+
return this.serverManager.servers.map((server) => server.name);
7372
}
7473

7574
constructor(
@@ -80,89 +79,72 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
8079
@inject(SecretNoteKernelManager) kernelManager: SecretNoteKernelManager,
8180
@inject(ILSPDocumentConnectionManager) lsp: ILSPDocumentConnectionManager,
8281
@inject(CodeEditorManager) codeEditorManager: CodeEditorManager,
83-
@inject(CodeEditorSettings) codeEditorSettings: CodeEditorSettings,
8482
) {
85-
super(
86-
options,
87-
cellService,
88-
viewManager,
89-
lsp,
90-
codeEditorManager,
91-
codeEditorSettings,
92-
);
83+
super(options, cellService, viewManager, lsp, codeEditorManager);
9384
this.serverManager = serverManager;
9485
this.kernelManager = kernelManager;
95-
this.executionParty =
96-
this.getExecutionParty() || this.allExecutionParty.map((item) => item.key);
86+
this.parties = this.getInitializedParties();
9787
}
9888

99-
async run() {
89+
getUsableConnections() {
10090
const libroModel = this.parent.model as SecretNoteModel;
101-
const cellModel = this.model;
10291

10392
if (!libroModel) {
104-
return false;
93+
return [];
10594
}
10695

107-
let kernelConnections = getOrigin(libroModel.kernelConnections);
108-
109-
// 没有可用的 Kernel 连接
110-
if (kernelConnections.length === 0) {
111-
message.info(l10n.t('没有可用的 Kernel 连接'));
112-
return false;
113-
}
96+
const kernelConnections = getOrigin(libroModel.kernelConnections);
11497

115-
kernelConnections = kernelConnections.filter((connection) => {
98+
return kernelConnections.filter((connection) => {
99+
if (connection.isDisposed) {
100+
return false;
101+
}
116102
const server = this.kernelManager.getServerByKernelConnection(connection);
117103
return (
118-
server && server.status === 'running' && this.executionParty.includes(server.id)
104+
server && server.status === 'running' && this.parties.includes(server.name)
119105
);
120106
});
121-
if (kernelConnections.length === 0) {
122-
message.info(l10n.t('请选择一个执行节点'));
123-
return false;
124-
}
125-
if (kernelConnections.length !== this.executionParty.length) {
126-
message.info(l10n.t('有的 Kernel 连接不可用'));
127-
return false;
128-
}
107+
}
129108

130-
const hasDisposedConnection = kernelConnections.some((item) => {
131-
return item.isDisposed;
132-
});
133-
if (hasDisposedConnection) {
134-
message.error(l10n.t('有的 Kernel 连接已经被销毁'));
109+
async run() {
110+
const cellModel = this.model;
111+
const kernelConnections = this.getUsableConnections();
112+
113+
if (kernelConnections.length === 0) {
114+
message.info(l10n.t('No available node to execute'));
135115
return false;
136116
}
137117

138118
this.clearExecution();
139-
this.setExecutionStatus({ executing: true });
140-
this.setExecutionTime({ start: '', end: '', toExecute: new Date().toISOString() });
141-
this.setExecutionParty();
119+
this.updateExecutionStatus({ executing: true });
120+
this.updateExecutionTime({
121+
toExecute: new Date().toISOString(),
122+
});
123+
this.savePartiesToMeta();
142124

143125
try {
144126
const list: Promise<KernelMessage.IExecuteReplyMsg>[] = [];
145127
for (let i = 0, len = kernelConnections.length; i < len; i += 1) {
146128
const connection = kernelConnections[i];
147-
148-
const future = connection.requestExecute({
149-
code: cellModel.value,
150-
});
129+
const future = connection.requestExecute(
130+
{
131+
code: cellModel.value,
132+
},
133+
// Even after receiving a reply message, you can still receive other messages.
134+
false,
135+
);
151136

152137
future.onIOPub = (
153138
msg: KernelMessage.IIOPubMessage<KernelMessage.IOPubMessageType>,
154139
) => {
140+
if (msg.header.msg_type === 'execute_input') {
141+
this.updateExecutionStatus({ kernelExecuting: true });
142+
this.updateExecutionTime({ start: msg.header.date });
143+
}
155144
cellModel.msgChangeEmitter.fire({
156145
connection,
157146
msg,
158147
});
159-
if (
160-
cellModel.kernelExecuting === false &&
161-
msg.header.msg_type === 'execute_input'
162-
) {
163-
this.setExecutionStatus({ kernelExecuting: true });
164-
this.setExecutionTime({ start: msg.header.date });
165-
}
166148
};
167149

168150
future.onReply = (msg: KernelMessage.IExecuteReplyMsg) => {
@@ -176,8 +158,8 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
176158
}
177159

178160
const futureDoneList = await Promise.all(list);
179-
this.setExecutionStatus({ executing: false, kernelExecuting: false });
180-
this.setExecutionTime(this.parseMessageTime(futureDoneList));
161+
this.updateExecutionStatus({ executing: false, kernelExecuting: false });
162+
this.updateExecutionTime(this.parseMessageTime(futureDoneList));
181163

182164
const ok = futureDoneList.every((msg) => msg.content.status === 'ok');
183165
if (ok) {
@@ -197,27 +179,27 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
197179
}
198180
}
199181

200-
setExecutionStatus(status: { executing?: boolean; kernelExecuting?: boolean }) {
182+
updateExecutionStatus(status: { executing?: boolean; kernelExecuting?: boolean }) {
201183
const { executing, kernelExecuting } = status;
202-
if (executing !== undefined) {
184+
if (!isUndefined(executing)) {
203185
this.model.executing = executing;
204186
}
205-
if (kernelExecuting !== undefined) {
187+
if (!isUndefined(kernelExecuting)) {
206188
this.model.kernelExecuting = kernelExecuting;
207189
}
208190
}
209191

210-
setExecutionTime(times: { start?: string; end?: string; toExecute?: string }) {
192+
updateExecutionTime(times: { start?: string; end?: string; toExecute?: string }) {
211193
const meta = this.model.metadata.execution as ExecutionMeta;
212194
if (meta) {
213195
const { start, end, toExecute } = times;
214-
if (start !== undefined) {
196+
if (!isUndefined(start)) {
215197
meta['shell.execute_reply.started'] = start;
216198
}
217-
if (end !== undefined) {
199+
if (!isUndefined(end)) {
218200
meta['shell.execute_reply.end'] = end;
219201
}
220-
if (toExecute !== undefined) {
202+
if (!isUndefined(toExecute)) {
221203
meta.to_execute = toExecute;
222204
}
223205
}
@@ -240,29 +222,32 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
240222
return { start, end };
241223
}
242224

243-
changeExecutionParty(party: string[]) {
244-
this.executionParty = party;
245-
this.setExecutionParty(party);
225+
onPartiesChange(parties: string[]) {
226+
this.parties = parties;
227+
this.savePartiesToMeta(parties);
228+
lastParties = parties;
246229
}
247230

248-
getExecutionParty() {
231+
getInitializedParties() {
249232
const execution = this.model.metadata.execution as ExecutionMeta;
250-
if (execution && execution.executionParty) {
233+
if (execution && execution.parties) {
251234
try {
252-
const party: string[] = JSON.parse(execution.executionParty as string);
253-
return party.filter((p) =>
254-
this.allExecutionParty.some((item) => item.key === p),
255-
);
235+
const parties: string[] = JSON.parse(execution.parties as string);
236+
return parties.filter((p) => this.partyList.includes(p));
256237
} catch (e) {
257238
return [];
258239
}
240+
} else if (lastParties.length > 0) {
241+
// load parties from previous cell settings
242+
return lastParties;
259243
}
244+
return this.partyList;
260245
}
261246

262-
setExecutionParty(party: string[] = this.executionParty) {
247+
savePartiesToMeta(parties: string[] = this.parties) {
263248
const execution = this.model.metadata.execution as ExecutionMeta;
264249
if (execution) {
265-
execution.executionParty = JSON.stringify(party);
250+
execution.parties = JSON.stringify(parties);
266251
}
267252
}
268253
}

packages/secretnote/src/modules/editor/model.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,5 @@ export class SecretNoteModel extends LibroModel {
231231

232232
autoSave = debounce(() => {
233233
this.commandRegistry.executeCommand(DocumentCommands.Save.id);
234-
}, 1000);
234+
}, 500);
235235
}

packages/secretnote/src/modules/file/log-preview-contrib.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ const LogViewer = React.lazy(() => import('@/components/log-viewer'));
99
export class LogPreview implements FilePreviewContribution {
1010
type = 'log';
1111
render = (data: string) => {
12-
return <LogViewer code={data} />;
12+
return <LogViewer code={[data]} />;
1313
};
1414
}

packages/secretnote/src/modules/metrics/view.tsx

-67
Original file line numberDiff line numberDiff line change
@@ -2,80 +2,13 @@ import type { ModalItem, ModalItemProps } from '@difizen/mana-app';
22
import { useInject } from '@difizen/mana-app';
33
import { l10n } from '@difizen/mana-l10n';
44
import { Badge, Drawer } from 'antd';
5-
import { forwardRef } from 'react';
65

76
import { Smoothie } from '@/components/smoothie';
87

98
import { MetricsService } from './service';
109

1110
import './index.less';
1211

13-
const MetricsComponent1 = forwardRef<HTMLDivElement, ModalItemProps<void>>(
14-
function MetricsComponent1(props, ref) {
15-
const { visible, close } = props;
16-
const metricsService = useInject<MetricsService>(MetricsService);
17-
const { metrics } = metricsService;
18-
19-
const afterOpenChange = async (open: boolean) => {
20-
if (open) {
21-
metricsService.enable();
22-
}
23-
};
24-
25-
const onClose = () => {
26-
metricsService.disable();
27-
close();
28-
};
29-
30-
return (
31-
<div ref={ref}>
32-
<Drawer
33-
placement="right"
34-
onClose={() => onClose()}
35-
width={360}
36-
open={visible}
37-
mask={false}
38-
afterOpenChange={afterOpenChange}
39-
destroyOnClose={true}
40-
title={l10n.t('资源消耗')}
41-
>
42-
<div className="secretnote-kernel-status">
43-
{metrics.map((item) => (
44-
<div key={item.kernel.id} className="kernel-status-item">
45-
<div className="server-name">{item.server.name}:</div>
46-
<div className="metrics-item">
47-
<span className="label">{l10n.t('名称')}:</span>
48-
<span>{item.kernel.name}</span>
49-
</div>
50-
<div className="metrics-item">
51-
<span className="label">{l10n.t('状态')}:</span>
52-
<Badge
53-
color={item.kernel.statusColor}
54-
text={item.kernel.statusText}
55-
/>
56-
</div>
57-
<div className="metrics-item">
58-
<span className="label">PID:</span>
59-
<span>{item.kernel.pid}</span>
60-
</div>
61-
<div className="metrics-item">
62-
<span className="label">CPU:</span>
63-
<span>{item.kernel.cpuText}</span>
64-
</div>
65-
<Smoothie data={{ time: Date.now(), data: item.kernel.cpu }} />
66-
<div className="metrics-item">
67-
<span className="label">RAM:</span>
68-
<span>{item.kernel.memoryText}</span>
69-
</div>
70-
<Smoothie data={{ time: Date.now(), data: item.kernel.memory }} />
71-
</div>
72-
))}
73-
</div>
74-
</Drawer>
75-
</div>
76-
);
77-
},
78-
);
7912
const MetricsComponent = (props: ModalItemProps<void>) => {
8013
const { visible, close } = props;
8114
const metricsService = useInject<MetricsService>(MetricsService);

0 commit comments

Comments
 (0)