Skip to content

Commit

Permalink
IJMP-1522 Added the ability to create a Zote Team Configuration file
Browse files Browse the repository at this point in the history
Zote Team Configuration file can be created for the current project directly from the plugin

New:
      src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZoweTeamConfigDialog.kt
      src/main/kotlin/org/zowe/explorer/explorer/actions/AddZoweTeamConfigAction.kt
      src/main/resources/files/zowe.config.json
      src/main/resources/files/zowe.schema.json
Modified:
      src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurable.kt
      src/main/kotlin/org/zowe/explorer/zowe/ZoweStartupActivity.kt
      src/main/kotlin/org/zowe/explorer/zowe/service/ZoweConfigService.kt
      src/main/kotlin/org/zowe/explorer/zowe/service/ZoweConfigServiceImpl.kt
      src/main/kotlin/org/zowe/explorer/zowe/service/ZoweFileListener.kt
      src/main/resources/META-INF/plugin.xml
  • Loading branch information
Katsiaryna Tsytsenia authored and Katsiaryna Tsytsenia committed Apr 17, 2024
1 parent 08f24b2 commit 8829c89
Show file tree
Hide file tree
Showing 10 changed files with 973 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,17 @@ class ZOSMFConnectionConfigurable : BoundSearchableConfigurable("z/OSMF Connecti
}

/** Generates a connection removal warning message that is used for working sets */
private fun generateRemoveWarningMessage(wsUsages: List<WorkingSetConfig>, wsType: String): StringBuilder {
val warningMessageBuilder =
StringBuilder("<nobr>The following $wsType working sets use selected connections:</nobr><br>")
wsUsages.forEach { wsConfig ->
warningMessageBuilder.append(wsConfig.name).append(", ")
companion object {
fun generateRemoveWarningMessage(wsUsages: List<WorkingSetConfig>, wsType: String): StringBuilder {
val warningMessageBuilder =
StringBuilder("<nobr>The following $wsType working sets use selected connections:</nobr><br>")
wsUsages.forEach { wsConfig ->
warningMessageBuilder.append(wsConfig.name).append(", ")
}
warningMessageBuilder.setLength(warningMessageBuilder.length - 2)
warningMessageBuilder.append(".<br>")
return warningMessageBuilder
}
warningMessageBuilder.setLength(warningMessageBuilder.length - 2)
warningMessageBuilder.append(".<br>")
return warningMessageBuilder
}

/** Remove connections with the warning before they are deleted */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright IBA Group 2020
*/

package org.zowe.explorer.config.connect.ui.zosmf

import com.intellij.icons.AllIcons
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.MessageDialogBuilder
import com.intellij.ui.dsl.builder.*
import org.zowe.explorer.common.ui.DialogMode
import org.zowe.explorer.common.ui.StatefulDialog
import org.zowe.explorer.common.ui.showUntilDone
import org.zowe.explorer.config.connect.ConnectionConfig
import org.zowe.explorer.config.connect.CredentialService
import org.zowe.explorer.config.connect.whoAmI
import org.zowe.explorer.dataops.DataOpsManager
import org.zowe.explorer.dataops.operations.InfoOperation
import org.zowe.explorer.dataops.operations.ZOSInfoOperation
import org.zowe.explorer.utils.*
import org.zowe.explorer.utils.crudable.Crudable
import org.zowe.explorer.utils.crudable.find
import org.zowe.explorer.zowe.ZOWE_CONFIG_NAME
import org.zowe.kotlinsdk.annotations.ZVersion
import java.awt.Component
import java.util.*
import javax.swing.JCheckBox
import javax.swing.JComponent
import javax.swing.JPasswordField
import javax.swing.JTextField

/** Dialog to add a new zowe config file */
class ZoweTeamConfigDialog(
private val crudable: Crudable,
override var state: ConnectionDialogState = ConnectionDialogState(),
val project: Project? = null
) : StatefulDialog<ConnectionDialogState>(project) {

/**
* Private field
* In case of DialogMode.UPDATE takes the last successful state from crudable, takes default state otherwise
*/
private val lastSuccessfulState: ConnectionDialogState =
if (state.mode == DialogMode.UPDATE) crudable.find<ConnectionConfig> { it.uuid == state.connectionUuid }
.findAny()
.orElseGet { state.connectionConfig }
.toDialogState(crudable) else ConnectionDialogState()

companion object {

/** Show Test connection dialog and test the connection regarding the dialog state.
* The method checks whether connection succeeds for specified user/password..
* */
@JvmStatic
fun showAndTestConnection(
crudable: Crudable,
parentComponent: Component? = null,
project: Project? = null,
initialState: ConnectionDialogState
): ConnectionDialogState? {
return showUntilDone(
initialState = initialState,
factory = { ZoweTeamConfigDialog(crudable, initialState, project) },
test = { state ->
val newTestedConnConfig: ConnectionConfig
if (initialState.mode == DialogMode.UPDATE) {
val newState = state.clone()
newState.initEmptyUuids(crudable)
newTestedConnConfig = ConnectionConfig(
newState.connectionUuid,
newState.connectionName,
newState.connectionUrl,
newState.isAllowSsl,
newState.zVersion
)
CredentialService.instance.setCredentials(
connectionConfigUuid = newState.connectionUuid,
username = newState.username,
password = newState.password
)
} else {
state.initEmptyUuids(crudable)
newTestedConnConfig = state.connectionConfig
CredentialService.instance.setCredentials(
connectionConfigUuid = state.connectionUuid,
username = state.username,
password = state.password
)
}
val throwable =
runTask(title = "Testing Connection to ${newTestedConnConfig.url}", project = project) {
return@runTask try {
runCatching {
service<DataOpsManager>().performOperation(InfoOperation(newTestedConnConfig), it)
}.onSuccess {
val systemInfo =
service<DataOpsManager>().performOperation(ZOSInfoOperation(newTestedConnConfig))
state.zVersion = when (systemInfo.zosVersion) {
"04.25.00" -> ZVersion.ZOS_2_2
"04.26.00" -> ZVersion.ZOS_2_3
"04.27.00" -> ZVersion.ZOS_2_4
"04.28.00" -> ZVersion.ZOS_2_5
else -> ZVersion.ZOS_2_1
}
}.onFailure {
throw it
}
null
} catch (t: Throwable) {
t
}
}
if (throwable != null) {
state.mode = DialogMode.UPDATE
val confirmMessage = "Do you want to add it anyway?"
val tMessage = throwable.message?.let {
if (it.contains("Exception")) {
it.substring(it.lastIndexOf(":") + 2)
.replaceFirstChar { c -> if (c.isLowerCase()) c.titlecase(Locale.getDefault()) else c.toString() }
} else {
it
}
}
val message = if (tMessage != null) {
"$tMessage\n\n$confirmMessage"
} else {
confirmMessage
}
val addAnyway = MessageDialogBuilder
.yesNo(
title = "Error Creating Connection",
message = message
).icon(AllIcons.General.ErrorDialog)
.run {
if (parentComponent != null) {
ask(parentComponent)
} else {
ask(project)
}
}
addAnyway
} else {
runTask(title = "Retrieving user information", project = project) {
state.owner = whoAmI(newTestedConnConfig) ?: ""
}
true
}
}
)
}
}

private val initialState = state.clone()

private lateinit var urlTextField: JTextField

private lateinit var sslCheckbox: JCheckBox

private lateinit var globalConfigCheckbox: JCheckBox

init {
isResizable = false
}

/** Create dialog with the fields */
override fun createCenterPanel(): JComponent {
val sameWidthLabelsGroup = "CONNECTION_DIALOG_LABELS_WIDTH_GROUP"

state.zoweConfigPath = "${project?.basePath}/${ZOWE_CONFIG_NAME}"
var connectionName = "zowe-".plus(project?.name)
return panel {
row {
label("Connection name")
.widthGroup(sameWidthLabelsGroup)
if (state.zoweConfigPath == null) {
textField()
.bindText(state::connectionName)
.enabled(false)
.text(connectionName)
.validationOnApply {
it.text = it.text.trim()
validateForBlank(it) ?: validateConnectionName(
it,
initialState.connectionName.ifBlank { null },
crudable
)
}
.focused()
.align(AlignX.FILL)
} else {
textField()
.bindText(state::connectionName)
.enabled(false)
.text(connectionName)
.applyToComponent { isEditable = false }
.align(AlignX.FILL)
}
}
row {
label("Connection URL: ")
.widthGroup(sameWidthLabelsGroup)
textField()
.bindText(state::connectionUrl)
.validationOnApply {
it.text = it.text.trim().removeTrailingSlashes()
validateForBlank(it) ?: validateZosmfUrl(it)
}
.also { urlTextField = it.component }
.align(AlignX.FILL)
}
row {
label("Username")
.widthGroup(sameWidthLabelsGroup)
(
cell(JPasswordField())
)
.bindText(state::username)
.validationOnApply {
validateForBlank(String(it.password).trim(), it)
}
.onApply {
state.username = state.username.trim().uppercase()
}
.align(AlignX.FILL)
}
row {
label("Password: ")
.widthGroup(sameWidthLabelsGroup)
cell(JPasswordField())
.bindText(state::password)
.validationOnApply { validateForBlank(it) }
.align(AlignX.FILL)
}
indent {
row {
checkBox("Accept self-signed SSL certificates")
.bindSelected(state::isAllowSsl)
.also { sslCheckbox = it.component }
}
row {
checkBox("Create global Zowe Team Configuration file")
.enabled(false)
}
}
}
.withMinimumWidth(500)
}

init {
init()
title = "Add Zowe Team Configuration file"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.zowe.explorer.explorer.actions

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.components.service
import com.intellij.openapi.vfs.VirtualFileManager
import org.zowe.explorer.config.configCrudable
import org.zowe.explorer.config.connect.CredentialService
import org.zowe.explorer.config.connect.ui.zosmf.ConnectionDialogState
import org.zowe.explorer.config.connect.ui.zosmf.ZoweTeamConfigDialog
import org.zowe.explorer.config.connect.ui.zosmf.initEmptyUuids
import org.zowe.explorer.utils.runReadActionInEdtAndWait
import org.zowe.explorer.zowe.ZOWE_CONFIG_NAME
import org.zowe.explorer.zowe.service.ZoweConfigService
import java.nio.file.Path


/**
* Action for adding zowe team config file through UI.
*/
class AddZoweTeamConfigAction : AnAction() {

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.EDT
}

override fun update(e: AnActionEvent) {
val project = e.project ?: let {
e.presentation.isEnabled = false
e.presentation.description = "Configuration file can only be created in the project"
return
}
val zoweConfigLocation = "${project.basePath}/$ZOWE_CONFIG_NAME"
runReadActionInEdtAndWait {
VirtualFileManager.getInstance().findFileByNioPath(Path.of(zoweConfigLocation))
}?.let {
e.presentation.isEnabled = false
e.presentation.description = "$ZOWE_CONFIG_NAME already exists in the project"
} ?: return
}

/** Shows zowe team config dialog */
override fun actionPerformed(e: AnActionEvent) {
val state = ZoweTeamConfigDialog.showAndTestConnection(
crudable = configCrudable,
project = e.project,
initialState = ConnectionDialogState().initEmptyUuids(configCrudable)
)
if (state != null) {
val connectionConfig = state.connectionConfig
val project = e.project ?: let {
e.presentation.isEnabled = false
e.presentation.description = "$ZOWE_CONFIG_NAME already exists in the project"
return
}
val zoweConfigService = project.service<ZoweConfigService>()
zoweConfigService.addZoweConfigFile(state)

CredentialService.instance.setCredentials(connectionConfig.uuid, state.username, state.password)
configCrudable.add(connectionConfig)
} else {
return
}
}

override fun isDumbAware(): Boolean {
return true
}
}
25 changes: 25 additions & 0 deletions src/main/kotlin/org/zowe/explorer/zowe/ZoweStartupActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,31 @@ fun showNotificationForAddUpdateZoweConfigIfNeeded(project: Project) {
}
}

/**
* Checks if zowe config has been deleted to be synchronized with crudable configs and show notification with delete action.
* @param project - project instance to check zoweConfig.
* @return Nothing.
*/
fun showNotificationForDeleteZoweConfigIfNeeded(project: Project) {
// if (zoweConfigState == ZoweConfigState.NOT_EXISTS) {
NotificationGroupManager.getInstance().getNotificationGroup(EXPLORER_NOTIFICATION_GROUP_ID)
.createNotification("Zowe config file has been deleted", NotificationType.INFORMATION)
.apply {
subscribe(ZOWE_CONFIG_CHANGED, object : ZoweConfigHandler {
override fun onConfigSaved(config: ZoweConfig, connectionConfig: ConnectionConfig) {
hideBalloon()
}
})
addAction(object : DumbAwareAction("Delete Zowe Connection") {
override fun actionPerformed(e: AnActionEvent) {
project.service<ZoweConfigService>().deleteZoweConfig()
hideBalloon()
}
}).notify(project)
}
// }
}

/**
* ZoweStartupActivity is needed to scan for the presence of a file at the project startup.
* @author Valiantsin Krus
Expand Down
Loading

0 comments on commit 8829c89

Please sign in to comment.