Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .run/Run plugin.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<configuration default="false" name="Run plugin" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalProjectPath" value="$PROJECT_DIR$/zowe-explorer-intellij" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--stacktrace" />
<option name="taskDescriptions">
Expand All @@ -18,6 +18,7 @@
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
6 changes: 5 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ data class PluginDescriptor(
val getUntil: () -> Provider<String>, // latest version string this is compatible with, can be wildcard like 202.*
// https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
val sdkVersion: String, // the version string passed to the intellij sdk gradle plugin
val sourceFolder: String // used as the source root for specifics of this build
val sourceFolder: String // use d as the source root for specifics of this build
)

val plugins = listOf(
Expand Down Expand Up @@ -152,6 +152,10 @@ dependencies {
testImplementation(libs.mockk)
testImplementation(libs.kotest.assertions.core)
testImplementation(libs.kotest.runner.junit5)

// Students
implementation(libs.okhttp3.mockwebserver)
implementation(libs.okhttp3.okhttp.tls)
}

intellijPlatform {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@

package org.zowe.explorer.dataops.content.synchronizer

import com.intellij.diff.DiffContentFactory
import com.intellij.diff.DiffManager
import com.intellij.diff.requests.SimpleDiffRequest
import com.intellij.icons.AllIcons
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.showYesNoDialog
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.VirtualFile
import org.zowe.explorer.dataops.DataOpsManager
import org.zowe.explorer.utils.runInEdtAndWait
import java.nio.charset.StandardCharsets

/**
* Functional interface to decide if file content can be uploaded or should be updated from mainframe.
Expand Down Expand Up @@ -47,20 +52,103 @@ fun interface SaveStrategy {
return if (!remoteLastSame) {
var result = shouldUpload
runInEdtAndWait {
result = showYesNoDialog(
title = "Remote Conflict in File ${file.name}",
message = "The file you are currently editing was changed on remote. Do you want to accept remote changes and discard local ones, or overwrite content on the mainframe by local version?",
noText = "Accept Remote",
yesText = "Overwrite Content on the Mainframe",
project = project,
icon = AllIcons.General.WarningDialog
val choice = Messages.showDialog(
project,
"The file you are currently editing was changed on remote. Do you want to accept remote changes and discard local ones, or overwrite content on the mainframe by local version?",
"Remote Conflict in File ${file.name}",
arrayOf("Compare And Decide", "Accept Remote", "Overwrite Content on the Mainframe"),
0, // Default is now "Compare And Decide"
AllIcons.General.WarningDialog
)

when (choice) {
0 -> { // Compare And Decide
// Get file content for comparison
val dataOpsManager = DataOpsManager.getService()
val contentSynchronizer = dataOpsManager.getContentSynchronizer(file)
if (contentSynchronizer != null) {
// Create a sync provider to get content
val syncProvider = DocumentedSyncProvider(file, SaveStrategy.default(project))

// Use the current file content as local content
val localBytes = file.contentsToByteArray()

// Get remote content from the stored remote state
val remoteBytes = contentSynchronizer.successfulContentStorage(syncProvider)
if (remoteBytes.isNotEmpty()) {
showFileComparison(project, file, localBytes, remoteBytes)
} else {
Messages.showErrorDialog(
project,
"Cannot compare files: remote content unavailable",
"Comparison Error"
)
}
} else {
Messages.showErrorDialog(
project,
"Cannot compare files: content synchronizer not available",
"Comparison Error"
)
}
// By default, after comparison we'll preserve local changes
result = shouldUpload
}
1 -> { // Accept Remote (equivalent to previous "No")
result = false
}
2 -> { // Overwrite Content on the Mainframe (equivalent to previous "Yes")
result = true
}
else -> {
result = shouldUpload
}
}
}
result
} else {
shouldUpload
}
}

/**
* Shows a comparison dialog between local and remote versions of a file
* @param project the project to show the dialog in
* @param file the file to compare
* @param localContent the current local content
* @param remoteContent the current remote content
*/
private fun showFileComparison(
project: Project?,
file: VirtualFile,
localContent: ByteArray,
remoteContent: ByteArray
) {
val contentFactory = DiffContentFactory.getInstance()

// For local content, we'll use the file directly
val localDiffContent = contentFactory.create(project, file)

// For remote content, create from bytes
// The correct parameter order is: project, byteContent, file
val remoteDiffContent = contentFactory.createFromBytes(
project,
remoteContent, // The byte array content (this should be the second parameter)
file // The file for context (this should be the third parameter)
)

// Create the diff request
val diffRequest = SimpleDiffRequest(
"Comparing Local and Remote Versions of ${file.name}",
localDiffContent,
remoteDiffContent,
"Local Version (Current)",
"Remote Version"
)

// Show the diff
DiffManager.getInstance().showDiff(project, diffRequest)
}

/**
* Creates a default save strategy with "yes/no" dialog when the last fetched bytes are different from the remote bytes.
Expand Down
Loading
Loading