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,118 @@
1
+ import { HighlightTextArea } from "./highlight-text-area.js";
2
+ import * as jsx from "@miqro/jsx";
3
+ import JSX from "@miqro/jsx";
4
+
5
+ const DEFAULT_HEADERS = `{"content-type": "application/json"}`;
6
+ const DEFAULT_BODY = `{}`;
7
+
8
+ export function APIPReview(props: {
9
+ apiPreview?: {
10
+ path: string;
11
+ method: string;
12
+ }[];
13
+ isPanelVisible: (panel: string) => boolean;
14
+ }) {
15
+ const pathRef = jsx.useRef();
16
+ const methodRef = jsx.useRef();
17
+ const headersRef = jsx.useRef();
18
+ const bodyRef = jsx.useRef();
19
+ const [headers, setHeaders] = jsx.useState<string>(DEFAULT_HEADERS);
20
+ const [body, setBody] = jsx.useState<string>(DEFAULT_BODY);
21
+
22
+ const [responseStatus, setresponseStatus] = jsx.useState<null | number>(null);
23
+ const [responseHeaders, setresponseHeaders] = jsx.useState<null | string>(null);
24
+ const [responseBody, setresponseBody] = jsx.useState<null | string>(null);
25
+
26
+ const { path, method } = props.apiPreview ? props.apiPreview[0] : { path: "", method: "" };
27
+
28
+ jsx.useEffect(() => {
29
+ setresponseStatus(null);
30
+ setresponseHeaders(null);
31
+ setresponseBody(null);
32
+ /*setHeaders(DEFAULT_HEADERS);
33
+ setBody(DEFAULT_BODY);*/
34
+ }, [path]);
35
+
36
+ const useBody = String(method).toLocaleLowerCase() !== "get";
37
+
38
+ function submit() {
39
+ try {
40
+ if (methodRef.current && pathRef.current && headersRef.current) {
41
+ setHeaders(headersRef.current.value);
42
+ if (bodyRef.current) {
43
+ setBody(bodyRef.current.value);
44
+ }
45
+ fetch(pathRef.current.value, useBody && bodyRef.current ? {
46
+ method: methodRef.current.value,
47
+ headers: JSON.parse(headersRef.current.value),
48
+ body: bodyRef.current.value
49
+ } : {
50
+ method: methodRef.current.value,
51
+ headers: JSON.parse(headersRef.current.value),
52
+ }).then(async (r) => {
53
+ setresponseStatus(r.status);
54
+ const headers = {};
55
+ r.headers.forEach((value, key) => {
56
+ headers[key] = value;
57
+ });
58
+ setresponseHeaders(JSON.stringify(headers, undefined, 2));
59
+ const text = await r.text();
60
+ setresponseBody(text);
61
+ try {
62
+ setresponseBody(JSON.stringify(JSON.parse(text), undefined, 2));
63
+ } catch (e) {
64
+ // ignore
65
+ }
66
+ }).catch(e => {
67
+ console.error(e);
68
+ });
69
+ }
70
+ } catch (e) {
71
+ console.error(e);
72
+ }
73
+ }
74
+
75
+ return <div
76
+ style={`${!props.isPanelVisible("right") ? "display: none;" : ""}${props.apiPreview ? "" : " display: none; "}margin:0; padding: 0; overflow: auto; max-height: 100%; width:100%;`}>
77
+ <form
78
+ onsubmit={ev => {
79
+ ev.preventDefault();
80
+ submit();
81
+ }}>
82
+ <p>path</p>
83
+ <input style="width: calc(100% - 4 * var(--file-browser-separation));" type="text" value={path} ref={pathRef} />
84
+ <p>method</p>
85
+ <input style="width: calc(100% - 4 * var(--file-browser-separation));" type="text" value={method} ref={methodRef} />
86
+ <p>headers</p>
87
+ <input style="width: calc(100% - 4 * var(--file-browser-separation));" type="text" value={headers} ref={headersRef} />
88
+ {useBody ?
89
+ <>
90
+ <p>body</p>
91
+ <input style="width: calc(100% - 4 * var(--file-browser-separation));" type="text" value={body} ref={bodyRef} />
92
+ </> :
93
+ <></>}
94
+ <button style="margin-top: var(--file-browser-separation); width: 100%;" class="btn"
95
+ onclick={ev => {
96
+ ev.preventDefault();
97
+ submit();
98
+ }}>submit</button>
99
+ <div>
100
+ <p>response status</p>
101
+ <p>{responseStatus}</p>
102
+ <p>response headers</p>
103
+ <HighlightTextArea
104
+ content={responseHeaders ? responseHeaders : "null"}
105
+ language={"json"}
106
+ disabled="true" />
107
+ <p>response body</p>
108
+ <HighlightTextArea
109
+ content={responseBody ? responseBody : "null"}
110
+ language={"json"}
111
+ disabled="true" />
112
+ </div>
113
+ </form>
114
+ </div>;
115
+ }
116
+
117
+ APIPReview.asFragment = true;
118
+ APIPReview.shadowInit = false;
@@ -0,0 +1,496 @@
1
+ import * as jsx from "@miqro/jsx";
2
+ import JSX from "@miqro/jsx";
3
+ import { FileEditor } from "./file-editor.js";
4
+ import { NewFile } from "./new-file.js";
5
+ import { useScroll } from "./scroll-query.js";
6
+ import { useFilterQuery } from "./filter-query.js";
7
+ import { FileBrowser } from "./file-browser.js";
8
+ import { StartPage } from "./start-page.js";
9
+ import { BASEEDITOR_PATH } from "../common/constants.js";
10
+ import { LogViewer } from "./log-viewer.js";
11
+ import { useLogSocket } from "../common/log-socket.js";
12
+
13
+ function InflateError2Map(errors: {
14
+ filePath: string;
15
+ error: string;
16
+ }[]) {
17
+ const errorMap: {
18
+ [filePath: string]: {
19
+ error: string
20
+ };
21
+ } = {};
22
+ for (const e of errors) {
23
+ const filePath = e.filePath;
24
+ const error = e.error;
25
+ errorMap[filePath] = {
26
+ error
27
+ };
28
+ }
29
+ return errorMap;
30
+ }
31
+
32
+ export function Editor(props: { disablelog?: boolean; disablepreview?: boolean; disablereload?: boolean; migrations: string; services: string; reloadstring: string; files: string; initialcurrent: string; classname?: string; errors: string }) {
33
+ //console.dir(props);
34
+ const logSocket = useLogSocket({
35
+ disableLog: (props as any).disablelog === "true" || props.disablelog === true ? true : false
36
+ });
37
+
38
+ const [services, setservices] = jsx.useState<string[]>(JSON.parse(props.services));
39
+ const [collapsed, setCollapsed] = jsx.useState<{
40
+ [dir: string]: boolean
41
+ }>((() => {
42
+ const ret: { [dir: string]: boolean } = {};
43
+ services.forEach(service => {
44
+ ret[`${service}/`] = false;
45
+ })
46
+ return ret;
47
+ })());
48
+
49
+ /*const [panelVisible, setpanelVisible] = jsx.useState<{
50
+ [panel: string]: boolean | undefined;
51
+ }>({ right: false, bottom: false });*/
52
+
53
+ const [rightPanelVisible, setRightPanelVisible] = jsx.useQuery("right-panel", "0");
54
+ const [leftPanelVisible, setLeftPanelVisible] = jsx.useQuery("left-panel", "1");
55
+ const [bottomPanelVisible, setBottomPanelVisible] = jsx.useQuery("bottom-panel", "0");
56
+
57
+ const [migrations, setmigrations] = jsx.useState<string[]>(JSON.parse(props.migrations));
58
+ const [files, setfiles] = jsx.useState(JSON.parse(props.files) as {
59
+ filePath: string;
60
+ language: string;
61
+ previewPath?: string;
62
+ dirs: string[];
63
+ apiPreview?: {
64
+ path: string;
65
+ method: string;
66
+ }[];
67
+ content?: string;
68
+ fileName: string;
69
+ }[]);
70
+ const [reloadString, setreloadString] = jsx.useState<string>(props.reloadstring);
71
+ const [changed, setchanged] = jsx.useState<{
72
+ [filePath: string]: string | null;
73
+ }>({});
74
+ const [errors, seterrors] = jsx.useState<{
75
+ [filePath: string]: {
76
+ error: string
77
+ };
78
+ }>(InflateError2Map(JSON.parse(props.errors)));
79
+ const [newFileDialogShow, setnewFileDialogShow] = jsx.useState<boolean>(false);
80
+ const [filter, setfilter] = useFilterQuery();
81
+
82
+ const refresh = jsx.useRefresh();
83
+ const [opened, setopened] = jsx.useState<{
84
+ [filePath: string]: {
85
+ filePath: string;
86
+ fileName: string;
87
+ language: string;
88
+ previewPath?: string;
89
+ apiPreview?: {
90
+ path: string;
91
+ method: string;
92
+ }[];
93
+ content: string | null;
94
+ error?: {
95
+ message: string;
96
+ }
97
+ }
98
+ }>({});
99
+ const [current, setcurrent] = jsx.useQuery("current", props.initialcurrent ? props.initialcurrent : "");
100
+ const [_, setScroll] = useScroll();
101
+
102
+ if (current instanceof Array) {
103
+ setcurrent(current[0]);
104
+ } else if (current) {
105
+ if (!opened[current]) {
106
+ const file = files.filter(file => file.filePath === current)[0];
107
+ if (!file) {
108
+ setcurrent("");
109
+ } else {
110
+ openFile(file.filePath);
111
+ }
112
+ }
113
+ }
114
+
115
+ /*useEffect(() => {
116
+ for (const service of services) {
117
+ if (collapsed[`${service}/`] === undefined) {
118
+ collapsed[`${service}/`] = true;
119
+ refresh();
120
+ }
121
+ }
122
+ }, services);*/
123
+
124
+ function openFile(filePath: string) {
125
+ console.log("open [%s]", filePath);
126
+ const isOpen = opened[filePath];
127
+ setScroll({
128
+ scrollLeft: 0,
129
+ scrollTop: 0
130
+ });
131
+ if (!isOpen) {
132
+ const file = files.filter(file => file.filePath === filePath)[0];
133
+ if (!file) {
134
+ throw new Error("cannot find reference to file [" + filePath + "]");
135
+ }
136
+ opened[file.filePath] = {
137
+ content: null,
138
+ ...file
139
+ };
140
+ changed[file.filePath] = null;
141
+
142
+ setopened(opened);
143
+
144
+ if (opened[file.filePath].content === null && (globalThis.window) !== undefined) {
145
+ if (opened[file.filePath].language !== "binary") {
146
+ fetch(BASEEDITOR_PATH + "/api/fs/read", {
147
+ method: "POST",
148
+ headers: {
149
+ ["content-type"]: "application/json"
150
+ },
151
+ body: JSON.stringify({
152
+ path: file.filePath
153
+ })
154
+ }).then(response => {
155
+
156
+ if (response.ok) {
157
+ response.json().then(json => {
158
+ const contents = json.contents;
159
+ if (opened[file.filePath]) {
160
+ opened[file.filePath].content = contents;
161
+ changed[file.filePath] = contents;
162
+ setopened(opened);
163
+ setchanged(changed);
164
+ refresh();
165
+ }
166
+ });
167
+ }
168
+ })
169
+ } else {
170
+ opened[file.filePath].content = "";
171
+ changed[file.filePath] = "";
172
+ setopened(opened);
173
+ refresh();
174
+ }
175
+ }
176
+ }
177
+ setcurrent(filePath);
178
+ }
179
+
180
+ function closeFile(filePath: string) {
181
+ setScroll({
182
+ scrollTop: 0,
183
+ scrollLeft: 0
184
+ })
185
+ console.log("closing [%s]", filePath);
186
+ //console.log("current [%s]", current);
187
+ if (filePath === current) {
188
+ setcurrent("");
189
+ }
190
+ delete opened[filePath];
191
+ delete changed[filePath];
192
+ setchanged(changed);
193
+ setopened(opened);
194
+ refresh();
195
+ }
196
+
197
+ async function scanFiles() {
198
+ const r = await fetch(BASEEDITOR_PATH + "/api/fs/scan", {
199
+ method: "GET"
200
+ });
201
+ if (r.ok) {
202
+ const { files, services } = await r.json();
203
+ setfiles(files);
204
+ setservices(services);
205
+ for (const file of files) {
206
+ if (opened[file.filePath]) {
207
+ opened[file.filePath] = {
208
+ content: opened[file.filePath].content,
209
+ ...file
210
+ };
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ function isDirCollapsed(dir: string) {
217
+ console.log("isDirCollapsed [%s]", dir);
218
+ if (dir === "" || filter !== "") {
219
+ return false;
220
+ }
221
+ return collapsed[dir] || collapsed[dir] === undefined ? true : false;
222
+ //return collapsed[dir] ? false : true;
223
+ }
224
+
225
+ function toggleCollapseDir(dir: string) {
226
+ console.log("toggleCollapseDir [%s]", dir);
227
+ collapsed[dir] = isDirCollapsed(dir) ? false : true;
228
+ setCollapsed(collapsed);
229
+ refresh();
230
+ }
231
+
232
+ async function deleteFile(file: string) {
233
+ console.log("deleteFile [%s]", file);
234
+ const r = await fetch(BASEEDITOR_PATH + "/api/fs/delete", {
235
+ method: "POST",
236
+ headers: {
237
+ ["content-type"]: "application/json"
238
+ },
239
+ body: JSON.stringify({
240
+ path: file
241
+ })
242
+ });
243
+ if (r.ok) {
244
+ await scanFiles();
245
+ if (opened[file]) {
246
+ closeFile(file);
247
+ }
248
+ }
249
+ }
250
+
251
+ async function renameFile(file: string, newName: string) {
252
+ console.log("renameFile [%s] to [%s]", file, newName);
253
+ if (opened[file]) {
254
+ const r = await fetch(BASEEDITOR_PATH + "/api/fs/rename", {
255
+ method: "POST",
256
+ headers: {
257
+ ["content-type"]: "application/json"
258
+ },
259
+ body: JSON.stringify({
260
+ path: file,
261
+ newName
262
+ })
263
+ });
264
+ if (r.ok) {
265
+ const fileO = opened[file];
266
+ const changeO = changed[file];
267
+ fileO.filePath = newName;
268
+ delete changed[file];
269
+ delete opened[file];
270
+ opened[newName] = fileO;
271
+ changed[newName] = changeO;
272
+
273
+ await scanFiles();
274
+
275
+ setopened(opened);
276
+ setchanged(changed);
277
+ if (current === file) {
278
+ setcurrent(newName);
279
+ }
280
+ refresh();
281
+ }
282
+ }
283
+ }
284
+
285
+ async function saveFile(file: string) {
286
+ console.log("saveFile [%s]", file);
287
+ const contents = changed[file];
288
+ if (opened[file] && contents !== undefined && contents !== null) {
289
+ const r = await fetch(BASEEDITOR_PATH + "/api/fs/write", {
290
+ method: "POST",
291
+ headers: {
292
+ ["content-type"]: "application/json"
293
+ },
294
+ body: JSON.stringify({
295
+ path: file,
296
+ contents,
297
+ override: true
298
+ })
299
+ });
300
+ if (r.ok) {
301
+ opened[file].content = contents;
302
+ setopened(opened);
303
+ setchanged(changed);
304
+ refresh();
305
+ }
306
+ }
307
+ }
308
+
309
+ async function reloadServer() {
310
+ const r = await fetch(BASEEDITOR_PATH + "/api/server/reload", {
311
+ method: "POST"
312
+ });
313
+ if (r.ok) {
314
+ const reloadResponse = await r.json();
315
+ if (reloadResponse.errors && reloadResponse.errors.length > 0) {
316
+ seterrors(InflateError2Map(reloadResponse.errors));
317
+ setreloadString(reloadResponse.reloadString);
318
+ refresh();
319
+ } else {
320
+ setreloadString(reloadResponse.reloadString);
321
+ seterrors({});
322
+ refresh();
323
+ }
324
+ setmigrations(reloadResponse.migrations);
325
+ await scanFiles();
326
+ }
327
+ }
328
+
329
+ function setLanguage(file: string, newLanguage: string) {
330
+ if (opened[file]) {
331
+ opened[file].language = newLanguage;
332
+ setopened(opened);
333
+ refresh();
334
+ }
335
+ }
336
+
337
+ function hasFileContentChanged(filePath: string) {
338
+ if (!opened[filePath]) {
339
+ return false;
340
+ }
341
+ return changed[filePath] !== opened[filePath].content
342
+ }
343
+
344
+ function isPanelVisible(panel: string) {
345
+ switch (panel) {
346
+ case "left":
347
+ return leftPanelVisible === "1";
348
+ case "bottom":
349
+ return bottomPanelVisible === "1";
350
+ case "right":
351
+ return rightPanelVisible === "1";
352
+ default:
353
+ return true;
354
+ }
355
+ //return panelVisible[panel] || panelVisible[panel] === undefined ? true : false;
356
+ }
357
+
358
+ function togglePanel(panel: string) {
359
+ console.log("togglePanel [%s]", panel);
360
+ /*panelVisible[panel] = !isPanelVisible(panel);
361
+ setpanelVisible(panelVisible);
362
+ refresh();*/
363
+ switch (panel) {
364
+ case "left":
365
+ return setLeftPanelVisible(isPanelVisible(panel) ? "0" : "1");
366
+ case "bottom":
367
+ return setBottomPanelVisible(isPanelVisible(panel) ? "0" : "1");
368
+ case "right":
369
+ return setRightPanelVisible(isPanelVisible(panel) ? "0" : "1");
370
+ default:
371
+ return;
372
+ }
373
+ }
374
+
375
+ const openedFile = opened[String(current)];
376
+
377
+ //console.log("Editor [%s]", openedFile?.filePath);
378
+
379
+ return <div class="editor">
380
+ <div class={`editor-firstrow${!isPanelVisible("bottom") ? " bottom-panel-hidden" : ""}`}>
381
+ <NewFile
382
+ migrations={migrations}
383
+ services={services}
384
+ open={newFileDialogShow}
385
+ ondone={async (path) => {
386
+ setnewFileDialogShow(false);
387
+ if (path) {
388
+ await scanFiles();
389
+ //await reloadServer();
390
+ }
391
+ }} />
392
+ <FileBrowser
393
+ disableLog={props.disablelog}
394
+ disablePreview={props.disablepreview}
395
+ disableReload={props.disablereload}
396
+ togglePanel={togglePanel}
397
+ isPanelVisible={isPanelVisible}
398
+ opened={Object.keys(opened).sort().map(o => opened[o])}
399
+ isDirCollapsed={isDirCollapsed}
400
+ toggleCollapseDir={toggleCollapseDir}
401
+ migrations={migrations}
402
+ hasErrors={(file) => errors[file] ? true : false}
403
+ reloadServer={reloadServer}
404
+ closeAll={() => {
405
+ const openedList = Object.keys(opened);
406
+ for (const o of openedList) {
407
+ closeFile(o);
408
+ }
409
+ }}
410
+ closeFile={closeFile}
411
+ current={current ? String(current) : ""}
412
+ files={files}
413
+ filter={filter}
414
+ hasFileContentChanged={hasFileContentChanged}
415
+ isOpen={(file) => opened[file] !== undefined}
416
+ openFile={openFile}
417
+ saveAll={async () => {
418
+ const openedList = Object.keys(opened);
419
+ for (const o of openedList) {
420
+ if (hasFileContentChanged(o)) {
421
+ await saveFile(o);
422
+ }
423
+ }
424
+ //await reloadServer();
425
+ }}
426
+ scanFiles={scanFiles}
427
+ setfilter={setfilter}
428
+ showNewFile={() => {
429
+ setnewFileDialogShow(true);
430
+ }}
431
+ />
432
+ <div class={`file-editor-list${!isPanelVisible("left") ? " left-panel-hidden" : ""}${!isPanelVisible("bottom") ? " bottom-panel-hidden" : ""}`}>
433
+ {!openedFile ?
434
+ <StartPage
435
+ disableLog={props.disablelog}
436
+ disablePreview={props.disablepreview}
437
+ disableReload={props.disablereload}
438
+ isPanelVisible={isPanelVisible}
439
+ togglePanel={togglePanel}
440
+ /> :
441
+ <div class="file-editor-container">
442
+ <FileEditor
443
+ disableLog={props.disablelog}
444
+ disablePreview={props.disablepreview}
445
+ disableReload={props.disablereload}
446
+ isPanelVisible={isPanelVisible}
447
+ togglePanel={togglePanel}
448
+ reloadString={reloadString}
449
+ error={errors[openedFile.filePath]?.error}
450
+ changed={hasFileContentChanged(openedFile.filePath)}
451
+ setlanguage={(newLanguage: string) => setLanguage(openedFile.filePath, newLanguage)}
452
+ deleteFile={async () => {
453
+ await deleteFile(openedFile.filePath);
454
+ //await reloadServer();
455
+ }}
456
+ renameFile={async (newName) => {
457
+ await renameFile(openedFile.filePath, newName);
458
+ //await reloadServer();
459
+ }}
460
+ saveFile={async (reload = false) => {
461
+ await saveFile(openedFile.filePath);
462
+ if (reload) {
463
+ await reloadServer();
464
+ }
465
+ //
466
+ }}
467
+ content={changed[openedFile.filePath] !== null ? changed[openedFile.filePath] : opened[openedFile.filePath].content}
468
+ current={current === openedFile.filePath}
469
+ revertFile={() => {
470
+ changed[openedFile.filePath] = openedFile.content;
471
+ setchanged(changed);
472
+ refresh();
473
+ }}
474
+ contentchange={(content) => {
475
+ changed[openedFile.filePath] = content;
476
+ setopened(opened);
477
+ refresh();
478
+ }}
479
+ closeFile={() => {
480
+ closeFile(openedFile.filePath);
481
+ }}
482
+ path={openedFile.filePath}
483
+ previewPath={openedFile.previewPath}
484
+ apiPreview={openedFile.apiPreview}
485
+ language={opened[openedFile.filePath].language} />
486
+ </div>}
487
+ </div>
488
+ </div>
489
+ <div class="editor-bottom-panel" style={`${!isPanelVisible("bottom") ? "display: none;" : ""}`}>
490
+ <LogViewer socket={logSocket} />
491
+ </div>
492
+ </div>
493
+ }
494
+
495
+ Editor.asFragment = true;
496
+ Editor.shadowInit = false;