Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.core.notifications

fun checkSeverity(notificationSeverity: String): NotificationSeverity = when (notificationSeverity) {

Check warning on line 6 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/CustomizeNotificationsUi.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Function "checkSeverity" is never used

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Function "checkSeverity" is never used
"Critical" -> NotificationSeverity.CRITICAL
"Warning" -> NotificationSeverity.WARNING
"Info" -> NotificationSeverity.INFO
else -> NotificationSeverity.INFO
}

// TODO: Add actions that can be performed from the notifications here
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.core.notifications

import com.intellij.openapi.project.Project

Check warning on line 6 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/DisplayToastNotifications.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

object DisplayToastNotifications {}

Check notice on line 8 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/DisplayToastNotifications.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Replace empty class body

Redundant empty class body

Check warning on line 8 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/DisplayToastNotifications.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Object "DisplayToastNotifications" is never used
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.core.notifications

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonToken
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonMappingException
import com.fasterxml.jackson.databind.JsonNode

class OperationConditionDeserializer : JsonDeserializer<NotificationExpression.OperationCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.OperationCondition = when (parser.currentToken) {
JsonToken.VALUE_STRING -> {
// Handle direct string value
NotificationExpression.OperationCondition(parser.valueAsString)
}
else -> throw JsonMappingException(parser, "Cannot deserialize OperatingCondition")
}
}

class ComparisonConditionDeserializer : JsonDeserializer<NotificationExpression.ComparisonCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.ComparisonCondition {
val op = OperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.ComparisonCondition(op.value)
}
}

class NotEqualsConditionDeserializer : JsonDeserializer<NotificationExpression.NotEqualsCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.NotEqualsCondition {
val op = OperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.NotEqualsCondition(op.value)
}
}
class GreaterThanConditionDeserializer : JsonDeserializer<NotificationExpression.GreaterThanCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.GreaterThanCondition {
val op = OperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.GreaterThanCondition(op.value)
}
}
class GreaterThanOrEqualsConditionDeserializer : JsonDeserializer<NotificationExpression.GreaterThanOrEqualsCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.GreaterThanOrEqualsCondition {
val op = OperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.GreaterThanOrEqualsCondition(op.value)
}
}
class LessThanConditionDeserializer : JsonDeserializer<NotificationExpression.LessThanCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.LessThanCondition {
val op = OperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.LessThanCondition(op.value)
}
}
class LessThanOrEqualsConditionDeserializer : JsonDeserializer<NotificationExpression.LessThanOrEqualsCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.LessThanOrEqualsCondition {
val op = OperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.LessThanOrEqualsCondition(op.value)
}
}
class ComplexOperationConditionDeserializer : JsonDeserializer<NotificationExpression.ComplexOperationCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.ComplexOperationCondition {
val node = parser.codec.readTree<JsonNode>(parser)
if (!node.isArray) {
throw JsonMappingException(parser, "anyOf/noneOf must contain an array of values")
}
val values = node.map { it.asText() }
return NotificationExpression.ComplexOperationCondition(values)
}
}
class AnyOfConditionDeserializer : JsonDeserializer<NotificationExpression.AnyOfCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.AnyOfCondition {
val op = ComplexOperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.AnyOfCondition(op.value)
}
}

class NoneOfConditionDeserializer : JsonDeserializer<NotificationExpression.NoneOfCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.NoneOfCondition {
val op = ComplexOperationConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.NoneOfCondition(op.value)
}
}

class ComplexConditionDeserializer : JsonDeserializer<NotificationExpression.ComplexCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.ComplexCondition {
val node = parser.codec.readTree<JsonNode>(parser)
if (!node.isArray) {
throw JsonMappingException(parser, "or/and must contain an array of values")
}
return NotificationExpression.ComplexCondition(node.toNotificationExpressions(parser))
}
}
class OrConditionDeserializer : JsonDeserializer<NotificationExpression.OrCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.OrCondition {
val op = ComplexConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.OrCondition(op.expectedValueList)
}
}

class AndConditionDeserializer : JsonDeserializer<NotificationExpression.AndCondition>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): NotificationExpression.AndCondition {
val op = ComplexConditionDeserializer().deserialize(parser, ctxt)
return NotificationExpression.AndCondition(op.expectedValueList)
}
}

class NotConditionDeserializer : JsonDeserializer<NotificationExpression.NotCondition>() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): NotificationExpression.NotCondition {
val node = p.codec.readTree<JsonNode>(p)
val parser = node.traverse(p.codec)
parser.nextToken()

return NotificationExpression.NotCondition(parser.readValueAs(NotificationExpression::class.java))
}
}

private fun JsonNode.toNotificationExpressions(p: JsonParser): List<NotificationExpression> = this.map { element ->
val parser = element.traverse(p.codec)
parser.nextToken()
parser.readValueAs(NotificationExpression::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.core.notifications

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.databind.annotation.JsonDeserialize

data class NotificationsList(
val schema: Schema,
val notifications: List<NotificationData>?,
)

data class Schema(
val version: String,
)

data class NotificationData(
val id: String,
val schedule: NotificationSchedule,
val severity: String,
val condition: NotificationDisplayCondition?,
val content: NotificationContentDescriptionLocale,
val actions: List<NotificationFollowupActions>? = emptyList(),
)

data class NotificationSchedule(
val type: String,
)

enum class NotificationSeverity {
INFO,
WARNING,
CRITICAL,
}

data class NotificationContentDescriptionLocale(
@JsonProperty("en-US")
val locale: NotificationContentDescription,
)

data class NotificationContentDescription(
val title: String,
val description: String,
)

data class NotificationFollowupActions(
val type: String,
val content: NotificationFollowupActionsContent,
)

data class NotificationFollowupActionsContent(
@JsonProperty("en-US")
val locale: NotificationActionDescription,
)

data class NotificationActionDescription(
val title: String,
val url: String?,
)

data class NotificationDisplayCondition(
val compute: ComputeType?,
val os: SystemType?,
val ide: SystemType?,
val extension: List<ExtensionType>?,
val authx: List<AuthxType>?,
)

data class ComputeType(
val type: NotificationExpression?,
val architecture: NotificationExpression?,
)

data class SystemType(
val type: NotificationExpression?,
val version: NotificationExpression?,
)

data class ExtensionType(
val id: String?,
val version: NotificationExpression?,
)

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.WRAPPER_OBJECT
)
@JsonSubTypes(
JsonSubTypes.Type(value = NotificationExpression.ComparisonCondition::class, name = "=="),
JsonSubTypes.Type(value = NotificationExpression.NotEqualsCondition::class, name = "!="),
JsonSubTypes.Type(value = NotificationExpression.GreaterThanCondition::class, name = ">"),
JsonSubTypes.Type(value = NotificationExpression.GreaterThanOrEqualsCondition::class, name = ">="),
JsonSubTypes.Type(value = NotificationExpression.LessThanCondition::class, name = "<"),
JsonSubTypes.Type(value = NotificationExpression.LessThanOrEqualsCondition::class, name = "<="),
JsonSubTypes.Type(value = NotificationExpression.AnyOfCondition::class, name = "anyOf"),
JsonSubTypes.Type(value = NotificationExpression.NotCondition::class, name = "not"),
JsonSubTypes.Type(value = NotificationExpression.OrCondition::class, name = "or"),
JsonSubTypes.Type(value = NotificationExpression.AndCondition::class, name = "and"),
JsonSubTypes.Type(value = NotificationExpression.NoneOfCondition::class, name = "noneOf")
)
sealed interface NotificationExpression {
@JsonDeserialize(using = NotConditionDeserializer::class)
data class NotCondition(
val expectedValue: NotificationExpression,
) : NotificationExpression

@JsonDeserialize(using = OrConditionDeserializer::class)
data class OrCondition(
val expectedValueList: List<NotificationExpression>,
) : NotificationExpression

@JsonDeserialize(using = AndConditionDeserializer::class)
data class AndCondition(
val expectedValueList: List<NotificationExpression>,
) : NotificationExpression

@JsonDeserialize(using = ComplexConditionDeserializer::class)
data class ComplexCondition(
val expectedValueList: List<NotificationExpression>,
) : NotificationExpression

// General class for comparison operators
@JsonDeserialize(using = OperationConditionDeserializer::class)
data class OperationCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = ComplexOperationConditionDeserializer::class)
data class ComplexOperationCondition(
val value: List<String>,
) : NotificationExpression

@JsonDeserialize(using = ComparisonConditionDeserializer::class)
data class ComparisonCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = NotEqualsConditionDeserializer::class)
data class NotEqualsCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = GreaterThanConditionDeserializer::class)
data class GreaterThanCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = GreaterThanOrEqualsConditionDeserializer::class)
data class GreaterThanOrEqualsCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = LessThanConditionDeserializer::class)
data class LessThanCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = LessThanOrEqualsConditionDeserializer::class)
data class LessThanOrEqualsCondition(
val value: String,
) : NotificationExpression

@JsonDeserialize(using = AnyOfConditionDeserializer::class)
data class AnyOfCondition(
val value: List<String>,
) : NotificationExpression

@JsonDeserialize(using = NoneOfConditionDeserializer::class)
data class NoneOfCondition(
val value: List<String>,
) : NotificationExpression
}

data class AuthxType(
val feature: String,
val type: NotificationExpression?,
val region: NotificationExpression?,
val connectionState: NotificationExpression?,
val ssoScopes: NotificationExpression?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package software.aws.toolkits.jetbrains.core.notifications

import com.intellij.openapi.project.Project

class ProcessNotificationsBase {
init {
// TODO: install a listener for the polling class
Expand All @@ -17,8 +19,11 @@
// iterates through the 2 lists and processes each notification(if it isn't dismissed)
}

fun processNotification() {
// TODO: calls the Rule engine and notifies listeners
fun processNotification(project: Project, notificationData: NotificationData) {
val shouldShow = RulesEngine.displayNotification(project, notificationData)
if(shouldShow) {

Check warning on line 24 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/ProcessNotificationsBase.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Control flow with empty body

'if' has empty body

Check warning

Code scanning / QDJVMC

Control flow with empty body Warning

'if' has empty body
// TODO: notifies listeners
}
}

fun notifyListenerForNotification() {
Expand Down
Loading
Loading