Skip to content

Commit ff7b5b7

Browse files
committed
#587 #591 UI Improvements after I18N changes. Ready for testing.
1 parent a5ec4e9 commit ff7b5b7

9 files changed

Lines changed: 94 additions & 55 deletions

File tree

web-designer/tcmenu-code-generator/src/main/java/com/thecoderscorner/menu/editorui/generator/logger/DelegatingUserFeedbackLogger.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ public class DelegatingUserFeedbackLogger implements UserFeedbackLogger {
99

1010
private final UserFeedbackLogger delegate;
1111

12+
@Override
13+
public void banner() {
14+
log.debug("Presenting banner");
15+
delegate.banner();
16+
}
17+
1218
@Override
1319
public void debug(String data) {
1420
log.debug(data);

web-designer/tcmenu-code-generator/src/main/java/com/thecoderscorner/menu/editorui/generator/logger/UserFeedbackLogger.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.thecoderscorner.menu.editorui.generator.logger;
22

33
public interface UserFeedbackLogger {
4+
void banner();
45
void debug(String data);
56
void info(String data);
67
void warn(String data);

web-designer/tcmenu-web-generator/src/main/java/com/thecoderscorner/menu/web/controller/GenerateCodeController.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ public class GenerateCodeController {
8989
private int maxFileSize = 1048576;
9090
@Value("${tcmenu.web.generator.maxTotalSize:5242880}")
9191
private int maxTotalSize = 5242880;
92-
@Value("${tcmenu.web.generator.rateLimitMinutes:1}")
93-
private int rateLimitMinutes = 1;
92+
@Value("${tcmenu.web.generator.rateLimitSeconds:15}")
93+
private int rateLimitSeconds = 15;
9494

9595
private Semaphore buildSemaphore;
9696

@@ -138,9 +138,9 @@ public GenerationResponse generateCode(@RequestBody String requestData, HttpServ
138138
long millisStart = System.currentTimeMillis();
139139
String userIp = servletRequest.getRemoteAddr();
140140
var lastBuildTime = userRateLimitCache.getIfPresent(userIp);
141-
if(lastBuildTime != null && Duration.between(lastBuildTime, LocalDateTime.now()).toMinutes() < rateLimitMinutes) {
141+
if(lastBuildTime != null && Duration.between(lastBuildTime, LocalDateTime.now()).toSeconds() < rateLimitSeconds) {
142142
log.warn("Request rejected: Rate limit exceeded for IP {}", userIp);
143-
return GenerationResponse.badResponse(List.of(new LogEntry("Rate limit exceeded, please wait " + rateLimitMinutes + " minute(s) between builds", Level.ERROR)));
143+
return GenerationResponse.badResponse(List.of(new LogEntry("Rate limit exceeded, please wait " + rateLimitSeconds + " seconds between builds", Level.ERROR)));
144144
}
145145

146146
GenerateCodeRequest request;
@@ -212,6 +212,7 @@ public GenerationResponse generateCode(@RequestBody String requestData, HttpServ
212212
log.info("Generating code for project {} with build UUID of {}", uuid, buildUuid);
213213

214214
var logger = new ControllerFeedbackLogger();
215+
logger.banner();
215216
EmbeddedPlatform platform = menuWithOptions.getOptions().getEmbeddedPlatform();
216217
var generator = codeGeneratorSupplier.getCodeGeneratorFor(platform, menuWithOptions.getOptions(), logger);
217218
log.info("Code generator for {} is an instance of {}", platform, generator.getClass().getSimpleName());
@@ -417,6 +418,18 @@ private List<CodePluginItem> allPlugins(CodeGeneratorOptions options) {
417418
static class ControllerFeedbackLogger implements UserFeedbackLogger {
418419
private final List<LogEntry> logEntries = new java.util.ArrayList<>(200);
419420
private final List<GeneratedFile> filesInOutput = new ArrayList<>();
421+
422+
@Override
423+
public void banner() {
424+
info(" _____ __ __ ");
425+
info(" / / / |_ ___| \\/ | ___ _ __ _ _ ");
426+
info(" / / /| __/ __| |\\/| |/ _ \\ '_ \\| | | |");
427+
info(" / / / | || (__| | | | __/ | | | |_| |");
428+
info("/_/_/ \\__\\___|_| |_|\\___|_| |_|\\__,_|");
429+
info("Code generator");
430+
info("");
431+
}
432+
420433
@Override
421434
public void debug(String data) {
422435
logEntries.add(new LogEntry(data, Level.DEBUG));

web-designer/tcmenu-web-generator/src/main/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ tcmenu.web.generator.maxFileSize=1048576
1111
# Max total request size (for all file contents combined, etc.)
1212
tcmenu.web.generator.maxTotalSize=5242880
1313
# Rate limit for builds (minutes between builds per IP)
14-
tcmenu.web.generator.rateLimitMinutes=1
14+
tcmenu.web.generator.rateLimitSeconds=15

web-designer/tcmenugen/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ function App() {
340340
</div>
341341
<nav>
342342
<ul>
343-
<li><NavLink to="/start-project">Start Project</NavLink></li>
343+
{!project && <li><NavLink to="/start-project">Start Project</NavLink></li>}
344344
<li><NavLink to="/menu-edit">Menu Edit</NavLink></li>
345345
{project && <li><NavLink to="/generate-code">Generate Code</NavLink></li>}
346346
{project && <li><NavLink to="/io-expanders">Io Expanders</NavLink></li>}

web-designer/tcmenugen/src/generator/FilePatcher.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
1-
import {GeneratedFile} from "./TcCodeGeneration";
1+
import {GeneratedFile, LogEntry} from "./TcCodeGeneration";
22
import {MenuTreeWithCodeOptions, RoundTripMode} from "../domain/ProjectStruct";
33
import {getDirectoryHandle} from "../App";
44

5-
export async function filePatcher(files: GeneratedFile[], project: MenuTreeWithCodeOptions) {
5+
export async function filePatcher(files: GeneratedFile[], project: MenuTreeWithCodeOptions,
6+
onLineLogged: (line: LogEntry) => void) {
7+
onLineLogged({level: "INFO", log: "Starting local file patching"});
68
if(project.roundTripMode !== RoundTripMode.DIRECTORY_IN_BROWSER) {
79
throw new Error("Round trip mode must be enabled for file patching");
810
}
911

1012
const rootDirectory = getDirectoryHandle();
1113
if(rootDirectory == null) {
14+
onLineLogged({level: "ERROR", log: "The project directory is not resolvable. Please use the zip and patch manually"});
1215
throw new Error("The project directory is not resolvable. Please use the zip and patch manually");
1316
}
1417

1518
const permission = await (rootDirectory as any).queryPermission({ mode: "readwrite" });
1619
if(permission !== "granted") {
1720
const requestedPermission = await (rootDirectory as any).requestPermission({ mode: "readwrite" });
1821
if(requestedPermission !== "granted") {
22+
onLineLogged({level: "ERROR", log: "Cannot write into directory, please use zip download instead"});
1923
throw new Error("Write permission was not granted. Please use the zip and patch manually");
2024
}
2125
}
@@ -28,13 +32,15 @@ export async function filePatcher(files: GeneratedFile[], project: MenuTreeWithC
2832
file.fileName.includes("\\") ||
2933
pathSegments.some(segment => segment === "" || segment === "." || segment === "..")
3034
) {
35+
onLineLogged({level: "ERROR", log: "Invalid generated file path: " + file.fileName});
3136
throw new Error("Invalid generated file path: " + file.fileName);
3237
}
3338

3439
const directorySegments = pathSegments.slice(0, -1);
3540
const fileName = pathSegments[pathSegments.length - 1];
3641

3742
if(directorySegments.length > 3) {
43+
onLineLogged({level: "ERROR", log: "Invalid generated file path - too many levels: " + file.fileName});
3844
throw new Error("Too many levels in the returned zip. Path=" + file.fileName);
3945
}
4046

@@ -55,13 +61,13 @@ export async function filePatcher(files: GeneratedFile[], project: MenuTreeWithC
5561
if(!resolvedFile.file.alwaysOverwrite) {
5662
try {
5763
await directoryHandle.getFileHandle(resolvedFile.fileName, { create: false });
58-
console.log(`File ${resolvedFile.fileName} is not overwritable and already exists, skipping`);
64+
onLineLogged({level: "INFO", log: `File ${resolvedFile.fileName} is not overwritable and already exists, skipping`});
5965
continue;
6066
} catch(error) {
61-
console.log(`File ${resolvedFile.fileName} does not exist, creating`);
67+
onLineLogged({level: "INFO", log: `File ${resolvedFile.fileName} does not exist and will be created`});
6268
}
6369
} else {
64-
console.log(`File ${resolvedFile.fileName} will be written out`);
70+
onLineLogged({level: "INFO", log: `File ${resolvedFile.fileName} will be written out`});
6571
}
6672

6773
const fileHandle = await directoryHandle.getFileHandle(resolvedFile.fileName, { create: true });

web-designer/tcmenugen/src/generator/GeneratorLogView.css

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
.generator-log-container {
22
margin-top: 20px;
3-
border: 1px solid #ccc;
4-
padding: 10px;
5-
background-color: #f9f9f9;
3+
border: 1px solid #444;
4+
padding: 15px;
5+
background-color: #f0f0f0;
6+
border-radius: 8px;
67
}
78

89
.generator-log-header {
@@ -46,39 +47,51 @@
4647
background-color: #218838;
4748
}
4849

49-
.log-table {
50-
width: 100%;
51-
border-collapse: collapse;
52-
font-family: monospace;
50+
.generator-log-terminal {
51+
background-color: #1e1e1e;
52+
color: #d4d4d4;
53+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
5354
font-size: 14px;
55+
padding: 15px;
56+
border-radius: 4px;
57+
max-height: 500px;
58+
overflow-y: auto;
59+
line-height: 1.5;
60+
box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
5461
}
5562

56-
.log-table th, .log-table td {
57-
padding: 8px;
58-
text-align: left;
59-
border-bottom: 1px solid #eee;
63+
.log-line {
64+
display: flex;
65+
margin-bottom: 2px;
66+
white-space: pre-wrap;
67+
word-break: break-all;
6068
}
6169

62-
.log-table th {
63-
background-color: #e0e0e0;
70+
.log-level {
71+
flex-shrink: 0;
72+
width: 60px;
73+
font-weight: bold;
74+
margin-right: 10px;
75+
}
76+
77+
.log-message {
78+
flex-grow: 1;
6479
}
6580

6681
.log-level-error {
67-
color: #d32f2f;
68-
font-weight: bold;
82+
color: #f44336;
6983
}
7084

7185
.log-level-warn {
72-
color: #ef6c00;
73-
font-weight: bold;
86+
color: #ff9800;
7487
}
7588

7689
.log-level-info {
77-
color: #388e3c;
90+
color: #4caf50;
7891
}
7992

8093
.log-level-debug {
81-
color: #757575;
94+
color: #9e9e9e;
8295
}
8396

8497
.status-success {

web-designer/tcmenugen/src/generator/GeneratorLogView.tsx

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export interface CodeGeneratedProperties {
1111
}
1212

1313
export const GeneratorLogView: React.FC<CodeGeneratedProperties> = ({response, onDismiss, menuProject}) => {
14+
const [logLines, setLogLines] = React.useState<LogEntry[]>(response.logLines);
15+
const [genStatus, setGenStatus] = React.useState<string>(response.successful ? "SUCCESS" : "FAILED");
1416
const getLevelClass = (level: string) => {
1517
switch (level.toUpperCase()) {
1618
case 'ERROR': return 'log-level-error';
@@ -22,27 +24,29 @@ export const GeneratorLogView: React.FC<CodeGeneratedProperties> = ({response, o
2224
}
2325
};
2426

27+
const onLineLogged = (line: LogEntry) => {
28+
setLogLines(prevLines => [...prevLines, line]);
29+
};
30+
2531
async function onPatchFiles() {
2632
try {
27-
await filePatcher(response.generatedFiles, menuProject);
28-
alert("All files patched successfully!");
33+
setGenStatus("PATCHING IN PROGRESS");
34+
await filePatcher(response.generatedFiles, menuProject, onLineLogged);
35+
onLineLogged({ level: "INFO", log: "All files patched successfully!"});
36+
setGenStatus("PATCHED FILES");
2937
} catch (error) {
3038
alert("Failed to patch files: " + error);
3139
}
3240
}
3341

3442
return (
3543
<div className="generator-log-container">
36-
<h3>We need your feedback on where to take things next!</h3>
37-
<p><a href="https://github.com/TcMenu/tcMenu/discussions/572">
38-
Share your thoughts on our GitHub web designer discussion
39-
</a></p>
4044
<div className="generator-log-header">
4145
<h3>Code Generation Results</h3>
4246
<div className="log-header-controls">
4347
<p>Build ID: {response.buildId}</p>
4448
<p>Status: <span className={response.successful ? "status-success" : "status-fail"}>
45-
{response.successful ? "SUCCESS" : "FAILED"}
49+
{genStatus}
4650
</span></p>
4751
</div>
4852
<div className="log-header-buttons">
@@ -58,22 +62,18 @@ export const GeneratorLogView: React.FC<CodeGeneratedProperties> = ({response, o
5862
<button type="button" className="dismiss-button" onClick={onDismiss}>Dismiss</button>
5963
</div>
6064
</div>
61-
<table className="log-table">
62-
<thead>
63-
<tr>
64-
<th style={{width: "100px"}}>Level</th>
65-
<th>Message</th>
66-
</tr>
67-
</thead>
68-
<tbody>
69-
{response.logLines && response.logLines.map((entry: LogEntry, index: number) => (
70-
<tr key={index}>
71-
<td className={getLevelClass(entry.level)}>{entry.level}</td>
72-
<td>{entry.log}</td>
73-
</tr>
74-
))}
75-
</tbody>
76-
</table>
65+
<div className="generator-log-terminal">
66+
{logLines && logLines.map((entry: LogEntry, index: number) => (
67+
<div key={index} className="log-line">
68+
<span className={`log-level ${getLevelClass(entry.level)}`}>
69+
{entry.level.toUpperCase().padEnd(5)}
70+
</span>
71+
<span className="log-message">{entry.log}</span>
72+
</div>
73+
))}
74+
</div>
75+
<h4><a href="https://github.com/TcMenu/tcMenu/discussions/572">
76+
Please help us improve the web designer by sharing your feedback on GitHub!</a></h4>
7777
</div>
7878
);
7979
}

web-designer/tcmenugen/src/menuedit/ProjectWelcome.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export function ProjectWelcome() {
8989
<div className="editor-actions">
9090

9191
{isFileSystemAccessSupported() ?
92-
<button className="open-dir-button" onClick={handleOpenDirectory}>Open Local Project Directory (legacy mode)</button> :
92+
<button className="open-dir-button" onClick={handleOpenDirectory}>Open Local Project Directory (round trip)</button> :
9393
<p>Round trip mode needs (Google Chrome or Microsoft Edge).</p>
9494
}
9595

@@ -103,7 +103,7 @@ export function ProjectWelcome() {
103103
onDragOver={handleDragOver}
104104
onDragLeave={handleDragLeave}
105105
>
106-
<p>Drag and drop your <strong>.emf</strong> project file here.</p>
106+
<p>Drag and drop your <strong>.emf</strong> project file here (outputs project as zip).</p>
107107
</div>
108108
</div>
109109

0 commit comments

Comments
 (0)