miqro 7.2.7 → 7.2.8

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 (94) hide show
  1. package/build/esm/editor/auth.d.ts +6 -0
  2. package/build/esm/editor/auth.js +42 -0
  3. package/build/esm/editor/common/constants.d.ts +4 -0
  4. package/build/esm/editor/common/constants.js +20 -0
  5. package/build/esm/editor/common/constants.server.d.ts +2 -0
  6. package/build/esm/editor/common/constants.server.js +4 -0
  7. package/build/esm/editor/common/editor-index.d.ts +2 -0
  8. package/build/esm/editor/common/editor-index.js +14 -0
  9. package/build/esm/editor/common/html-encode.d.ts +1 -0
  10. package/build/esm/editor/common/html-encode.js +14 -0
  11. package/build/esm/editor/common/log-socket.d.ts +15 -0
  12. package/build/esm/editor/common/log-socket.js +71 -0
  13. package/build/esm/editor/common/templates.d.ts +11 -0
  14. package/build/esm/editor/common/templates.js +477 -0
  15. package/build/esm/editor/components/api-preview.d.ts +11 -0
  16. package/build/esm/editor/components/api-preview.js +92 -0
  17. package/build/esm/editor/components/editor.d.ts +16 -0
  18. package/build/esm/editor/components/editor.js +367 -0
  19. package/build/esm/editor/components/file-browser.d.ts +37 -0
  20. package/build/esm/editor/components/file-browser.js +127 -0
  21. package/build/esm/editor/components/file-editor-toolbar.d.ts +22 -0
  22. package/build/esm/editor/components/file-editor-toolbar.js +95 -0
  23. package/build/esm/editor/components/file-editor.d.ts +32 -0
  24. package/build/esm/editor/components/file-editor.js +61 -0
  25. package/build/esm/editor/components/filter-query.d.ts +1 -0
  26. package/build/esm/editor/components/filter-query.js +23 -0
  27. package/build/esm/editor/components/highlight-text-area.d.ts +11 -0
  28. package/build/esm/editor/components/highlight-text-area.js +127 -0
  29. package/build/esm/editor/components/log-viewer.d.ts +6 -0
  30. package/build/esm/editor/components/log-viewer.js +71 -0
  31. package/build/esm/editor/components/new-file.d.ts +10 -0
  32. package/build/esm/editor/components/new-file.js +119 -0
  33. package/build/esm/editor/components/scroll-query.d.ts +7 -0
  34. package/build/esm/editor/components/scroll-query.js +22 -0
  35. package/build/esm/editor/components/start-page.d.ts +13 -0
  36. package/build/esm/editor/components/start-page.js +32 -0
  37. package/build/esm/editor/http/admin/editor/api/fs/delete.api.d.ts +4 -0
  38. package/build/esm/editor/http/admin/editor/api/fs/delete.api.js +30 -0
  39. package/build/esm/editor/http/admin/editor/api/fs/read.api.d.ts +7 -0
  40. package/build/esm/editor/http/admin/editor/api/fs/read.api.js +50 -0
  41. package/build/esm/editor/http/admin/editor/api/fs/rename.api.d.ts +7 -0
  42. package/build/esm/editor/http/admin/editor/api/fs/rename.api.js +40 -0
  43. package/build/esm/editor/http/admin/editor/api/fs/scan.api.d.ts +26 -0
  44. package/build/esm/editor/http/admin/editor/api/fs/scan.api.js +150 -0
  45. package/build/esm/editor/http/admin/editor/api/fs/write.api.d.ts +3 -0
  46. package/build/esm/editor/http/admin/editor/api/fs/write.api.js +39 -0
  47. package/build/esm/editor/http/admin/editor/api/server/reload.api.d.ts +10 -0
  48. package/build/esm/editor/http/admin/editor/api/server/reload.api.js +46 -0
  49. package/build/esm/editor/http/admin/editor/api/server/restart.api.d.ts +10 -0
  50. package/build/esm/editor/http/admin/editor/api/server/restart.api.js +46 -0
  51. package/build/esm/editor/http/admin/editor/editor.d.ts +1 -0
  52. package/build/esm/editor/http/admin/editor/editor.js +8 -0
  53. package/build/esm/editor/http/admin/editor/index.api.d.ts +3 -0
  54. package/build/esm/editor/http/admin/editor/index.api.js +23 -0
  55. package/build/esm/editor/server.d.ts +3 -0
  56. package/build/esm/editor/server.js +49 -0
  57. package/build/esm/editor/ws.d.ts +3 -0
  58. package/build/esm/editor/ws.js +12 -0
  59. package/build/esm/src/common/admin-interface.d.ts +36 -0
  60. package/build/esm/src/common/admin-interface.js +44 -0
  61. package/build/esm/src/services/app.d.ts +1 -1
  62. package/build/esm/src/services/editor.d.ts +1 -1
  63. package/build/esm/src/services/utils/admin-interface.d.ts +1 -1
  64. package/build/esm/src/services/utils/websocketmanager.d.ts +1 -1
  65. package/editor/auth.ts +52 -0
  66. package/editor/common/constants.server.ts +5 -0
  67. package/editor/common/constants.ts +21 -0
  68. package/editor/common/editor-index.tsx +17 -0
  69. package/editor/common/html-encode.ts +14 -0
  70. package/editor/common/log-socket.tsx +87 -0
  71. package/editor/common/templates.ts +481 -0
  72. package/editor/components/api-preview.tsx +118 -0
  73. package/editor/components/editor.tsx +496 -0
  74. package/editor/components/file-browser.tsx +311 -0
  75. package/editor/components/file-editor-toolbar.tsx +194 -0
  76. package/editor/components/file-editor.tsx +125 -0
  77. package/editor/components/filter-query.tsx +26 -0
  78. package/editor/components/highlight-text-area.tsx +148 -0
  79. package/editor/components/log-viewer.tsx +113 -0
  80. package/editor/components/new-file.tsx +172 -0
  81. package/editor/components/scroll-query.tsx +25 -0
  82. package/editor/components/start-page.tsx +52 -0
  83. package/editor/http/admin/editor/api/fs/delete.api.tsx +32 -0
  84. package/editor/http/admin/editor/api/fs/read.api.tsx +55 -0
  85. package/editor/http/admin/editor/api/fs/rename.api.tsx +41 -0
  86. package/editor/http/admin/editor/api/fs/scan.api.tsx +181 -0
  87. package/editor/http/admin/editor/api/fs/write.api.tsx +41 -0
  88. package/editor/http/admin/editor/api/server/reload.api.ts +53 -0
  89. package/editor/http/admin/editor/api/server/restart.api.tsx +52 -0
  90. package/editor/http/admin/editor/editor.tsx +10 -0
  91. package/editor/http/admin/editor/index.api.tsx +43 -0
  92. package/editor/server.ts +57 -0
  93. package/editor/ws.ts +17 -0
  94. package/package.json +1 -1
@@ -0,0 +1,311 @@
1
+ import * as jsx from "@miqro/jsx";
2
+ import JSX from "@miqro/jsx";
3
+
4
+ interface FileBrowserFile {
5
+ filePath: string;
6
+ fileName: string;
7
+ language: string;
8
+ content?: string;
9
+ dirs: string[];
10
+ }
11
+
12
+ interface FileBrowserProps {
13
+ filter: string;
14
+ migrations: string[];
15
+ current: string;
16
+ isDirCollapsed: (dir: string) => boolean;
17
+ toggleCollapseDir: (dir: string) => void;
18
+ saveAll: () => void;
19
+ isOpen: (file: string) => boolean;
20
+ openFile: (file: string) => void;
21
+ setfilter: (newFilter) => void;
22
+ showNewFile: () => void;
23
+ scanFiles: () => void;
24
+ closeAll: () => void;
25
+ closeFile: (file: string) => void;
26
+ reloadServer: () => void;
27
+ hasFileContentChanged: (file: string) => boolean;
28
+ hasErrors: (file: string) => boolean;
29
+ files: FileBrowserFile[];
30
+ opened: {
31
+ fileName: string;
32
+ filePath: string;
33
+ }[];
34
+ isPanelVisible: (panel: string) => boolean;
35
+ togglePanel: (panel: string) => void;
36
+ disableLog?: boolean; disablePreview?: boolean; disableReload?: boolean;
37
+ }
38
+
39
+ export function FileBrowser(props: FileBrowserProps) {
40
+ return <div class="file-browser" style={`${!props.isPanelVisible("left") ? "display: none;" : ""}`}>
41
+ <div class="file-browser-toolbar">
42
+ <div class="row">
43
+ <button
44
+ class="file-editor-button btn"
45
+ style={`width: 10%;${props.disableReload ? "width: 30%;" : ""}`}
46
+ onclick={ev => {
47
+ ev.preventDefault();
48
+ props.togglePanel("left");
49
+ }}>{"<<"}</button>
50
+ {props.disableLog ? <></> :
51
+ <button
52
+ id="log-btn"
53
+ class="file-editor-button btn"
54
+ style={`width: 30%;${props.disableLog ? "display: none;" : ""}`}
55
+ onclick={ev => {
56
+ ev.preventDefault();
57
+ props.togglePanel("bottom");
58
+ }}>log</button>}
59
+ {props.disableReload ? <></> :
60
+ <button
61
+ id="scan-btn"
62
+ class="file-editor-button btn active"
63
+ style={`width: 30%;${props.disableReload ? "display: none;" : ""}`}
64
+ onclick={ev => {
65
+ ev.preventDefault();
66
+ props.scanFiles();
67
+ }}>scan</button>}
68
+ {props.disableReload ? <></> :
69
+ <button
70
+ id="reload-btn"
71
+ class="file-editor-button btn warning"
72
+ style={`width: 30%;${props.disableReload ? "display: none;" : ""}`}
73
+ onclick={ev => {
74
+ ev.preventDefault();
75
+ props.reloadServer();
76
+ }}>reload</button>}
77
+ </div>
78
+ <div class="row">
79
+ <input
80
+ type="text"
81
+ style="width: 100%;"
82
+ value={props.filter}
83
+ oninput={ev => {
84
+ ev.preventDefault();
85
+ const text = ev.target.value;
86
+ props.setfilter(text);
87
+ }}
88
+ placeholder={"..filter.."} />
89
+ </div>
90
+ <div class="row">
91
+ {props.disablePreview ? <></> :
92
+ <button
93
+ id="preview-btn"
94
+ class="file-editor-button btn"
95
+ style={`width: 30%;${props.disablePreview ? "display: none;" : ""}`}
96
+ onclick={ev => {
97
+ ev.preventDefault();
98
+ props.togglePanel("right");
99
+ }}>preview</button>}
100
+ <button
101
+ id="new-btn"
102
+ class="file-editor-button btn info"
103
+ style="width: 20%;"
104
+ onclick={ev => {
105
+ ev.preventDefault();
106
+ props.showNewFile();
107
+ }}>new</button>
108
+ {props.disableReload ? <></> :
109
+ <button
110
+ id="scan-btn"
111
+ class="file-editor-button btn active"
112
+ style={`width: 30%;${!props.disableReload ? "display: none;" : ""}`}
113
+ onclick={ev => {
114
+ ev.preventDefault();
115
+ props.scanFiles();
116
+ }}>scan</button>}
117
+ <button
118
+ id="saveall-btn"
119
+ class="file-editor-button btn success"
120
+ style="width: 25%;"
121
+ onclick={ev => {
122
+ ev.preventDefault();
123
+ props.saveAll();
124
+
125
+ }}>save</button>
126
+ <button
127
+ id="closeall-btn"
128
+ class="file-editor-button btn danger"
129
+ style="width: 25%;"
130
+ onclick={ev => {
131
+ ev.preventDefault();
132
+ props.closeAll();
133
+ }}>close</button>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="file-browser-files">
138
+ {props.opened.length > 0 ? <div class="file-browser-opened-files" style="padding: var(--file-browser-separation);">
139
+ {/*<p style="padding: 0; margin: 0;">opened</p>*/}
140
+ <ul style="padding: 0; margin: 0;">
141
+ {props.opened.map(file => <File
142
+ closeFile={props.closeFile}
143
+ current={props.current}
144
+ fileName={file.fileName}
145
+ filePath={file.filePath}
146
+ hasErrors={props.hasErrors}
147
+ hasFileContentChanged={props.hasFileContentChanged}
148
+ isOpen={props.isOpen}
149
+ openFile={props.openFile} />)}
150
+ </ul></div> : <></>}
151
+ <FileTree
152
+ isDirCollapsed={props.isDirCollapsed}
153
+ toggleCollapseDir={props.toggleCollapseDir}
154
+ closeFile={props.closeFile}
155
+ current={props.current}
156
+ files={props.files}
157
+ filter={props.filter}
158
+ hasErrors={props.hasErrors}
159
+ hasFileContentChanged={props.hasFileContentChanged}
160
+ isOpen={props.isOpen}
161
+ openFile={props.openFile} />
162
+ </div>
163
+ </div>
164
+ }
165
+
166
+ interface FileTreeProps {
167
+ isDirCollapsed: (dir: string) => boolean;
168
+ toggleCollapseDir: (dir: string) => void;
169
+ current: string;
170
+ files: FileBrowserFile[];
171
+ filter: string;
172
+ isOpen: (file: string) => boolean;
173
+ openFile: (file: string) => void;
174
+ closeFile: (file: string) => void;
175
+ hasErrors: (file: string) => boolean;
176
+ hasFileContentChanged: (file: string) => boolean;
177
+ }
178
+
179
+ interface FileTreeDir {
180
+ dirs: {
181
+ [name: string]: FileTreeDir
182
+ };
183
+ files: FileBrowserFile[];
184
+ name: string;
185
+ fullName: string;
186
+ }
187
+
188
+ function FileTree(props: FileTreeProps) {
189
+ const ret: FileTreeDir = {
190
+ dirs: {},
191
+ files: [],
192
+ name: "",
193
+ fullName: ""
194
+ };
195
+
196
+ props.files.forEach((file) => {
197
+ let cDir = ret;
198
+ let fullName = "";
199
+ for (const dir of file.dirs) {
200
+ fullName += dir + "/";
201
+ if (cDir.dirs[dir] === undefined) {
202
+ const newDir: FileTreeDir = {
203
+ dirs: {},
204
+ files: [],
205
+ name: dir,
206
+ fullName: `${fullName}`
207
+ };
208
+ cDir.dirs[dir] = newDir;
209
+ cDir = newDir;
210
+ } else {
211
+ cDir = cDir.dirs[dir];
212
+ }
213
+ }
214
+ cDir.files.push(file);
215
+ });
216
+
217
+ //console.dir(ret);
218
+
219
+ return <FileTreeFolder {...props} tree={ret} level={0} />
220
+ }
221
+
222
+ interface FileTreeFolderProps {
223
+ isDirCollapsed: (dir: string) => boolean;
224
+ toggleCollapseDir: (dir: string) => void;
225
+ tree: FileTreeDir;
226
+ current: string;
227
+ filter: string;
228
+ level: number;
229
+ isOpen: (file: string) => boolean;
230
+ openFile: (file: string) => void;
231
+ closeFile: (file: string) => void;
232
+ hasErrors: (file: string) => boolean;
233
+ hasFileContentChanged: (file: string) => boolean;
234
+ }
235
+
236
+ function FileTreeFolder(props: FileTreeFolderProps) {
237
+
238
+ //console.dir(props.tree);
239
+
240
+ const dirs = Object.keys(props.tree.dirs).map(k => props.tree.dirs[k]);
241
+
242
+ const files = props.tree.files.filter(file => props.filter ? file.filePath.includes(props.filter) : true);
243
+
244
+
245
+ return <ul style={`margin-left: calc(2 * var(--file-browser-separation-file));${props.level === 0 ? " padding: var(--file-browser-separation);" : ""}`}>
246
+ <>
247
+ {props.tree.name !== "" ? <div class="file-browser-dir" style="padding: 0;">
248
+ <p style="margin: 0;">{props.tree.name}/</p>
249
+ <button
250
+ onclick={ev => {
251
+ ev.preventDefault();
252
+ ev.stopPropagation();
253
+ props.toggleCollapseDir(props.tree.fullName);
254
+ }}
255
+ class="btn-small"
256
+ style={"margin: 0; margin-left: calc(2 * var(--file-browser-separation));"}>{props.isDirCollapsed(props.tree.fullName) ? "+" : "-"}</button>
257
+ </div> : <></>}
258
+ {props.isDirCollapsed(props.tree.fullName) ? <></> :
259
+ <>
260
+ {dirs.map(dir => {
261
+ return <FileTreeFolder {...props} tree={dir} level={props.level + 1} />
262
+ })}
263
+ {files.map(file => <File
264
+ closeFile={props.closeFile}
265
+ current={props.current}
266
+ fileName={file.fileName}
267
+ filePath={file.filePath}
268
+ hasErrors={props.hasErrors}
269
+ hasFileContentChanged={props.hasFileContentChanged}
270
+ isOpen={props.isOpen}
271
+ openFile={props.openFile} />)
272
+ }
273
+ </>}
274
+ </>
275
+ </ul>
276
+ }
277
+
278
+ interface FileProps {
279
+ fileName: string;
280
+ filePath: string;
281
+ current: string;
282
+ isOpen: (file: string) => boolean;
283
+ openFile: (file: string) => void;
284
+ closeFile: (file: string) => void;
285
+ hasErrors: (file: string) => boolean;
286
+ hasFileContentChanged: (file: string) => boolean;
287
+ }
288
+
289
+ function File(props: FileProps) {
290
+ const isOpen = props.isOpen(props.filePath);
291
+
292
+ return <li
293
+ class={`file-browser-file${props.hasErrors(props.filePath) ? " error" : ""}${props.hasFileContentChanged(props.filePath) ? " changed" : ""}${props.current === props.filePath ? " active" : ""}${isOpen ? " open" : ""}`}
294
+ style={"display: flex; justify-content: flex-start; align-items: center; margin-left: calc(2 * var(--file-browser-separation-file));"}
295
+ onclick={ev => {
296
+ ev.preventDefault();
297
+ ev.stopPropagation();
298
+ props.openFile(props.filePath);
299
+ }}>
300
+ <p style="margin: 0; padding: 0;">{props.fileName}{props.hasFileContentChanged(props.filePath) ? "(*)" : ""}</p>
301
+ <button
302
+ onclick={ev => {
303
+ ev.preventDefault();
304
+ ev.stopPropagation();
305
+ props.closeFile(props.filePath);
306
+ }}
307
+ class="btn-small"
308
+ style={props.isOpen(props.filePath) ? "margin-left: calc(2 * var(--file-browser-separation-file));" : "display: none;"}
309
+ disabled={!props.isOpen(props.filePath)}>X</button>
310
+ </li>
311
+ }
@@ -0,0 +1,194 @@
1
+ import * as jsx from "@miqro/jsx";
2
+ import JSX from "@miqro/jsx";
3
+
4
+ import { SUPPORTED_LANGUAGES } from "../common/constants.js";
5
+
6
+ interface FileEditorToolbar {
7
+ path: string;
8
+ language: string;
9
+ changed: boolean;
10
+ renameFile: (newName: string) => void;
11
+ deleteFile: () => void;
12
+ setlanguage: (newLang: string) => void;
13
+ saveFile: (reload?: boolean) => void;
14
+ revertFile: () => void;
15
+ closeFile: () => void;
16
+ togglePanel: (panel: string) => void;
17
+ isPanelVisible: (panel: string) => boolean;
18
+ disableLog?: boolean; disablePreview?: boolean; disableReload?: boolean;
19
+ }
20
+
21
+ export function FileEditorToolbar(props: FileEditorToolbar) {
22
+
23
+ const renamingRef = jsx.useRef();
24
+ const refresh = jsx.useRefresh();
25
+ const [renaming, setrenaming] = jsx.useState<boolean>(false);
26
+
27
+ jsx.useEffect(() => {
28
+ if (renamingRef.current) {
29
+ renamingRef.current.value = props.path;
30
+ renamingRef.current.focus();
31
+ refresh();
32
+ }
33
+ }, [renamingRef.current]);
34
+
35
+ jsx.useEffect(() => {
36
+ setrenaming(false);
37
+ }, [props.path]);
38
+
39
+ return <div class="file-editor-toolbar">
40
+ <div class="file-editor-toolbar-row">
41
+ <button
42
+ class="file-editor-button btn"
43
+ style={`${props.isPanelVisible("left") ? "display: none;" : "margin-right: var(--file-browser-separation);"}`}
44
+ onclick={ev => {
45
+ ev.preventDefault();
46
+ props.togglePanel("left");
47
+ }}>{">>"}</button>
48
+ <button
49
+ id="save-btn"
50
+ disabled={!props.changed}
51
+ class={`btn success`}
52
+ onclick={ev => {
53
+ ev.preventDefault();
54
+ props.saveFile();
55
+ }}>save</button>
56
+ {props.disableReload ? <></> : <button
57
+ id="savereload-btn"
58
+ disabled={!props.changed}
59
+ class={`btn info`}
60
+ style="margin-left: var(--file-browser-separation);"
61
+ onclick={ev => {
62
+ ev.preventDefault();
63
+ props.saveFile(true);
64
+ }}>save/reload</button>}
65
+ <button
66
+ id="revert-btn"
67
+ disabled={!props.changed}
68
+ style="margin-left: var(--file-browser-separation);"
69
+ class={`btn warning`}
70
+ onclick={ev => {
71
+ ev.preventDefault();
72
+ props.revertFile();
73
+ }}>revert</button>
74
+ <button
75
+ id="close-btn"
76
+ class={`btn danger`}
77
+ style="margin-left: var(--file-browser-separation);"
78
+ onclick={ev => {
79
+ ev.preventDefault();
80
+ props.closeFile();
81
+
82
+ }}>close</button>
83
+ {SUPPORTED_LANGUAGES.includes(props.language) ?
84
+ <select
85
+ value={props.language}
86
+ oninput={ev => {
87
+ ev.preventDefault();
88
+ props.setlanguage(ev.target.value);
89
+ }}
90
+ style="margin: 0; padding: 0; margin-left: calc(2*var(--file-browser-separation-file));">
91
+ {SUPPORTED_LANGUAGES.map(language => <option value={language}>{language}</option>)}
92
+ </select> : <></>}
93
+ {/*<div
94
+ style="margin-left: calc(2*var(--file-browser-separation));"
95
+ class={`toggle-panel-button left-side-panel-button ${props.isPanelVisible("left") ? "active" : ""}`}
96
+ onclick={ev => {
97
+ ev.preventDefault();
98
+ props.togglePanel("left");
99
+ }}
100
+ ></div>
101
+ <br />
102
+ <div
103
+ style="margin-left: calc(2*var(--file-browser-separation-file));"
104
+ class={`toggle-panel-button bottom-side-panel-button ${props.isPanelVisible("bottom") ? "active" : ""}`}
105
+ onclick={ev => {
106
+ ev.preventDefault();
107
+ props.togglePanel("bottom");
108
+ }}
109
+ ></div>
110
+ <br />
111
+ <div class={`toggle-panel-button right-side-panel-button ${props.isPanelVisible("right") ? "active" : ""}`}
112
+ onclick={ev => {
113
+ ev.preventDefault();
114
+ props.togglePanel("right");
115
+ }}
116
+ ></div>*/}
117
+
118
+
119
+ </div>
120
+ <div class="file-editor-toolbar-row">
121
+ {!renaming ?
122
+ <><p
123
+ style="margin-left:20px;"
124
+ onclick={ev => {
125
+ ev.preventDefault();
126
+ setrenaming(true);
127
+ }}>{props.path}</p>
128
+ </> :
129
+ <>
130
+ <form
131
+ style="width: 100%; height: 100%; margin-right: calc(2 * var(--file-browser-separation));"
132
+ onsubmit={ev => {
133
+ ev.preventDefault();
134
+ setrenaming(false);
135
+ if (renamingRef.current && renamingRef.current.value !== props.path) {
136
+ setrenaming(false);
137
+ props.renameFile(renamingRef.current.value);
138
+ }
139
+ }}>
140
+ <input
141
+ style="width: 100%; height: 100%;"
142
+ onfocusout={ev => {
143
+ ev.preventDefault();
144
+ //setrenaming(false);
145
+ }}
146
+ ref={renamingRef}
147
+ onkeydown={(ev) => {
148
+ if (ev.keyCode === 27) {
149
+ // catch esc
150
+ ev.preventDefault();
151
+ setrenaming(false);
152
+ } else {
153
+ refresh();
154
+ }
155
+ }}
156
+ type="text" />
157
+ </form>
158
+ {renamingRef.current && renamingRef.current.value !== props.path && renamingRef.current.value !== "" ?
159
+ <button
160
+ style="margin-left: var(--file-browser-separation);"
161
+ class="btn info"
162
+ onclick={ev => {
163
+ ev.preventDefault();
164
+ if (renamingRef.current) {
165
+ setrenaming(false);
166
+ props.renameFile(renamingRef.current.value);
167
+ }
168
+ }}>rename file</button>
169
+ : <></>}
170
+ <button
171
+ style="margin-left: var(--file-browser-separation);"
172
+ class="btn danger"
173
+ onclick={ev => {
174
+ ev.preventDefault();
175
+ if (renamingRef.current) {
176
+ setrenaming(false);
177
+ props.deleteFile();
178
+ }
179
+ }}>delete file</button>
180
+ <button
181
+ style="margin-left: var(--file-browser-separation);"
182
+ class="btn"
183
+ onclick={ev => {
184
+ ev.preventDefault();
185
+ setrenaming(false);
186
+ }}>cancel</button>
187
+ </>
188
+ }
189
+ </div>
190
+ </div>
191
+ }
192
+
193
+ FileEditorToolbar.asFragment = true;
194
+ FileEditorToolbar.shadowInit = false;
@@ -0,0 +1,125 @@
1
+ import * as jsx from "@miqro/jsx";
2
+ import JSX from "@miqro/jsx";
3
+
4
+ import { APIPReview } from "./api-preview.js";
5
+ import { FileEditorToolbar } from "./file-editor-toolbar.js";
6
+ import { HighlightTextArea } from "./highlight-text-area.js";
7
+ import { useScroll } from "./scroll-query.js";
8
+
9
+ interface FileEditorProps {
10
+ current: boolean;
11
+ error: string;
12
+ path: string;
13
+ previewPath: string | undefined;
14
+ apiPreview: undefined | {
15
+ path: string;
16
+ method: string;
17
+ }[];
18
+ content: string | null;
19
+ contentchange: (content: string) => void;
20
+ closeFile: () => void;
21
+ saveFile: (reload?: boolean) => void;
22
+ revertFile: () => void;
23
+ deleteFile: () => void;
24
+ renameFile: (newName) => void;
25
+ setlanguage: (newLanguage) => void;
26
+ language: string;
27
+ changed: boolean;
28
+ reloadString: string;
29
+ togglePanel: (panel: string) => void;
30
+ isPanelVisible: (panel: string) => boolean;
31
+ disableLog?: boolean; disablePreview?: boolean; disableReload?: boolean;
32
+ }
33
+
34
+ export function FileEditor({ disableLog, disablePreview, disableReload, togglePanel, isPanelVisible, apiPreview, reloadString, error, revertFile, changed, setlanguage, saveFile, deleteFile, renameFile, current, path, previewPath, content, contentchange, closeFile, language }: FileEditorProps) {
35
+ //console.log("FileEditor [%s]", path);
36
+ const iFrameRef = jsx.useRef();
37
+ const scrollRef = jsx.useRef();
38
+ const [scroll, setScroll] = useScroll();
39
+
40
+ jsx.useEffect(() => {
41
+ if (scrollRef.current) {
42
+ (scrollRef.current as any).scrollLeft = scroll.scrollLeft;
43
+ (scrollRef.current as any).scrollTop = scroll.scrollTop;
44
+ }
45
+ }, [scrollRef.current]);
46
+
47
+ jsx.useEffect(() => {
48
+ if (current && scrollRef.current) {
49
+ setScroll({
50
+ scrollLeft: (scrollRef.current as any).scrollLeft,
51
+ scrollTop: (scrollRef.current as any).scrollTop
52
+ }, true);
53
+ }
54
+ }, [current]);
55
+
56
+ jsx.useEffect(() => {
57
+ if (iFrameRef.current) {
58
+ (iFrameRef.current as any).src = "";
59
+ (iFrameRef.current as any).src = previewPath;
60
+ }
61
+ }, [iFrameRef.current, previewPath, reloadString]);
62
+
63
+ return <div class="file-editor">
64
+ {content === null ? <p>loading</p> : <>
65
+ <FileEditorToolbar
66
+ disableLog={disableLog}
67
+ disablePreview={disablePreview}
68
+ disableReload={disableReload}
69
+ isPanelVisible={isPanelVisible}
70
+ togglePanel={togglePanel}
71
+ revertFile={revertFile}
72
+ closeFile={closeFile}
73
+ language={language}
74
+ path={path}
75
+ changed={changed}
76
+ saveFile={saveFile}
77
+ setlanguage={setlanguage}
78
+ deleteFile={deleteFile}
79
+ renameFile={renameFile} />
80
+ <div
81
+ //class={`file-editor-content${previewPath || apiPreview ? " split" : ""}`}
82
+ class="file-editor-content">
83
+ <div ref={scrollRef}
84
+ class={`file-editor-text-editor${previewPath || (apiPreview && apiPreview.length > 0) && isPanelVisible("right") ? " split" : ""}`}
85
+ //class={`file-editor-text-editor`}
86
+ onscroll={ev => {
87
+ setScroll({
88
+ scrollLeft: ev.target.scrollLeft,
89
+ scrollTop: ev.target.scrollTop
90
+ });
91
+ }}>
92
+ {error ?
93
+ <p class="file-editor-content-error">{error}</p>
94
+ : <></>}
95
+ {language !== "binary" ?
96
+ <HighlightTextArea
97
+ tabChar=" "
98
+ oncontentchange={(args: CustomEvent) => {
99
+ if (contentchange) {
100
+ contentchange(args.detail);
101
+ }
102
+ }}
103
+ content={content}
104
+ language={language} /> : <p>binary data not supported</p>
105
+ }
106
+ </div>
107
+ {apiPreview && apiPreview.length > 0 ? <APIPReview
108
+ isPanelVisible={isPanelVisible}
109
+ apiPreview={apiPreview} /> : <></>}
110
+ {previewPath && isPanelVisible("right") ? <div
111
+ class={`file-editor-preview`}
112
+ style={`${!isPanelVisible("right") ? "display: none;" : ""}`}>
113
+ <div class="file-editor-preview-path"><a href={previewPath} target="_blank">open in new window</a></div>
114
+ <iframe
115
+ ref={iFrameRef}
116
+ src={previewPath} sandbox="allow-scripts allow-same-origin"></iframe>
117
+ </div> : <></>}
118
+ </div>
119
+ </>}
120
+ </div>
121
+ }
122
+
123
+ FileEditor.asFragment = true;
124
+ FileEditor.shadowInit = false;
125
+
@@ -0,0 +1,26 @@
1
+
2
+ import * as jsx from "@miqro/jsx";
3
+ import JSX from "@miqro/jsx";
4
+
5
+ let queryTimeout2: any = null;
6
+
7
+ export function useFilterQuery(): [string, (newFilter: string, inmediate?: boolean) => void] {
8
+ const [filterQuery, setfilterQuery] = jsx.useQuery("filter", "");
9
+ const [filter, setfilter] = jsx.useState<string>(typeof filterQuery === "string" ? filterQuery : "");
10
+
11
+ return [
12
+ filter,
13
+ (newFilter: string, inmediate?: boolean) => {
14
+ clearTimeout(queryTimeout2);
15
+ if (inmediate) {
16
+ setfilter(newFilter);
17
+ setfilterQuery(newFilter);
18
+ } else {
19
+ setfilter(newFilter);
20
+ queryTimeout2 = setTimeout(() => {
21
+ setfilter(newFilter);
22
+ setfilterQuery(newFilter);
23
+ }, 1000);
24
+ }
25
+ }]
26
+ }