Skip to content

Commit

Permalink
Merge branch 'feature/IJMP-1537' into 'release/v1.2.0-221'
Browse files Browse the repository at this point in the history
IJMP-1537: move tasks from 2.0.0 to 1.2.0

See merge request ijmp/for-mainframe!491
  • Loading branch information
Dzianis Lisiankou committed Mar 15, 2024
2 parents 41f94ec + 60c1457 commit f5bd87d
Show file tree
Hide file tree
Showing 15 changed files with 398 additions and 488 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 eu.ibagroup.formainframe.common

import java.util.*

class SettingsPropertyManager

/**
* Properties from the settings.properties file
*/
internal val settingsProperties by lazy {
Properties().apply {
load(SettingsPropertyManager::class.java.classLoader.getResourceAsStream("settings.properties"))
}
}

/**
* Check if the debug mode is enabled
*/
fun isDebugModeEnabled(): Boolean {
return settingsProperties.getProperty("debug.mode")?.toBoolean() ?: false
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ import eu.ibagroup.formainframe.ui.build.tso.config.TSOConfigWrapper
import eu.ibagroup.formainframe.ui.build.tso.ui.TSOSessionParams
import eu.ibagroup.formainframe.utils.cancelByIndicator
import eu.ibagroup.formainframe.utils.log
import eu.ibagroup.formainframe.dataops.operations.MessageType as MessageTypeEnum
import org.zowe.kotlinsdk.MessageType
import org.zowe.kotlinsdk.TsoApi
import org.zowe.kotlinsdk.TsoData
import org.zowe.kotlinsdk.TsoResponse
import io.ktor.util.*
import retrofit2.Response
import java.nio.charset.Charset
import java.util.*

/**
* Factory class which represents a TSO operation runner. Defined in plugin.xml
Expand Down Expand Up @@ -85,12 +84,7 @@ class TsoOperationRunner : OperationRunner<TsoOperation, TsoResponse> {
response = api<TsoApi>(state.getConnectionConfig())
.sendMessageToTso(
state.getConnectionConfig().authToken,
body = TsoData(
tsoResponse = MessageType(
version = "0100",
data = operation.message
)
),
body = createTsoData(operation),
servletKey = servletKey
)
.cancelByIndicator(progressIndicator)
Expand Down Expand Up @@ -140,4 +134,51 @@ class TsoOperationRunner : OperationRunner<TsoOperation, TsoResponse> {
return response?.body() ?: throw Exception("Cannot retrieve response from server.")
}

/**
* Create TsoData object depending on the specified message type
* @throws Exception if message type not specified
*/
private fun createTsoData(operation: TsoOperation): TsoData {
return when (operation.messageType) {
MessageTypeEnum.TSO_MESSAGE -> TsoData(
tsoMessage = createMessageType(operation)
)

MessageTypeEnum.TSO_PROMPT -> TsoData(
tsoPrompt = createMessageType(operation)
)

MessageTypeEnum.TSO_RESPONSE -> TsoData(
tsoResponse = createMessageType(operation)
)

null -> throw Exception("Message type not specified")
}
}

/**
* Create MessageType object depending on the specified message data
* @throws Exception if message data not specified
*/
private fun createMessageType(operation: TsoOperation): MessageType {
return when (operation.messageData) {
MessageData.DATA_DATA -> MessageType(
version = "0100",
data = operation.message
)

MessageData.DATA_HIDDEN -> MessageType(
version = "0100",
hidden = operation.message
)

MessageData.DATA_ACTION -> MessageType(
version = "0100",
action = operation.message
)

null -> throw Exception("Message data not specified")
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@

package eu.ibagroup.formainframe.explorer.actions

import com.intellij.notification.Notification
import com.intellij.notification.NotificationAction
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.components.service
import com.intellij.openapi.progress.runModalTask
import com.intellij.openapi.ui.showOkNoDialog
import eu.ibagroup.formainframe.analytics.AnalyticsService
import eu.ibagroup.formainframe.analytics.events.FileAction
import eu.ibagroup.formainframe.analytics.events.FileEvent
Expand All @@ -28,6 +30,7 @@ import eu.ibagroup.formainframe.config.ws.FilesWorkingSetConfig
import eu.ibagroup.formainframe.dataops.DataOpsManager
import eu.ibagroup.formainframe.dataops.operations.DatasetAllocationOperation
import eu.ibagroup.formainframe.dataops.operations.DatasetAllocationParams
import eu.ibagroup.formainframe.explorer.ExplorerUnit
import eu.ibagroup.formainframe.explorer.FilesWorkingSet
import eu.ibagroup.formainframe.explorer.ui.AllocationDialog
import eu.ibagroup.formainframe.explorer.ui.DSMaskNode
Expand All @@ -44,6 +47,8 @@ import org.zowe.kotlinsdk.Dataset
import org.zowe.kotlinsdk.DatasetOrganization
import org.zowe.kotlinsdk.DsnameType

const val ALLOCATE_ACTION_NOTIFICATION_GROUP_ID = "eu.ibagroup.formainframe.explorer.AllocateActionNotificationGroup"

abstract class AllocateActionBase : AnAction() {

/**
Expand Down Expand Up @@ -140,34 +145,10 @@ abstract class AllocateActionBase : AnAction() {
}
val nodeToClean = parentProbablyDSMaskNode?.castOrNull<FileFetchNode<*, *, *, *, *, *>>()
nodeToClean?.let { cleanInvalidateOnExpand(nodeToClean, view) }

var nodeCleaned = false
runInEdt {
if (
showOkNoDialog(
title = "Dataset ${state.datasetName} Has Been Created",
message = "Would you like to add mask \"${state.datasetName}\" to ${workingSet.name}",
project = e.project,
okText = "Yes",
noText = "No"
)
) {
val filesWorkingSetConfig =
configCrudable.getByUniqueKey<FilesWorkingSetConfig>(workingSet.uuid)?.clone()
if (filesWorkingSetConfig != null) {
nodeToClean?.cleanCache(recursively = false, cleanBatchedQuery = true, sendTopic = false)
nodeCleaned = true

filesWorkingSetConfig.dsMasks.add(DSMask().apply { mask = state.datasetName })
configCrudable.update(filesWorkingSetConfig)
}
}

if (!nodeCleaned) {
nodeToClean?.cleanCache(recursively = false, cleanBatchedQuery = true)
}
}
nodeToClean?.cleanCache(recursively = false, cleanBatchedQuery = true)
initialState.errorMessage = ""

showNotification(state, workingSet)
}
.onFailure { t ->
explorer.reportThrowable(t, e.project)
Expand All @@ -187,4 +168,34 @@ abstract class AllocateActionBase : AnAction() {
override fun isDumbAware(): Boolean {
return true
}

/**
* Shows a notification about successful allocation and suggest adding a mask to the working set
*/
private fun showNotification(
state: DatasetAllocationParams,
workingSet: ExplorerUnit<*>
) {
val notification = Notification(
ALLOCATE_ACTION_NOTIFICATION_GROUP_ID,
"Dataset ${state.datasetName} has been created",
"Would you like to add mask \"${state.datasetName}\" to ${workingSet.name}?",
NotificationType.INFORMATION
)
notification.addActions(
setOf(
NotificationAction.createSimpleExpiring("Add mask") {
val filesWorkingSetConfig =
configCrudable.getByUniqueKey<FilesWorkingSetConfig>(workingSet.uuid)?.clone()
if (filesWorkingSetConfig != null) {
filesWorkingSetConfig.dsMasks.add(DSMask().apply { mask = state.datasetName })
configCrudable.update(filesWorkingSetConfig)
}
},
NotificationAction.createSimpleExpiring("Skip") { }
)
)
notification.setSuggestionType(true)
Notifications.Bus.notify(notification)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.intellij.ui.dsl.builder.panel
import com.intellij.ui.dsl.builder.toNullableProperty
import com.intellij.ui.dsl.gridLayout.HorizontalAlign
import com.intellij.ui.layout.selectedValueMatches
import eu.ibagroup.formainframe.common.message
import eu.ibagroup.formainframe.common.ui.StatefulDialog
import eu.ibagroup.formainframe.config.connect.ConnectionConfig
import eu.ibagroup.formainframe.config.connect.getUsername
Expand Down Expand Up @@ -133,6 +134,10 @@ class AllocationDialog(project: Project?, config: ConnectionConfig, override var
.bindItem(state.allocationParameters::allocationUnit.toNullableProperty())
.also { spaceUnitBox = it.component }
.widthGroup(sameWidthComboBoxGroup)
contextHelp(
description = message("allocation.dialog.unit.size.hint.description"),
title = message("allocation.dialog.unit.size.hint.title")
)
}
row {
label("Primary allocation: ")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package eu.ibagroup.formainframe.ui.build
import com.intellij.execution.process.NopProcessHandler
import com.intellij.execution.process.ProcessHandler
import com.intellij.execution.process.ProcessOutputType
import com.intellij.openapi.util.Key
import com.intellij.terminal.TerminalExecutionConsole
import com.jediterm.terminal.TerminalKeyEncoder
import eu.ibagroup.formainframe.ui.build.tso.utils.InputRecognizer
Expand All @@ -33,6 +34,7 @@ class TerminalCommandReceiver(terminalConsole: TerminalExecutionConsole) {
private var needToWaitForCommandInput = false
private var commandsInQueue: Queue<String> = LinkedList()
private var expectParameters = false
private var prevCommandEndsWithReady = false
var initialized = false

private var onCommandEntered: (String) -> Unit = {}
Expand Down Expand Up @@ -146,15 +148,34 @@ class TerminalCommandReceiver(terminalConsole: TerminalExecutionConsole) {
override fun getProcessInput(): OutputStream {
return this@TerminalCommandReceiver.processInput
}

/**
* Override notifyTextAvailable() method to check what the command ends with
*/
override fun notifyTextAvailable(text: String, outputType: Key<*>) {
if (text != "\n" && text.endsWith("\n")) {
prevCommandEndsWithReady = isTextEndsWithReady(text)
}
super.notifyTextAvailable(text, outputType)
}
}
terminalConsole.withConvertLfToCrlfForNonPtyProcess(true)
terminalConsole.attachToProcess(processHandler)
}

/**
* Check if the text ends with "READY" - successful completion of TSO command
*/
private fun isTextEndsWithReady(text: String): Boolean {
val successfulEnding = "READY"
val trimmedText = text.trimEnd()
return trimmedText.endsWith(successfulEnding, true)
}

/**
* Called when command is submitted. Clean up the entered command for follow up user input
*/
private fun cleanCommand() {
fun cleanCommand() {
this.typedCommand = ""
this.textAfterCursor = ""
this.cursorPosition = 0
Expand Down Expand Up @@ -193,6 +214,20 @@ class TerminalCommandReceiver(terminalConsole: TerminalExecutionConsole) {
}
}

/**
* Return true if console is waiting for command input or else otherwise
*/
fun isNeedToWaitForCommandInput(): Boolean {
return needToWaitForCommandInput
}

/**
* Return true if previous command ends with "READY" or else otherwise
*/
fun isPrevCommandEndsWithReady(): Boolean {
return prevCommandEndsWithReady
}

/**
* Called when user finished typing the command and pressed Enter
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ class TSOWindowFactory : ToolWindowFactory {
try {
sendTopic(SESSION_RECONNECT_TOPIC, project).reconnect(project, console, session)
processHandler.notifyTextAvailable(
"Successfully reconnected to the TSO session.\n",
"Successfully reconnected to the TSO session.\nREADY\n",
ProcessOutputType.STDOUT
)
} catch (e: Exception) {
Expand Down
Loading

0 comments on commit f5bd87d

Please sign in to comment.