@difizen/libro-jupyter 0.1.0 → 0.1.2

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.
Files changed (136) hide show
  1. package/es/add-between-cell/add-between-cell.d.ts.map +1 -1
  2. package/es/add-between-cell/add-between-cell.js +7 -7
  3. package/es/add-between-cell/index.less +6 -0
  4. package/es/cell/jupyter-code-cell-model.d.ts +2 -2
  5. package/es/cell/jupyter-code-cell-model.d.ts.map +1 -1
  6. package/es/cell/jupyter-code-cell-model.js +7 -3
  7. package/es/cell/jupyter-code-cell-view.d.ts +9 -4
  8. package/es/cell/jupyter-code-cell-view.d.ts.map +1 -1
  9. package/es/cell/jupyter-code-cell-view.js +137 -100
  10. package/es/command/command-contribution.d.ts.map +1 -1
  11. package/es/command/command-contribution.js +9 -9
  12. package/es/components/cell-execution-tip.d.ts.map +1 -1
  13. package/es/components/cell-execution-tip.js +14 -1
  14. package/es/components/cell-input-bottom-blank.d.ts.map +1 -1
  15. package/es/components/cell-input-bottom-blank.js +4 -4
  16. package/es/components/icons.d.ts +5 -0
  17. package/es/components/icons.d.ts.map +1 -0
  18. package/es/components/index.less +1 -0
  19. package/es/config/config-contribution.d.ts +2 -2
  20. package/es/config/config-contribution.d.ts.map +1 -1
  21. package/es/config/config-contribution.js +7 -7
  22. package/es/config/config.d.ts +8 -0
  23. package/es/config/config.d.ts.map +1 -0
  24. package/es/config/config.js +15 -1
  25. package/es/config/index.d.ts +1 -0
  26. package/es/config/index.d.ts.map +1 -1
  27. package/es/config/index.js +2 -1
  28. package/es/file/file-command.d.ts +1 -0
  29. package/es/file/file-command.d.ts.map +1 -1
  30. package/es/file/file-command.js +20 -8
  31. package/es/file/file-create-modal.d.ts +5 -1
  32. package/es/file/file-create-modal.d.ts.map +1 -1
  33. package/es/file/file-create-modal.js +178 -56
  34. package/es/file/file-createdir-modal-contribution.d.ts +1 -1
  35. package/es/file/file-createdir-modal.d.ts +4 -3
  36. package/es/file/file-createdir-modal.d.ts.map +1 -1
  37. package/es/file/file-createdir-modal.js +122 -59
  38. package/es/file/file-icon.d.ts +11 -0
  39. package/es/file/file-icon.d.ts.map +1 -0
  40. package/es/file/file-icon.js +475 -0
  41. package/es/file/file-name-alias.d.ts +7 -0
  42. package/es/file/file-name-alias.d.ts.map +1 -0
  43. package/es/file/file-protocol.d.ts +14 -0
  44. package/es/file/file-protocol.d.ts.map +1 -0
  45. package/es/file/file-rename-modal.d.ts +1 -0
  46. package/es/file/file-rename-modal.d.ts.map +1 -1
  47. package/es/file/file-rename-modal.js +100 -25
  48. package/es/file/file-tree-label-provider.d.ts +13 -0
  49. package/es/file/file-tree-label-provider.d.ts.map +1 -0
  50. package/es/file/index.d.ts +3 -0
  51. package/es/file/index.d.ts.map +1 -1
  52. package/es/file/index.js +4 -1
  53. package/es/file/index.less +98 -0
  54. package/es/file/navigatable-view.d.ts +13 -6
  55. package/es/file/navigatable-view.d.ts.map +1 -1
  56. package/es/file/navigatable-view.js +53 -7
  57. package/es/file/open-handler-contribution.js +1 -1
  58. package/es/file/utils.d.ts +2 -0
  59. package/es/file/utils.d.ts.map +1 -0
  60. package/es/index.d.ts +17 -15
  61. package/es/index.d.ts.map +1 -1
  62. package/es/index.js +17 -15
  63. package/es/keybind-instructions/index.less +2 -2
  64. package/es/keybind-instructions/keybind-instructions-contribution.js +2 -2
  65. package/es/keybind-instructions/keybind-instructions-items.d.ts +14 -0
  66. package/es/keybind-instructions/keybind-instructions-items.d.ts.map +1 -0
  67. package/es/libro-jupyter-model.d.ts +8 -4
  68. package/es/libro-jupyter-model.d.ts.map +1 -1
  69. package/es/libro-jupyter-model.js +24 -17
  70. package/es/libro-jupyter-protocol.d.ts +4 -0
  71. package/es/libro-jupyter-protocol.d.ts.map +1 -1
  72. package/es/libro-jupyter-protocol.js +2 -1
  73. package/es/libro-jupyter-server-launch-manager.d.ts +3 -1
  74. package/es/libro-jupyter-server-launch-manager.d.ts.map +1 -1
  75. package/es/libro-jupyter-server-launch-manager.js +9 -2
  76. package/es/libro-jupyter-view.d.ts +2 -1
  77. package/es/libro-jupyter-view.d.ts.map +1 -1
  78. package/es/libro-jupyter-view.js +4 -2
  79. package/es/module.d.ts.map +1 -1
  80. package/es/module.js +12 -10
  81. package/es/output/libro-jupyter-outputarea.d.ts +3 -0
  82. package/es/output/libro-jupyter-outputarea.d.ts.map +1 -1
  83. package/es/output/libro-jupyter-outputarea.js +49 -4
  84. package/es/rendermime/index.less +12 -1
  85. package/es/rendermime/plotly-renderers.d.ts +15 -14
  86. package/es/rendermime/plotly-renderers.d.ts.map +1 -1
  87. package/es/rendermime/plotly-renderers.js +1 -3
  88. package/es/theme/color-registry.d.ts +6 -0
  89. package/es/theme/color-registry.d.ts.map +1 -0
  90. package/es/theme/index.d.ts +2 -0
  91. package/es/theme/index.d.ts.map +1 -0
  92. package/es/toolbar/kernel-selector-dropdown.d.ts.map +1 -1
  93. package/es/toolbar/kernel-selector-dropdown.js +2 -6
  94. package/es/typings/index.d.ts +7 -2
  95. package/package.json +16 -14
  96. package/src/add-between-cell/add-between-cell.tsx +17 -8
  97. package/src/add-between-cell/index.less +6 -0
  98. package/src/cell/jupyter-code-cell-model.ts +6 -4
  99. package/src/cell/jupyter-code-cell-view.tsx +81 -48
  100. package/src/command/command-contribution.ts +13 -9
  101. package/src/components/cell-execution-tip.tsx +8 -2
  102. package/src/components/cell-input-bottom-blank.tsx +10 -5
  103. package/src/components/index.less +1 -0
  104. package/src/config/config-contribution.ts +3 -3
  105. package/src/config/config.ts +17 -2
  106. package/src/config/index.ts +1 -0
  107. package/src/file/file-command.tsx +16 -8
  108. package/src/file/file-create-modal.tsx +129 -26
  109. package/src/file/file-createdir-modal.tsx +64 -32
  110. package/src/file/file-icon.tsx +502 -0
  111. package/src/file/file-rename-modal.tsx +55 -16
  112. package/src/file/index.less +98 -0
  113. package/src/file/index.ts +3 -0
  114. package/src/file/navigatable-view.tsx +60 -5
  115. package/src/file/open-handler-contribution.ts +1 -1
  116. package/src/index.spec.ts +1 -5
  117. package/src/index.ts +17 -16
  118. package/src/keybind-instructions/index.less +2 -2
  119. package/src/keybind-instructions/keybind-instructions-contribution.ts +2 -2
  120. package/src/libro-jupyter-model.ts +34 -20
  121. package/src/libro-jupyter-protocol.ts +5 -0
  122. package/src/libro-jupyter-server-launch-manager.ts +11 -2
  123. package/src/libro-jupyter-view.tsx +4 -1
  124. package/src/module.ts +23 -15
  125. package/src/output/libro-jupyter-outputarea.tsx +31 -3
  126. package/src/rendermime/index.less +12 -1
  127. package/src/rendermime/plotly-render.tsx +1 -1
  128. package/src/rendermime/plotly-renderers.ts +15 -17
  129. package/src/toolbar/kernel-selector-dropdown.tsx +2 -6
  130. package/src/typings/index.d.ts +7 -2
  131. package/es/configuration/index.js +0 -2
  132. package/es/configuration/libro-configuration-contribution.js +0 -24
  133. package/es/configuration/libro-configuration.js +0 -12
  134. package/src/configuration/index.ts +0 -2
  135. package/src/configuration/libro-configuration-contribution.ts +0 -11
  136. package/src/configuration/libro-configuration.ts +0 -14
@@ -11,7 +11,6 @@ import { ViewManager } from '@difizen/mana-app';
11
11
  import {
12
12
  CommandContribution,
13
13
  FileStatNode,
14
- FileTreeCommand,
15
14
  inject,
16
15
  MenuContribution,
17
16
  ModalService,
@@ -28,6 +27,7 @@ import { FileRenameModal } from './file-rename-modal.js';
28
27
  import { JupyterFileService } from './file-service.js';
29
28
  import { FileView } from './file-view/index.js';
30
29
  import { copy2clipboard } from './utils.js';
30
+ import './index.less';
31
31
 
32
32
  const FileCommands = {
33
33
  OPEN_FILE: {
@@ -70,6 +70,10 @@ const FileCommands = {
70
70
  id: 'fileTree.command.refresh',
71
71
  label: '刷新',
72
72
  },
73
+ REMOVE: {
74
+ id: 'fileTree.command.remove',
75
+ label: '删除',
76
+ },
73
77
  };
74
78
  export const FileTreeContextMenuPath: MenuPath = ['file-tree-context-menu'];
75
79
 
@@ -176,13 +180,17 @@ export class FileCommandContribution
176
180
  return FileStatNode.is(node) && node.fileStat.isFile;
177
181
  },
178
182
  });
179
- command.registerHandler(FileTreeCommand.REMOVE.id, {
183
+ command.registerHandler(FileCommands.REMOVE.id, {
180
184
  execute: (node) => {
181
185
  if (FileStatNode.is(node)) {
182
186
  const filePath = node.uri.path.toString();
183
187
  Modal.confirm({
184
- title: '确认删除一下文件或文件夹?',
185
- content: filePath,
188
+ width: 424,
189
+ title: '确认要删除这个文件/文件夹吗?',
190
+ content: `请确认是否删除文件 ${filePath} ,删除后将不可恢复,请谨慎操作。`,
191
+ wrapClassName: 'libro-remove-file-modal',
192
+ cancelText: '取消',
193
+ okText: '确定',
186
194
  onOk: async () => {
187
195
  try {
188
196
  await this.fileService.delete(node.uri);
@@ -252,7 +260,7 @@ export class FileCommandContribution
252
260
  });
253
261
  command.registerCommand(FileCommands.CREATE_FILE, {
254
262
  execute: async (data) => {
255
- let path = '/workspace';
263
+ let path = this.fileView.model.location?.path.toString() || '/';
256
264
  if (FileStatNode.is(data)) {
257
265
  path = data.fileStat.isDirectory
258
266
  ? data.uri.path.toString()
@@ -265,7 +273,7 @@ export class FileCommandContribution
265
273
  });
266
274
  command.registerCommand(FileCommands.CREATE_DIR, {
267
275
  execute: async (data) => {
268
- let path = '/workspace';
276
+ let path = this.fileView.model.location?.path.toString() || '/';
269
277
  if (FileStatNode.is(data)) {
270
278
  path = data.fileStat.isDirectory
271
279
  ? data.uri.path.toString()
@@ -279,7 +287,7 @@ export class FileCommandContribution
279
287
 
280
288
  command.registerCommand(FileCommands.COPY_PATH, {
281
289
  execute: async (data) => {
282
- let path = '/workspace';
290
+ let path = this.fileView.model.location?.path.toString() || '/';
283
291
  if (FileStatNode.is(data)) {
284
292
  path = data.uri.path.toString();
285
293
  }
@@ -291,7 +299,7 @@ export class FileCommandContribution
291
299
  execute: async (data) => {
292
300
  let relative = '';
293
301
  if (FileStatNode.is(data)) {
294
- relative = pathUtil.relative('/workspace', data.uri.path.toString());
302
+ relative = pathUtil.relative('/', data.uri.path.toString());
295
303
  }
296
304
  copy2clipboard(relative);
297
305
  },
@@ -1,15 +1,26 @@
1
- import type { ModalItem, ModalItemProps } from '@difizen/mana-app';
1
+ import type { ModalItemProps, ModalItem } from '@difizen/mana-app';
2
2
  import { URI, useInject, ViewManager } from '@difizen/mana-app';
3
+ import { Col, Form, message, Row, Input, Modal } from 'antd';
3
4
  import type { InputRef } from 'antd';
4
- import { Input, Modal } from 'antd';
5
5
  import { useEffect, useRef, useState } from 'react';
6
+ import './index.less';
6
7
 
7
- import { FileView, JupyterFileService } from './index.js';
8
+ import {
9
+ FileView,
10
+ JSONIcon,
11
+ JupyterFileService,
12
+ MoreIcon,
13
+ NotebookIcon,
14
+ PythonIcon,
15
+ } from './index.js';
8
16
 
9
17
  export interface ModalItemType {
10
18
  path: string;
19
+ fileType?: FileType;
11
20
  }
12
21
 
22
+ type FileType = '.ipynb' | '.py' | '.json' | '.sql' | undefined;
23
+
13
24
  export const FileCreateModalComponent: React.FC<ModalItemProps<ModalItemType>> = ({
14
25
  visible,
15
26
  close,
@@ -17,9 +28,35 @@ export const FileCreateModalComponent: React.FC<ModalItemProps<ModalItemType>> =
17
28
  }: ModalItemProps<ModalItemType>) => {
18
29
  const fileService = useInject(JupyterFileService);
19
30
  const viewManager = useInject(ViewManager);
20
- const [newFileName, setNewFileName] = useState('');
31
+ const [fileType, setFileType] = useState<FileType>(data.fileType);
21
32
  const [fileView, setFileView] = useState<FileView>();
22
33
  const inputRef = useRef<InputRef>(null);
34
+ const [form] = Form.useForm();
35
+
36
+ const onFinish = async (values: { fileName: string }) => {
37
+ await form.validateFields();
38
+ close();
39
+ try {
40
+ await fileService.newFile(values.fileName + fileType || '', new URI(data.path));
41
+ if (fileView) {
42
+ fileView.model.refresh();
43
+ }
44
+ } catch {
45
+ message.error('新建文件失败');
46
+ }
47
+ };
48
+
49
+ const validateFileName = async (rule: any, value: string, callback: any) => {
50
+ if (!value || !value.length) {
51
+ throw new Error('请输入文件名');
52
+ } else {
53
+ const targetURI = new URI(data.path + value + (fileType || ''));
54
+ const fileRes = await fileService.resolve(targetURI);
55
+ if (fileRes.isFile) {
56
+ throw new Error('文件名称已存在,请重新输入');
57
+ }
58
+ }
59
+ };
23
60
 
24
61
  useEffect(() => {
25
62
  viewManager
@@ -38,31 +75,97 @@ export const FileCreateModalComponent: React.FC<ModalItemProps<ModalItemType>> =
38
75
  title="新建文件"
39
76
  open={visible}
40
77
  onCancel={close}
41
- onOk={async () => {
42
- await fileService.newFile(newFileName, new URI(data.path));
43
- if (fileView) {
44
- fileView.model.refresh();
45
- }
46
- close();
78
+ width={788}
79
+ cancelText="取消"
80
+ okText="确定"
81
+ onOk={() => {
82
+ form.submit();
47
83
  }}
48
84
  keyboard={true}
85
+ wrapClassName="libro-create-file-modal"
49
86
  >
50
- <Input
51
- value={newFileName}
52
- onChange={(e) => {
53
- setNewFileName(e.target.value);
54
- }}
55
- ref={inputRef}
56
- onKeyDown={async (e) => {
57
- if (e.keyCode === 13) {
58
- await fileService.newFile(newFileName, new URI(data.path));
59
- if (fileView) {
60
- fileView.model.refresh();
61
- }
62
- close();
63
- }
64
- }}
65
- />
87
+ <div className="libro-create-file-path-container">
88
+ <div className="libro-create-file-des">创建位置:</div>
89
+ <span className="libro-create-file-path">{data.path}</span>
90
+ </div>
91
+ <div className="libro-create-file-des">文件类型:</div>
92
+ <Row>
93
+ <Col
94
+ className="gutter-row"
95
+ style={{ paddingLeft: 'unset', paddingRight: '16px' }}
96
+ >
97
+ <div
98
+ className={`libro-create-file-type ${
99
+ fileType === '.ipynb' ? 'active' : ''
100
+ }`}
101
+ onClick={() => {
102
+ setFileType('.ipynb');
103
+ }}
104
+ >
105
+ <NotebookIcon />
106
+ <span className="libro-create-file-type-text">Notebook</span>
107
+ </div>
108
+ </Col>
109
+ <Col
110
+ className="gutter-row"
111
+ style={{ paddingLeft: 'unset', paddingRight: '16px' }}
112
+ >
113
+ <div
114
+ className={`libro-create-file-type ${fileType === '.py' ? 'active' : ''}`}
115
+ onClick={() => {
116
+ setFileType('.py');
117
+ }}
118
+ >
119
+ <PythonIcon />
120
+ <span className="libro-create-file-type-text">Python</span>
121
+ </div>
122
+ </Col>
123
+ <Col
124
+ className="gutter-row"
125
+ style={{ paddingLeft: 'unset', paddingRight: '16px' }}
126
+ >
127
+ <div
128
+ className={`libro-create-file-type ${fileType === '.json' ? 'active' : ''}`}
129
+ onClick={() => {
130
+ setFileType('.json');
131
+ }}
132
+ >
133
+ <JSONIcon />
134
+ <span className="libro-create-file-type-text">JSON</span>
135
+ </div>
136
+ </Col>
137
+ <Col
138
+ className="gutter-row"
139
+ style={{ paddingLeft: 'unset', paddingRight: '16px' }}
140
+ >
141
+ <div
142
+ className={`libro-create-file-type ${
143
+ fileType === undefined ? 'active' : ''
144
+ }`}
145
+ onClick={() => {
146
+ setFileType(undefined);
147
+ }}
148
+ >
149
+ <MoreIcon />
150
+ <span className="libro-create-file-type-text">其他</span>
151
+ </div>
152
+ </Col>
153
+ </Row>
154
+ <Form
155
+ layout="vertical"
156
+ autoComplete="off"
157
+ form={form}
158
+ onFinish={onFinish}
159
+ className="libro-create-file-form"
160
+ >
161
+ <Form.Item
162
+ name="fileName"
163
+ label="文件名称"
164
+ rules={[{ required: true, validator: validateFileName }]}
165
+ >
166
+ <Input addonAfter={fileType || ''} />
167
+ </Form.Item>
168
+ </Form>
66
169
  </Modal>
67
170
  );
68
171
  };
@@ -2,28 +2,52 @@ import type { ModalItem, ModalItemProps } from '@difizen/mana-app';
2
2
  import { URI } from '@difizen/mana-app';
3
3
  import { ViewManager } from '@difizen/mana-app';
4
4
  import { useInject } from '@difizen/mana-app';
5
+ import { Form, message, Input, Modal } from 'antd';
5
6
  import type { InputRef } from 'antd';
6
- import { Input } from 'antd';
7
- import { Modal } from 'antd';
8
7
  import { useEffect, useRef, useState } from 'react';
9
8
 
10
9
  import { JupyterFileService } from './file-service.js';
11
10
  import { FileView } from './file-view/index.js';
11
+ import './index.less';
12
12
 
13
- export interface ModalItemType {
13
+ export interface FileDirCreateModalItemType {
14
14
  path: string;
15
15
  }
16
16
 
17
- export const FileCreateDirModalComponent: React.FC<ModalItemProps<ModalItemType>> = ({
18
- visible,
19
- close,
20
- data,
21
- }: ModalItemProps<ModalItemType>) => {
17
+ export const FileCreateDirModalComponent: React.FC<
18
+ ModalItemProps<FileDirCreateModalItemType>
19
+ > = ({ visible, close, data }: ModalItemProps<FileDirCreateModalItemType>) => {
22
20
  const fileService = useInject(JupyterFileService);
23
21
  const viewManager = useInject(ViewManager);
24
22
  const inputRef = useRef<InputRef>(null);
25
- const [dirName, setDirName] = useState('');
26
23
  const [fileView, setFileView] = useState<FileView>();
24
+ const [form] = Form.useForm();
25
+
26
+ const onFinish = async (values: { dirName: string }) => {
27
+ await form.validateFields();
28
+ close();
29
+ try {
30
+ await fileService.newFileDir(values.dirName, new URI(data.path));
31
+ if (fileView) {
32
+ fileView.model.refresh();
33
+ }
34
+ } catch {
35
+ message.error('新建文件夹失败');
36
+ }
37
+ };
38
+
39
+ const validateDirName = async (rule: any, value: string, callback: any) => {
40
+ if (!value || !value.length) {
41
+ throw new Error('请输入文件夹名');
42
+ } else {
43
+ const targetURI = new URI(data.path + value);
44
+ const fileRes = await fileService.resolve(targetURI);
45
+ if (fileRes.isDirectory) {
46
+ throw new Error('文件夹名称已存在,请重新输入');
47
+ }
48
+ }
49
+ };
50
+
27
51
  useEffect(() => {
28
52
  viewManager
29
53
  .getOrCreateView(FileView)
@@ -41,36 +65,44 @@ export const FileCreateDirModalComponent: React.FC<ModalItemProps<ModalItemType>
41
65
  title="新建文件夹"
42
66
  open={visible}
43
67
  onCancel={close}
44
- onOk={async () => {
45
- await fileService.newFileDir(dirName, new URI(data.path));
46
- if (fileView) {
47
- fileView.model.refresh();
48
- }
49
- close();
68
+ cancelText="取消"
69
+ okText="确定"
70
+ onOk={() => {
71
+ form.submit();
50
72
  }}
51
73
  keyboard={true}
74
+ wrapClassName="libro-create-dir-modal"
75
+ width={524}
52
76
  >
53
- <Input
54
- value={dirName}
55
- onChange={(e) => {
56
- setDirName(e.target.value);
57
- }}
58
- ref={inputRef}
59
- onKeyDown={async (e) => {
60
- if (e.keyCode === 13) {
61
- await fileService.newFileDir(dirName, new URI(data.path));
62
- if (fileView) {
63
- fileView.model.refresh();
64
- }
65
- close();
66
- }
67
- }}
68
- />
77
+ <div className="libro-create-file-des">创建位置:</div>
78
+ <span className="libro-create-file-path">{data.path}</span>
79
+ <Form
80
+ layout="vertical"
81
+ autoComplete="off"
82
+ form={form}
83
+ onFinish={onFinish}
84
+ className="libro-create-dir-file-form"
85
+ >
86
+ <Form.Item
87
+ name="dirName"
88
+ label="文件夹名称"
89
+ rules={[{ required: true, validator: validateDirName }]}
90
+ >
91
+ <Input
92
+ ref={inputRef}
93
+ onKeyDown={async (e) => {
94
+ if (e.keyCode === 13) {
95
+ form.submit();
96
+ }
97
+ }}
98
+ />
99
+ </Form.Item>
100
+ </Form>
69
101
  </Modal>
70
102
  );
71
103
  };
72
104
 
73
- export const FileDirCreateModal: ModalItem<ModalItemType> = {
105
+ export const FileDirCreateModal: ModalItem<FileDirCreateModalItemType> = {
74
106
  id: 'file.createdir.modal',
75
107
  component: FileCreateDirModalComponent,
76
108
  };