From 5bc9cd5ae96ffcd4a8e56fa631125501eb4ea0e5 Mon Sep 17 00:00:00 2001 From: Vivek Ranjan Date: Sat, 8 Jul 2023 06:48:39 -0400 Subject: [PATCH] MAK-59 IJ: Tool window to show calendar events --- CHANGELOG.md | 2 + .../co/makerflow/client/apis/EventsApi.kt | 57 ++-- .../makerflow/client/models/CalendarEvent.kt | 32 +- .../co/makerflow/client/models/Conference.kt | 20 +- .../client/models/ConferenceEntryPoint.kt | 8 +- .../UpcomingCalendarEvents200Response.kt | 33 ++ .../panels/CalendarEventsPanel.kt | 312 ++++++++++++++++++ .../panels/CalendarEventsToolWindowFactory.kt | 18 + .../panels/TasksToolWindowFactory.kt | 4 +- .../intellijplugin/services/EventsService.kt | 61 ++++ .../intellijplugin/state/FlowState.kt | 1 - src/main/resources/META-INF/plugin.xml | 2 + 12 files changed, 493 insertions(+), 57 deletions(-) create mode 100644 src/main/kotlin/co/makerflow/client/models/UpcomingCalendarEvents200Response.kt create mode 100644 src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsPanel.kt create mode 100644 src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsToolWindowFactory.kt create mode 100644 src/main/kotlin/co/makerflow/intellijplugin/services/EventsService.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index d51de89..08efdf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ track of all your notifications. - See all your notifications from GitHub/Bitbucket in your IDE - Add new tasks - Start Flow Mode for a task to focus on it +- Added a tool window to see your calendar events for the next few hours + - Join an upcoming event with one click ### Changed diff --git a/src/main/kotlin/co/makerflow/client/apis/EventsApi.kt b/src/main/kotlin/co/makerflow/client/apis/EventsApi.kt index f22d4c2..81933e5 100644 --- a/src/main/kotlin/co/makerflow/client/apis/EventsApi.kt +++ b/src/main/kotlin/co/makerflow/client/apis/EventsApi.kt @@ -15,54 +15,55 @@ package co.makerflow.client.apis -import co.makerflow.client.models.CalendarEvent - -import co.makerflow.client.infrastructure.* +import co.makerflow.client.infrastructure.ApiClient +import co.makerflow.client.infrastructure.HttpResponse +import co.makerflow.client.infrastructure.RequestConfig +import co.makerflow.client.infrastructure.RequestMethod +import co.makerflow.client.infrastructure.wrap +import co.makerflow.client.models.UpcomingCalendarEvents200Response +import com.fasterxml.jackson.databind.ObjectMapper import io.ktor.client.HttpClientConfig -import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.http.ParametersBuilder -import com.fasterxml.jackson.databind.ObjectMapper - open class EventsApi( +open class EventsApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { +) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { - /** - * - * - * @param source To specify source of request (optional) - * @return kotlin.collections.List - */ - @Suppress("UNCHECKED_CAST") - open suspend fun upcomingCalendarEvents(source: kotlin.String?): HttpResponse> { + /** + * + * + * @param source To specify source of request (optional) + * @return UpcomingCalendarEvents200Response + */ + @Suppress("UNCHECKED_CAST") + open suspend fun upcomingCalendarEvents(source: kotlin.String?): HttpResponse { - val localVariableAuthNames = listOf("api_token") + val localVariableAuthNames = listOf("api_token") - val localVariableBody = - io.ktor.client.utils.EmptyContent + val localVariableBody = + io.ktor.client.utils.EmptyContent - val localVariableQuery = mutableMapOf>() - source?.apply { localVariableQuery["source"] = listOf("$source") } + val localVariableQuery = mutableMapOf>() + source?.apply { localVariableQuery["source"] = listOf("$source") } - val localVariableHeaders = mutableMapOf() + val localVariableHeaders = mutableMapOf() - val localVariableConfig = RequestConfig( + val localVariableConfig = RequestConfig( RequestMethod.GET, "/tasks/calendar/events", query = localVariableQuery, headers = localVariableHeaders, requiresAuthentication = true, - ) + ) - return request( + return request( localVariableConfig, localVariableBody, localVariableAuthNames - ).wrap() - } + ).wrap() + } - } +} diff --git a/src/main/kotlin/co/makerflow/client/models/CalendarEvent.kt b/src/main/kotlin/co/makerflow/client/models/CalendarEvent.kt index 629b5b9..9e5e48d 100644 --- a/src/main/kotlin/co/makerflow/client/models/CalendarEvent.kt +++ b/src/main/kotlin/co/makerflow/client/models/CalendarEvent.kt @@ -15,27 +15,28 @@ package co.makerflow.client.models -import co.makerflow.client.models.Conference - +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty /** * A event in user's calendar * - * @param id - * @param userIntegrationId - * @param iCalUID - * @param start - * @param startTimezone - * @param end - * @param endTimezone - * @param summary - * @param htmlLink - * @param conference + * @param id + * @param userIntegrationId + * @param iCalUID + * @param start + * @param startTimezone + * @param end + * @param endTimezone + * @param summary + * @param htmlLink + * @param conference + * @param providerId */ -data class CalendarEvent ( +@JsonIgnoreProperties(ignoreUnknown = true) +data class CalendarEvent( @field:JsonProperty("id") val id: kotlin.Int? = null, @@ -65,7 +66,10 @@ data class CalendarEvent ( val htmlLink: kotlin.String? = null, @field:JsonProperty("conference") - val conference: Conference? = null + val conference: Conference? = null, + + @field:JsonProperty("provider_id") + val providerId: kotlin.String? = null ) diff --git a/src/main/kotlin/co/makerflow/client/models/Conference.kt b/src/main/kotlin/co/makerflow/client/models/Conference.kt index 6e39757..aedb372 100644 --- a/src/main/kotlin/co/makerflow/client/models/Conference.kt +++ b/src/main/kotlin/co/makerflow/client/models/Conference.kt @@ -15,23 +15,23 @@ package co.makerflow.client.models -import co.makerflow.client.models.ConferenceEntryPoint - +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty /** - * * - * @param conferenceId - * @param location - * @param organizerEmail - * @param organizerName - * @param status - * @param entryPoints + * + * @param conferenceId + * @param location + * @param organizerEmail + * @param organizerName + * @param status + * @param entryPoints */ -data class Conference ( +@JsonIgnoreProperties(ignoreUnknown = true) +data class Conference( @field:JsonProperty("conferenceId") val conferenceId: kotlin.String? = null, diff --git a/src/main/kotlin/co/makerflow/client/models/ConferenceEntryPoint.kt b/src/main/kotlin/co/makerflow/client/models/ConferenceEntryPoint.kt index 4ec3159..3974b19 100644 --- a/src/main/kotlin/co/makerflow/client/models/ConferenceEntryPoint.kt +++ b/src/main/kotlin/co/makerflow/client/models/ConferenceEntryPoint.kt @@ -16,17 +16,19 @@ package co.makerflow.client.models +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty /** * Information about calling into the meeting * - * @param entryPointType - * @param label - * @param uri + * @param entryPointType + * @param label + * @param uri */ +@JsonIgnoreProperties(ignoreUnknown = true) data class ConferenceEntryPoint ( @field:JsonProperty("entryPointType") diff --git a/src/main/kotlin/co/makerflow/client/models/UpcomingCalendarEvents200Response.kt b/src/main/kotlin/co/makerflow/client/models/UpcomingCalendarEvents200Response.kt new file mode 100644 index 0000000..c47c367 --- /dev/null +++ b/src/main/kotlin/co/makerflow/client/models/UpcomingCalendarEvents200Response.kt @@ -0,0 +1,33 @@ +/** + * + * Please note: + * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + * + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package co.makerflow.client.models + +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * + * + * @param events + */ + + +data class UpcomingCalendarEvents200Response ( + + @field:JsonProperty("events") + val events: kotlin.collections.List? = null + +) + diff --git a/src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsPanel.kt b/src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsPanel.kt new file mode 100644 index 0000000..16d025f --- /dev/null +++ b/src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsPanel.kt @@ -0,0 +1,312 @@ +package co.makerflow.intellijplugin.panels + +import co.makerflow.client.models.CalendarEvent +import co.makerflow.intellijplugin.services.EventsService +import com.intellij.icons.AllIcons +import com.intellij.ide.BrowserUtil +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.service +import com.intellij.openapi.ui.DialogPanel +import com.intellij.openapi.ui.SimpleToolWindowPanel +import com.intellij.ui.JBColor +import com.intellij.ui.RoundedLineBorder +import com.intellij.ui.components.JBPanel +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.dsl.builder.Align +import com.intellij.ui.dsl.builder.AlignX +import com.intellij.ui.dsl.builder.BottomGap +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.Row +import com.intellij.ui.dsl.builder.RowLayout +import com.intellij.ui.dsl.builder.panel +import com.intellij.ui.dsl.gridLayout.Gaps +import com.intellij.util.concurrency.AppExecutorUtil +import com.intellij.util.ui.AsyncProcessIcon +import com.intellij.util.ui.JBUI +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.ocpsoft.prettytime.PrettyTime +import java.awt.Cursor +import java.awt.Dimension +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit +import java.util.concurrent.TimeUnit +import javax.swing.BoxLayout +import javax.swing.JButton +import javax.swing.JComponent +import javax.swing.JPanel +import javax.swing.border.CompoundBorder + + +private const val CONTENT_TOP_OFFSET = 10 +private const val DELAY_TO_RELOAD_EVENTS = 300L +private const val INITIAL_DELAY_TO_RELOAD_EVENTS = 60L + +class UpcomingEventsPanel : SimpleToolWindowPanel(true) { + + private val fetchEventsCoroutineScope = CoroutineScope(Dispatchers.IO) + private val loadingIconPanel = panel { + row { + cell( + AsyncProcessIcon.BigCentered("Loading events from calendar...") + ) + .align(Align.CENTER) + } + row { + label("Please wait, loading events from calendar...") + .align(Align.CENTER) + } + }.apply { + border = JBUI.Borders.empty() + alignmentX = CENTER_ALIGNMENT + } + private var container = JBPanel>().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add( + loadingIconPanel + ) + } + private val loadingMessageContent = JBScrollPane(container).apply { + border = JBUI.Borders.emptyTop(CONTENT_TOP_OFFSET) + } + + class ReloadAction(private val panel: UpcomingEventsPanel) : + AnAction("Reload", "Reload upcoming events", AllIcons.Actions.Refresh) { + override fun actionPerformed(e: AnActionEvent) { + panel.loadEvents() + } + + } + + val reloadAction = ReloadAction(this) + + init { + + super.setContent(loadingMessageContent) + + ApplicationManager.getApplication().invokeLater { + loadEvents() + } + + AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay({ + ApplicationManager.getApplication().invokeLater { + loadEvents() + } + }, INITIAL_DELAY_TO_RELOAD_EVENTS, DELAY_TO_RELOAD_EVENTS, TimeUnit.SECONDS) + + + } + + private fun loadEvents() { + val service = service() + fetchEventsCoroutineScope.launch { + val events = service.fetchEvents() + if (events.isEmpty()) { + ApplicationManager.getApplication().invokeLater { + val noEventsMessage = panel { + row { + label("No upcoming events, go get some sun!") + .align(Align.CENTER) + } + }.apply { + border = JBUI.Borders.empty() + alignmentX = CENTER_ALIGNMENT + } + super.setContent(JBScrollPane(noEventsMessage).apply { + border = JBUI.Borders.emptyTop(CONTENT_TOP_OFFSET) + }) + } + return@launch + } + ApplicationManager.getApplication().invokeLater { + val eventPresentationComponent = EventPresentationComponent() + val updatedContainer = JBPanel>() + // Set layout to BoxLayout to stack components vertically + updatedContainer.layout = BoxLayout(updatedContainer, BoxLayout.Y_AXIS) + events.forEach { + updatedContainer.add( + eventPresentationComponent.getComponent(it) + ) + } + super.setContent(JBScrollPane(updatedContainer).apply { + border = JBUI.Borders.empty() + }) + } + } + } + +} + + +private const val LIST_ITEM_PADDING_MARGIN = 5 +private const val ROUNDED_CORNER_RADIUS = 5 + +class EventPresentationComponent { + + fun getComponent(event: CalendarEvent): JComponent { + val eventPanel = EventPanel() + eventPanel.layout = BoxLayout(eventPanel, BoxLayout.Y_AXIS) + eventPanel.add(buildPanel(event)) + return eventPanel + } + + inner class EventPanel : JPanel() { + override fun getMaximumSize(): Dimension { + // Makes it so the height matches the content and width is the maximum available in parent + return Dimension(Int.MAX_VALUE, this.preferredSize.height) + } + } + + private fun buildPanel(event: CalendarEvent): DialogPanel { + val videoUri = event.conference?.entryPoints?.firstOrNull { it.entryPointType == "video" }?.uri + val panel = panel { + titleRow(event) + separator() + subTitleRow(event) + separator().visible(videoUri.isNullOrBlank().not()) + videoRow(event, videoUri) + } + panel.border = CompoundBorder( + JBUI.Borders.empty(LIST_ITEM_PADDING_MARGIN), // Outer border for padding around each item + CompoundBorder( + // Inner border for the gray line around each item + RoundedLineBorder(JBColor.GRAY, ROUNDED_CORNER_RADIUS), + // Innermost border for left and right margins + JBUI.Borders.empty(0, LIST_ITEM_PADDING_MARGIN) + ) + ) + panel.apply() + return panel + } + + @Suppress("unused", "kotlin:S125") + private fun Panel.videoRow(event: CalendarEvent, videoUri: String?) { + + row { + videoUri?.let { + button("Join Now") { + BrowserUtil.browse(videoUri) + }.applyToComponent { + icon = AllIcons.Ide.External_link_arrow + } + // joinOnStartButton(event, videoUri, p, start, now) + // Join on start button to be implemented as part of MAK-60 + } + } + .bottomGap(BottomGap.NONE).layout(RowLayout.PARENT_GRID) + .visible(videoUri.isNullOrBlank().not()) + } + + @Suppress("unused", "kotlin:S1144") + private fun Row.joinOnStartButton( + event: CalendarEvent, + videoUri: String + ) { + val start = Instant.parse(event.start).atZone(ZoneId.systemDefault()).toLocalDateTime() + val p = PrettyTime() + val now = LocalDateTime.now() + button("Join On Start") { + val sourceButton = it.source as JButton + if (sourceButton.isEnabled) { + // Difference between now and start in milliseconds + val delay = Instant.now().until(Instant.parse(event.start), ChronoUnit.MILLIS) + AppExecutorUtil.getAppScheduledExecutorService().schedule({ + BrowserUtil.browse(videoUri) + }, delay, TimeUnit.MILLISECONDS) + AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay({ + sourceButton.text = "Joining in ${p.format(start)}" + }, 0, 1, TimeUnit.SECONDS); + sourceButton.isEnabled = false + } + }.applyToComponent { + icon = AllIcons.Actions.BuildAutoReloadChanges + }.visible(start.isAfter(now)) + } + + private fun Panel.subTitleRow(event: CalendarEvent) { + val now = LocalDateTime.now() + val start = Instant.parse(event.start).atZone(ZoneId.systemDefault()).toLocalDateTime() + val end = Instant.parse(event.end).atZone(ZoneId.systemDefault()).toLocalDateTime() + val p = PrettyTime() + val pattern = DateTimeFormatter.ofPattern("HH:mm a") + val startInfo = "Start${if (start.isAfter(now)) "s" else "ed"} at ${start.format(pattern)} (${p.format(start)})" + val endInfo = "End${if (end.isAfter(now)) "s" else "ed"} at ${end.format(pattern)} (${p.format(end)})" + val timingInfo = "$startInfo | $endInfo" + row { + comment(timingInfo).customize(Gaps.EMPTY) + }.bottomGap(BottomGap.NONE) + } + + /** + * Provides a label that tells the user whether the event is from the past, ongoing or upcoming + */ + private fun determineRelativeLabel(event: CalendarEvent): String { + val now = LocalDateTime.now() + val start = Instant.parse(event.start).atZone(ZoneId.systemDefault()).toLocalDateTime() + val end = Instant.parse(event.end).atZone(ZoneId.systemDefault()).toLocalDateTime() + return when { + start.isBefore(now) && end.isAfter(now) -> "Ongoing" + start.isAfter(now) -> "Upcoming" + else -> "Past" + } + } + + private fun Panel.titleRow(event: CalendarEvent) { + val relativeLabel = determineRelativeLabel(event) + row { + label(relativeLabel).applyToComponent { + border = CompoundBorder( + JBUI.Borders.empty(), // Outer border for padding around each item + CompoundBorder( + // Inner border for the gray line around each item + RoundedLineBorder(JBColor.GRAY, ROUNDED_CORNER_RADIUS), + // Innermost border for left and right margins + JBUI.Borders.empty(0, LIST_ITEM_PADDING_MARGIN) + ) + ) + background = when (relativeLabel) { + "Past" -> { + JBColor.namedColor("Panel.background") + } + + "Ongoing" -> { + JBColor.namedColor("Banner.warningBackground") + } + + else -> { + JBColor.namedColor("Banner.infoBackground") + } + } + isOpaque = true + } + event.summary?.let { + label(it.trim()).applyToComponent { + event.htmlLink?.let { + // Make the label clickable + cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) + addMouseListener(object : MouseAdapter() { + override fun mouseClicked(e: MouseEvent?) { + BrowserUtil.browse(event.htmlLink) + } + }) + toolTipText = "Click to open in calendar" + } + } + .customize(Gaps.EMPTY) + .applyToComponent { + border = JBUI.Borders.empty() + } + .align(AlignX.LEFT) + } + }.bottomGap(BottomGap.NONE) + } + +} diff --git a/src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsToolWindowFactory.kt b/src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsToolWindowFactory.kt new file mode 100644 index 0000000..33e6a55 --- /dev/null +++ b/src/main/kotlin/co/makerflow/intellijplugin/panels/CalendarEventsToolWindowFactory.kt @@ -0,0 +1,18 @@ +package co.makerflow.intellijplugin.panels + +import com.intellij.ide.lightEdit.LightEditCompatible +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.ToolWindow +import com.intellij.openapi.wm.ToolWindowFactory + +@Suppress("UnstableApiUsage") +class CalendarEventsToolWindowFactory: ToolWindowFactory, DumbAware, LightEditCompatible { + override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + val panel = UpcomingEventsPanel() + val contentManager = toolWindow.contentManager + val content = contentManager.factory.createContent(panel, null, false) + contentManager.addContent(content) + toolWindow.setTitleActions(listOf(panel.reloadAction)) + } +} diff --git a/src/main/kotlin/co/makerflow/intellijplugin/panels/TasksToolWindowFactory.kt b/src/main/kotlin/co/makerflow/intellijplugin/panels/TasksToolWindowFactory.kt index b35feb8..a4042d0 100644 --- a/src/main/kotlin/co/makerflow/intellijplugin/panels/TasksToolWindowFactory.kt +++ b/src/main/kotlin/co/makerflow/intellijplugin/panels/TasksToolWindowFactory.kt @@ -1,12 +1,14 @@ package co.makerflow.intellijplugin.panels +import com.intellij.ide.lightEdit.LightEditCompatible import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.Project import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory -class TasksToolWindowFactory : ToolWindowFactory, DumbAware { +@Suppress("UnstableApiUsage") +class TasksToolWindowFactory : ToolWindowFactory, DumbAware, LightEditCompatible { override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { val contentManager = toolWindow.contentManager val tasksPanel = TasksPanel() diff --git a/src/main/kotlin/co/makerflow/intellijplugin/services/EventsService.kt b/src/main/kotlin/co/makerflow/intellijplugin/services/EventsService.kt new file mode 100644 index 0000000..6589c4e --- /dev/null +++ b/src/main/kotlin/co/makerflow/intellijplugin/services/EventsService.kt @@ -0,0 +1,61 @@ +package co.makerflow.intellijplugin.services + +import co.makerflow.client.apis.EventsApi +import co.makerflow.client.infrastructure.ApiClient +import co.makerflow.client.models.CalendarEvent +import co.makerflow.intellijplugin.settings.SettingsState +import com.intellij.openapi.components.Service +import com.intellij.openapi.diagnostic.thisLogger +import com.intellij.openapi.project.DumbAware +import com.squareup.moshi.JsonEncodingException +import io.ktor.client.call.NoTransformationFoundException +import io.ktor.serialization.JsonConvertException +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +@Service +class EventsService : DumbAware { + private val baseUrl = System.getenv("MAKERFLOW_API_URL") ?: ApiClient.BASE_URL + + private fun eventsApi(): EventsApi { + val apiToken = getApiToken() + val api = EventsApi(baseUrl, null, null, ApiClient.JSON_DEFAULT) + api.setApiKey(apiToken) + return api + } + + private fun getApiToken() = System.getenv("MAKERFLOW_API_TOKEN") ?: SettingsState.instance.apiToken + + suspend fun fetchEvents(): List { + return coroutineScope { + var events: List? = listOf() + launch { + val response = eventsApi().upcomingCalendarEvents("jetbrains") + @Suppress("TooGenericExceptionCaught") + try { + if (response.success) { + events = response.body().events + } + } catch (e: Exception) { + @Suppress("kotlin:S125") + when (e) { + is JsonConvertException, + is NoTransformationFoundException, + is JsonEncodingException -> { + /* + Intentionally commented out */ +// thisLogger().error(e) +// thisLogger().error("Error converting ongoing flow mode: ${e.message}") + } + + else -> { + thisLogger().error("Error fetching events: ${e.message}") + throw e + } + } + } + }.join() + return@coroutineScope events!! + } + } +} diff --git a/src/main/kotlin/co/makerflow/intellijplugin/state/FlowState.kt b/src/main/kotlin/co/makerflow/intellijplugin/state/FlowState.kt index d65a3b3..3164bc5 100644 --- a/src/main/kotlin/co/makerflow/intellijplugin/state/FlowState.kt +++ b/src/main/kotlin/co/makerflow/intellijplugin/state/FlowState.kt @@ -4,7 +4,6 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.components.State import com.intellij.openapi.components.Storage -import com.intellij.openapi.components.service import com.intellij.util.xmlb.XmlSerializerUtil @State(name = "co.makerflow.intellijplugin.state.FlowState", storages = [Storage("MakerflowFlowState.xml")]) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 5a3b87b..392437a 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -26,6 +26,8 @@ id="co.makerflow.intellijplugin.FlowStatusBarWidgetFactory" /> +