Skip to content

Commit

Permalink
feat: allow to disable editor notifications (redhat-developer#763)
Browse files Browse the repository at this point in the history
Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish committed Oct 3, 2024
1 parent 9c69e50 commit 2742a2e
Show file tree
Hide file tree
Showing 10 changed files with 639 additions and 284 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ open class EditorResource(
private val resourceModel: IResourceModel,
private val resourceChangedListener: IResourceModelListener?,
// for mocking purposes
private val clusterResourceFactory: (resource: HasMetadata, context: IActiveContext<out HasMetadata, out KubernetesClient>?) -> ClusterResource? =
private val clusterResourceFactory: (
resource: HasMetadata,
context: IActiveContext<out HasMetadata, out KubernetesClient>?
) -> ClusterResource? =
ClusterResource.Factory::create
) {
var disposed: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,16 @@ import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.observable.properties.AtomicBooleanProperty
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.util.messages.MessageBusConnection
import com.redhat.devtools.intellij.common.utils.MetadataClutter
import com.redhat.devtools.intellij.common.validation.KubernetesResourceInfo
import com.redhat.devtools.intellij.kubernetes.editor.notification.DeletedNotification
import com.redhat.devtools.intellij.kubernetes.editor.notification.ErrorNotification
import com.redhat.devtools.intellij.kubernetes.editor.notification.PullNotification
import com.redhat.devtools.intellij.kubernetes.editor.notification.PulledNotification
import com.redhat.devtools.intellij.kubernetes.editor.notification.PushNotification
import com.redhat.devtools.intellij.kubernetes.editor.notification.PushedNotification
import com.redhat.devtools.intellij.kubernetes.editor.notification.Notifications
import com.redhat.devtools.intellij.kubernetes.editor.util.getDocument
import com.redhat.devtools.intellij.kubernetes.editor.util.isKubernetesResource
import com.redhat.devtools.intellij.kubernetes.model.IResourceModel
Expand All @@ -39,6 +36,8 @@ import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
import com.redhat.devtools.intellij.kubernetes.model.util.toTitle
import com.redhat.devtools.intellij.kubernetes.settings.SettingsChangeListener
import com.redhat.devtools.intellij.kubernetes.settings.SettingsConfigurable
import io.fabric8.kubernetes.api.model.HasMetadata
import java.util.concurrent.CompletableFuture

Expand All @@ -57,18 +56,7 @@ open class ResourceEditor(
// for mocking purposes
private val createResourceFileForVirtual: (file: VirtualFile?) -> ResourceFile? =
ResourceFile.Factory::create,
// for mocking purposes
private val pushNotification: PushNotification = PushNotification(editor, project),
// for mocking purposes
private val pushedNotification: PushedNotification = PushedNotification(editor, project),
// for mocking purposes
private val pullNotification: PullNotification = PullNotification(editor, project),
// for mocking purposes
private val pulledNotification: PulledNotification = PulledNotification(editor, project),
// for mocking purposes
private val deletedNotification: DeletedNotification = DeletedNotification(editor, project),
// for mocking purposes
private val errorNotification: ErrorNotification = ErrorNotification(editor, project),
private val notifications: Notifications = Notifications(editor, project),
// for mocking purposes
private val getDocument: (FileEditor) -> Document? = ::getDocument,
// for mocking purposes
Expand All @@ -81,14 +69,18 @@ open class ResourceEditor(
// for mocking purposes
private val diff: ResourceDiff = ResourceDiff(project),
// for mocking purposes
protected val editorResources: EditorResources = EditorResources(resourceModel)
protected val editorResources: EditorResources = EditorResources(resourceModel),
private val connection: MessageBusConnection = ApplicationManager.getApplication().messageBus.connect()
) : Disposable {

init {
Disposer.register(editor, this)
editorResources.resourceChangedListener = onResourceChanged()
resourceModel.addListener(onNamespaceOrContextChanged())
runAsync { enableEditingNonProjectFile() }
runAsync {
enableEditingNonProjectFile()
connection.subscribe(SettingsChangeListener.CHANGED, onSettingsChanged())
}
}

companion object {
Expand All @@ -98,6 +90,7 @@ open class ResourceEditor(
}

private var onNamespaceContextChanged: IResourceModelListener = onNamespaceOrContextChanged()
private var syncEnabled = AtomicBooleanProperty(false)

/**
* Updates this editor notifications and title.
Expand All @@ -117,15 +110,15 @@ open class ResourceEditor(
if (editorResources.size == 1) {
// show notification for 1 resource
val editorResource = editorResources.firstOrNull() ?: return@runAsync
showNotification(editorResource)
notifications.show(editorResource)
} else if (editorResources.size > 1) {
// show notification for multiple resources
showNotification(editorResources)
notifications.show(editorResources)
}
} catch (e: Exception) {
runInUI {
hideNotifications()
errorNotification.show(
notifications.hideAll()
notifications.showError(
toTitle(e),
toMessage(e.cause)
)
Expand All @@ -134,108 +127,14 @@ open class ResourceEditor(
}
}

open protected fun updateDeleted(deleted: HasMetadata?) {
protected open fun updateDeleted(deleted: HasMetadata?) {
if (deleted == null) {
return
}
editorResources.setDeleted(deleted)
update()
}

private fun showNotification(editorResource: EditorResource) {
val state = editorResource.getState()
val resource = editorResource.getResource()
when (state) {
is Error ->
showErrorNotification(state.title, state.message)
is Pushed ->
showPushedNotification(listOf(editorResource))
is DeletedOnCluster ->
showDeletedNotification(resource)
/**
* avoid too many notifications, don't notify outdated
is Outdated ->
showPullNotification(resource)
*/
is Modified ->
showPushNotification(true, listOf(editorResource))

else ->
runInUI {
hideNotifications()
}
}
}

private fun showNotification(editorResources: Collection<EditorResource>) {
val toPush = editorResources.filter(FILTER_TO_PUSH)
if (toPush.isNotEmpty()) {
showPushNotification(false, toPush)
return
}
val inError = editorResources.filter(FILTER_ERROR)
if (inError.isNotEmpty()) {
showErrorNotification(inError)
} else {
runInUI {
hideNotifications()
}
}
}

private fun showErrorNotification(title: String, message: String?) {
runInUI {
hideNotifications()
errorNotification.show(title, message)
}
}

private fun showErrorNotification(editorResources: Collection<EditorResource>) {
val inError = editorResources.filter(FILTER_ERROR)
val toDisplay = inError.firstOrNull()?.getState() as? Error ?: return
showErrorNotification(toDisplay.title, toDisplay.message)
}

private fun showPushNotification(showPull: Boolean, editorResources: Collection<EditorResource>) {
runInUI {
// hide & show in the same UI thread runnable avoid flickering
hideNotifications()
pushNotification.show(showPull, editorResources)
}
}

private fun showPushedNotification(editorResources: Collection<EditorResource>) {
runInUI {
// hide & show in the same UI thread runnable avoid flickering
hideNotifications()
pushedNotification.show(editorResources)
}
}

private fun showPullNotification(resource: HasMetadata) {
runInUI {
hideNotifications()
pullNotification.show(resource)
}
}

private fun showDeletedNotification(resource: HasMetadata) {
runInUI {
// hide & show in the same UI thread runnable avoid flickering
hideNotifications()
deletedNotification.show(resource)
}
}

private fun hideNotifications() {
errorNotification.hide()
pullNotification.hide()
deletedNotification.hide()
pushNotification.hide()
pushedNotification.hide()
pulledNotification.hide()
}

/**
* Pulls the resource from the cluster and replaces the content of this editor.
* Does nothing if it doesn't exist.
Expand All @@ -248,7 +147,7 @@ open class ResourceEditor(
}
runInUI {
// hide before running pull. Pull may take quite some time on remote cluster
hideNotifications()
notifications.hideAll()
}
val resource = resources.firstOrNull() ?: return

Expand Down Expand Up @@ -293,7 +192,7 @@ open class ResourceEditor(
fun push(all: Boolean) {
runInUI {
// hide before running push. Push may take quite some time on remote cluster
hideNotifications()
notifications.hideAll()
}
runAsync {
if (all) {
Expand Down Expand Up @@ -370,7 +269,7 @@ open class ResourceEditor(
}
runInUI {
replaceDocument(resources)
hideNotifications()
notifications.hideAll()
}
}

Expand Down Expand Up @@ -408,6 +307,9 @@ open class ResourceEditor(
}

override fun modified(modified: Any) {
if (syncEnabled.get()) {
return
}
update()
}
}
Expand All @@ -431,6 +333,27 @@ open class ResourceEditor(
}
}

protected open fun onSettingsChanged(): SettingsChangeListener {
return object : SettingsChangeListener {
override fun changed(property: String, value: String?) {
if (value == null) {
return
}

if (SettingsConfigurable.EDITOR_SYNC_DISABLED == property) {
val enabled = value.toBoolean()
syncEnabled.set(enabled)
if (enabled) {
update()
} else {
editorResources.stopWatchAll()
notifications.hideSyncNotifications()
}
}
}
}
}

/**
* Closes this instance and cleans up references to it.
* - Removes the resource model listener,
Expand Down Expand Up @@ -496,5 +419,6 @@ open class ResourceEditor(
override fun dispose() {
resourceModel.removeListener(onNamespaceContextChanged)
editorResources.dispose()
connection.dispose()
}
}
Loading

0 comments on commit 2742a2e

Please sign in to comment.