Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable partial graphs in nx console & fix bugs #2115

Merged
merged 20 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 15 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
2 changes: 1 addition & 1 deletion apps/intellij/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"runIde": {
"executor": "nx:run-commands",
"options": {
"command": "node ./apps/intellij/run-gradle.js:apps:intellij:runIde"
"command": "node ./apps/intellij/run-gradle.js :apps:intellij:runIde"
}
},
"build": {
Expand Down
2 changes: 2 additions & 0 deletions apps/intellij/run-gradle.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ const gradleProcess = spawn(gradleCommand, [arg], { shell: true, stdio: 'inherit

gradleProcess.on('error', (err) => {
console.error(`Failed to start subprocess: ${err}`);
process.exit(1);
});

gradleProcess.on('close', (code) => {
console.log(`Gradle process exited with code ${code}`);
process.exit(code);
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ class NxGraphBrowser(project: Project) : NxGraphBrowserBase(project) {
NxWorkspaceRefreshListener {
coroutineScope.launch {
try {
val error = NxlsService.getInstance(project).workspace()?.error
setErrorAndRefresh(error)
val errors = NxlsService.getInstance(project).workspace()?.errors
setErrorsAndRefresh(errors)
} catch (e: Throwable) {
logger<ProjectDetailsBrowser>().debug(e.message)
}
Expand All @@ -58,9 +58,10 @@ class NxGraphBrowser(project: Project) : NxGraphBrowserBase(project) {
}
currentLoadHtmlJob =
coroutineScope.launch {
error =
this@NxGraphBrowser.error ?: NxlsService.getInstance(project).workspace()?.error
error.also {
errors =
this@NxGraphBrowser.errors
?: NxlsService.getInstance(project).workspace()?.errors
errors.also {
if (it != null) {
withContext(Dispatchers.EDT) {
wrappedBrowserLoadHtml(getErrorHtml(it))
Expand All @@ -84,7 +85,7 @@ class NxGraphBrowser(project: Project) : NxGraphBrowserBase(project) {
fun selectAllProjects() {
lastGraphCommand = GraphCommand.SelectAllProjects()
executeWhenLoaded {
if (error != null) return@executeWhenLoaded
if (errors != null) return@executeWhenLoaded
if (browser.isDisposed) {
thisLogger().warn("Can't select all projects because browser has been disposed.")
return@executeWhenLoaded
Expand All @@ -98,7 +99,7 @@ class NxGraphBrowser(project: Project) : NxGraphBrowserBase(project) {
fun focusProject(projectName: String) {
lastGraphCommand = GraphCommand.FocusProject(projectName)
executeWhenLoaded {
if (error != null) return@executeWhenLoaded
if (errors != null) return@executeWhenLoaded
if (browser.isDisposed) return@executeWhenLoaded
browser.executeJavaScript(
"window.waitForRouter?.().then(() => {console.log('navigating to $projectName'); window.externalApi.focusProject('$projectName')})"
Expand All @@ -109,7 +110,7 @@ class NxGraphBrowser(project: Project) : NxGraphBrowserBase(project) {
fun focusTargetGroup(targetGroup: String) {
lastGraphCommand = GraphCommand.FocusTargetGroup(targetGroup)
executeWhenLoaded {
if (error != null) return@executeWhenLoaded
if (errors != null) return@executeWhenLoaded
if (browser.isDisposed) return@executeWhenLoaded
browser.executeJavaScript(
"window.waitForRouter?.().then(() => {console.log('navigating to group $targetGroup'); window.externalApi.selectAllTargetsByName('$targetGroup')})"
Expand All @@ -120,7 +121,7 @@ class NxGraphBrowser(project: Project) : NxGraphBrowserBase(project) {
fun focusTarget(projectName: String, targetName: String) {
lastGraphCommand = GraphCommand.FocusTarget(projectName, targetName)
executeWhenLoaded {
if (error != null) return@executeWhenLoaded
if (errors != null) return@executeWhenLoaded
if (browser.isDisposed) return@executeWhenLoaded
browser.executeJavaScript(
"window.waitForRouter?.().then(() => {console.log('navigating to target $projectName:$targetName'); window.externalApi.focusTarget('$projectName','$targetName')})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import com.intellij.ui.JBColor
import com.intellij.ui.jcef.*
import com.intellij.util.ui.UIUtil
import dev.nx.console.graph.ui.NxGraphDownloadHandler
import dev.nx.console.nxls.NxlsService
import dev.nx.console.models.NxError
import dev.nx.console.nxls.NxRefreshWorkspaceService
import dev.nx.console.run.NxTaskExecutionManager
import dev.nx.console.telemetry.TelemetryService
import dev.nx.console.utils.*
Expand Down Expand Up @@ -48,7 +49,7 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
protected val browserLoadedState: MutableStateFlow<Boolean> = MutableStateFlow(false)
protected val executeWhenLoadedJobs: MutableList<Job> = mutableListOf()

protected var error: String? = null
protected var errors: Array<NxError>? = null

init {
graphServer.start()
Expand Down Expand Up @@ -104,6 +105,8 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
browser.loadHTML(modifiedHtml)
}
Disposer.dispose(oldQueryMessenger)

setColors()
}

protected fun loadGraphHtmlBase(): String {
Expand All @@ -127,7 +130,7 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {

htmlText =
htmlText.replace(
"<base\\b[^>]*/>".toRegex(),
"<base\\b[^>]*>".toRegex(),
"""
<base href="${Matcher.quoteReplacement(graphBasePath)}">
"""
Expand Down Expand Up @@ -177,6 +180,7 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
if (type.startsWith('request') && id && pendingRequests.has(id)) {
const payloadParsed = JSON.parse(payload);
const resolve = pendingRequests.get(id);
console.log('Received response for', type, payloadParsed);
resolve(payloadParsed);
pendingRequests.delete(id);
}
Expand Down Expand Up @@ -230,8 +234,8 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
return htmlText
}

protected fun setErrorAndRefresh(error: String?) {
this.error = error
protected fun setErrorsAndRefresh(errors: Array<NxError>?) {
this.errors = errors
refresh()
}

Expand Down Expand Up @@ -301,7 +305,7 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
executeWhenLoadedJobs.add(job)
}

protected fun getErrorHtml(error: String): String {
protected fun getErrorHtml(errors: Array<NxError>): String {
return """
<style>
body {
Expand All @@ -321,9 +325,10 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
}
</style>

<p>Unable to load the project graph. The following error occurred:</p>
<pre>${error}</pre>
If you are unable to resolve this issue, click here to <a href="#" onclick="window.reset()">reset</a> the graph.
<p>Unable to load the project graph. The following error${if(errors.isNotEmpty()) "s" else ""} occurred:</p>
${errors.map { "<pre>${it.message ?: ""} \n ${it.stack ?: ""}</pre>" }.joinToString("\n")
}
If you are unable to resolve this issue, click here to <a href="#" onclick="window.reset()">reload the project graph</a>. If that doesn't work, try running <code>nx reset</code> in the terminal & restart the IDE.
"""
.trimIndent()
}
Expand All @@ -336,9 +341,7 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
resetQuery?.also { query ->
if (query.isDisposed) return@executeWhenLoaded
query.addHandler {
val nxlsService = NxlsService.getInstance(project)
CoroutineScope(Dispatchers.EDT).launch { nxlsService.refreshWorkspace() }

NxRefreshWorkspaceService.getInstance(project).refreshWorkspace()
null
}

Expand Down Expand Up @@ -374,12 +377,12 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
const darkClass = 'vscode-dark';
const lightClass = 'vscode-light';

body.classList.remove(darkClass, lightClass);
body.classList?.remove(darkClass, lightClass);

if (isDark) {
body.classList.add(darkClass);
body.classList?.add(darkClass);
} else {
body.classList.add(lightClass);
body.classList?.add(lightClass);
}
console.log("$backgroundColor")
body.style.setProperty('background-color', '$backgroundColor', 'important');
Expand Down Expand Up @@ -409,7 +412,9 @@ abstract class NxGraphBrowserBase(protected val project: Project) : Disposable {
if (response.error != null) {
thisLogger()
.debug("Error handling graph request: ${response.error}")
setErrorAndRefresh(response.error)
setErrorsAndRefresh(
arrayOf(NxError(response.error, null, null, null))
)
return@launch
}
browser.executeJavaScript(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ open class NxGraphServer(
}
}

fun restart() {
this.dispose()
this.start()
}

private suspend fun spawnProcess(port: Int): Process {
println("trying to start graph at $port")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,59 @@ data class NxWorkspace(
val workspace: NxWorkspaceConfiguration,
val daemonEnabled: Boolean?,
val workspacePath: String,
val error: String?,
val errors: Array<NxError>?,
val isLerna: Boolean,
val nxVersion: NxVersion,
val isEncapsulatedNx: Boolean,
val isPartial: Boolean?,
val workspaceLayout: WorkspaceLayout?,
) {}
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as NxWorkspace

if (validWorkspaceJson != other.validWorkspaceJson) return false
if (workspace != other.workspace) return false
if (daemonEnabled != other.daemonEnabled) return false
if (workspacePath != other.workspacePath) return false
if (errors != null) {
if (other.errors == null) return false
if (!errors.contentEquals(other.errors)) return false
} else if (other.errors != null) return false
if (isLerna != other.isLerna) return false
if (nxVersion != other.nxVersion) return false
if (isEncapsulatedNx != other.isEncapsulatedNx) return false
if (workspaceLayout != other.workspaceLayout) return false

return true
}

override fun hashCode(): Int {
var result = validWorkspaceJson.hashCode()
result = 31 * result + workspace.hashCode()
result = 31 * result + (daemonEnabled?.hashCode() ?: 0)
result = 31 * result + workspacePath.hashCode()
result = 31 * result + (errors?.contentHashCode() ?: 0)
result = 31 * result + isLerna.hashCode()
result = 31 * result + nxVersion.hashCode()
result = 31 * result + isEncapsulatedNx.hashCode()
result = 31 * result + (workspaceLayout?.hashCode() ?: 0)
return result
}
}

data class WorkspaceLayout(val appsDir: String?, val libsDir: String?)

data class NxWorkspaceConfiguration(val projects: Map<String, NxProject>) {}

data class NxError(
val message: String?,
val stack: String?,
val file: String?,
val pluginName: String?
) {

constructor(message: String) : this(message, null, null, null)
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
package dev.nx.console.nxls

import StandardNxGraphServer
import com.intellij.notification.Notification
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.EDT
import com.intellij.openapi.components.Service
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project
import dev.nx.console.NxIcons
import dev.nx.console.graph.ui.NxGraphFileType
import dev.nx.console.utils.Notifier
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext

class NxRefreshWorkspaceAction :
DumbAwareAction("Refresh Nx Workspace", "Refreshes the Nx workspace", null) {
DumbAwareAction("Refresh Nx Workspace", "Refreshes the Nx workspace", NxIcons.Action) {

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
Expand Down Expand Up @@ -59,7 +64,6 @@ class NxRefreshWorkspaceService(val project: Project) {
if (refreshing) {
return
}

refreshing = true

ProgressManager.getInstance()
Expand All @@ -68,7 +72,11 @@ class NxRefreshWorkspaceService(val project: Project) {
override fun run(indicator: ProgressIndicator) {
runBlocking {
try {
NxlsService.getInstance(project).refreshWorkspace()
withContext(Dispatchers.EDT) {
NxlsService.getInstance(project).restart()
StandardNxGraphServer.getInstance(project).restart()
NxlsService.getInstance(project).refreshWorkspace()
}
} catch (ex: Exception) {
Notifier.notifyAnything(project, "Error refreshing workspace")
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.util.application
import dev.nx.console.NxConsoleBundle
import dev.nx.console.utils.Notifier
import dev.nx.console.utils.nodeInterpreter
import dev.nx.console.utils.nxBasePath
import java.io.File
Expand Down Expand Up @@ -58,7 +57,7 @@ class NxlsProcess(private val project: Project, private val cs: CoroutineScope)

logger.trace("Nxls early exit: $this")

Notifier.notifyNxlsError(project)
// Notifier.notifyNxlsError(project)
MaxKless marked this conversation as resolved.
Show resolved Hide resolved
onExit?.invoke()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,16 @@ class NxlsService(val project: Project, private val cs: CoroutineScope) {
wrapper.stop()
}

suspend fun refreshWorkspace() {
// call nx reset to clear all caches
server()?.getNxService()?.reset()
suspend fun restart() {
server()?.getNxService()?.stopDaemon()?.await()
thisLogger().info("reset done")
wrapper.stop()
start()
awaitStarted()
}

suspend fun refreshWorkspace() {
server()?.getNxService()?.refreshWorkspace()
}

suspend fun workspace(): NxWorkspace? {
Expand Down Expand Up @@ -209,6 +213,8 @@ class NxlsService(val project: Project, private val cs: CoroutineScope) {
} catch (e: MessageIssueException) {
Notifier.notifyLspMessageIssueExceptionThrottled(project, requestName, e)
null
} catch (e: CancellationException) {
null
}
}
}
Expand Down
Loading
Loading