Skip to content

Code formatting while saving#382

Open
stijnpotters1 wants to merge 4 commits intomasterfrom
fix/auto-save-formatting
Open

Code formatting while saving#382
stijnpotters1 wants to merge 4 commits intomasterfrom
fix/auto-save-formatting

Conversation

@stijnpotters1
Copy link
Contributor

@stijnpotters1 stijnpotters1 commented Mar 24, 2026

Now the code is not formatted or normalized when the file is getting saved.

Instead of moving elements, attributes and cursor:
Now the cursor stays where it was left and attributes dont shift

Note:

  • When adding a configuration or adapter the reformatting is applied.
  • Also the full crud for the adapter since this is only used in the studio. When you return to the editor, the code is not formatted without bothering the user while editing the configuration

Copilot AI review requested due to automatic review settings March 24, 2026 16:55
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes the “save configuration” flow so saving XML no longer reformats/normalizes content (preventing cursor/attribute shifting), and updates backend + frontend contracts accordingly.

Changes:

  • Backend: updateConfiguration now writes raw content to disk and returns no XML payload (controller returns an empty 200 response).
  • Frontend: saveConfiguration now expects no response body; editor no longer replaces content with server-returned XML after save.
  • Config creation paths now add the flow namespace when creating new XML configuration files; tests updated for the new behaviors.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/main/java/org/frankframework/flow/configuration/ConfigurationService.java Stops XML normalization on update; adds namespace insertion when creating new configs (now introduces XML transform exceptions).
src/main/java/org/frankframework/flow/configuration/ConfigurationController.java Update endpoint now returns ResponseEntity<Void>; add-config endpoint now declares XML-related checked exceptions.
src/main/java/org/frankframework/flow/filetree/FileTreeService.java Creating .xml files delegates to configuration creation; throws clause updated (currently contains a compile-breaking duplicate).
src/main/java/org/frankframework/flow/filetree/FileTreeController.java Propagates XML-related checked exceptions from file creation endpoint.
src/main/frontend/app/services/configuration-service.ts saveConfiguration now returns Promise<void> and drops the previous XML response type.
src/main/frontend/app/routes/editor/editor.tsx Save no longer sets editor content from a server-returned XML response.
src/main/frontend/app/routes/studio/canvas/flow.tsx Awaits git diff refresh after saving.
src/test/java/org/frankframework/flow/configuration/ConfigurationServiceTest.java Updates assertions to match raw-write behavior (no newline/normalization).
src/test/java/org/frankframework/flow/configuration/ConfigurationControllerTest.java Updates mocks to reflect boolean/void-style update response.
src/test/java/org/frankframework/flow/filetree/FileTreeServiceTest.java Updates test method signatures to match new checked exceptions.
src/main/java/org/frankframework/flow/adapter/AdapterService.java Removes a stray blank line.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 88 to 90
public Project addConfigurationToFolder(String projectName, String configurationName, String folderPath)
throws IOException, ApiException {
throws IOException, ApiException, ParserConfigurationException, SAXException, TransformerException {
Project project = projectService.getProject(projectName);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addConfigurationToFolder() now declares TransformerException. Unlike SAXException/ParserConfigurationException, TransformerException is not handled by GlobalExceptionHandler, so this can leak as a default Spring error response that doesn’t match the frontend’s expected error shape. Handle/wrap TransformerException (e.g., into ApiException) to keep API error responses consistent.

Copilot uses AI. Check for mistakes.
Comment on lines 49 to +51
public ResponseEntity<ProjectDTO> addConfiguration(
@PathVariable String projectName, @PathVariable String configName)
throws ProjectNotFoundException, IOException {
throws ProjectNotFoundException, IOException, ParserConfigurationException, TransformerException, SAXException {
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint now declares TransformerException, but GlobalExceptionHandler does not map TransformerException to the standard ErrorResponse shape. If this exception escapes, Spring’s default error JSON will likely break the frontend apiFetch error parsing (it expects httpStatus/messages). Prefer catching/wrapping XML transform errors into ApiException (or adding a dedicated handler) to keep error responses consistent.

Copilot uses AI. Check for mistakes.
Comment on lines 63 to 65
public Project addConfiguration(String projectName, String configurationName)
throws ProjectNotFoundException, IOException {
throws ProjectNotFoundException, IOException, TransformerException, ParserConfigurationException, SAXException {
Project project = projectService.getProject(projectName);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addConfiguration() now propagates TransformerException/ParserConfigurationException/SAXException to the controller layer. GlobalExceptionHandler currently handles SAX/ParserConfiguration but not TransformerException, which can lead to inconsistent error payloads for clients. Consider catching TransformerException here and rethrowing an ApiException (or otherwise ensuring it’s handled consistently).

Copilot uses AI. Check for mistakes.
@stijnpotters1 stijnpotters1 requested a review from Matthbo March 24, 2026 17:37
@stijnpotters1 stijnpotters1 self-assigned this Mar 24, 2026
@stijnpotters1 stijnpotters1 marked this pull request as ready for review March 24, 2026 17:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Stijn Potters <stijn.potters1@gmail.com>
@stijnpotters1 stijnpotters1 requested review from Copilot and removed request for Copilot March 24, 2026 17:39
Copilot AI review requested due to automatic review settings March 24, 2026 17:43
@stijnpotters1 stijnpotters1 linked an issue Mar 24, 2026 that may be closed by this pull request
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/main/java/org/frankframework/flow/filetree/FileTreeService.java:145

  • FileTreeService.createFile now exposes XML-processing checked exceptions (ParserConfigurationException, SAXException, TransformerException) in its public signature even though callers may be creating non-XML files. This leaks implementation details and forces controllers/tests to deal with XML-specific exceptions. Consider catching these exceptions inside createFile (or inside ConfigurationService.addConfigurationToFolder) and rethrowing an ApiException/IOException with context so the signature can remain throws IOException, ApiException.
	public FileTreeNode createFile(String projectName, String parentPath, String fileName)
			throws IOException, ApiException, ParserConfigurationException, TransformerException, SAXException {
		if (parentPath == null || parentPath.isBlank()) {
			throw new IllegalArgumentException("Parent path must not be empty");
		}

		validateFileName(fileName);
		String fullPath = parentPath.endsWith("/") ? parentPath + fileName : parentPath + "/" + fileName;
		validateWithinProject(projectName, fullPath);

		if (fileName.toLowerCase().endsWith(".xml")) {
			configurationService.addConfigurationToFolder(projectName, fileName, parentPath);
		} else {
			fileSystemStorage.createFile(fullPath);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 47 to +60
@@ -56,16 +55,13 @@ public String updateConfiguration(String filepath, String content)
if (Files.isDirectory(absolutePath)) {
throw new ConfigurationNotFoundException("Invalid file path: " + filepath);
}
Document updatedDocument = XmlConfigurationUtils.insertFlowNamespace(content);
String updatedContent = XmlConfigurationUtils.convertNodeToString(updatedDocument);

// Just write to the disk. ProjectService reads directly from disk now!
fileSystemStorage.writeFile(absolutePath.toString(), updatedContent);
return updatedContent;
fileSystemStorage.writeFile(absolutePath.toString(), content);
return true;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateConfiguration now returns boolean but always returns true, and the controller ignores the return value. This makes the API misleading and adds unnecessary branching for callers/tests. Consider changing the method to void (or return something meaningful) and removing the unconditional return true.

Copilot uses AI. Check for mistakes.
Comment on lines 48 to 52
@PostMapping("/{projectName}/configurations/{configName}")
public ResponseEntity<ProjectDTO> addConfiguration(
@PathVariable String projectName, @PathVariable String configName)
throws ProjectNotFoundException, IOException {
throws ProjectNotFoundException, IOException, ParserConfigurationException, TransformerException, SAXException {
Project project = configurationService.addConfiguration(projectName, configName);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addConfiguration is now declared to throw TransformerException, but there is no global @ExceptionHandler for TransformerException (unlike SAXException / ParserConfigurationException). This will likely result in inconsistent/non-JSON 500 responses if a transform fails. Consider catching TransformerException here and wrapping it in ApiException (or adding a global handler) to keep error responses consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to 39
return apiFetch<void>(`/projects/${encodeURIComponent(projectName)}/configuration`, {
method: 'PUT',
body: JSON.stringify({ filepath, content }),
})
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchConfigurationCached uses the module-level configCache, but saveConfiguration doesn't update or invalidate that cache. After saving, other screens that rely on fetchConfigurationCached can read stale XML until a manual cache clear happens. Consider updating configCache for the saved key (set it to content) or deleting that key once the PUT succeeds.

Suggested change
return apiFetch<void>(`/projects/${encodeURIComponent(projectName)}/configuration`, {
method: 'PUT',
body: JSON.stringify({ filepath, content }),
})
await apiFetch<void>(`/projects/${encodeURIComponent(projectName)}/configuration`, {
method: 'PUT',
body: JSON.stringify({ filepath, content }),
})
const key = `${projectName}:${filepath}`
configCache.set(key, content)

Copilot uses AI. Check for mistakes.
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Editor saving results is moving selector Backend automatically alphabetises attributes

2 participants