Skip to content

Commit

Permalink
Merge branch 'master' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKless committed May 10, 2024
2 parents 6416c83 + 7acb20f commit 433673b
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 75 deletions.
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,6 @@ You can install Nx Console in the following places:
Visual Studio Marketplace.
- [Nx Console for JetBrains](https://plugins.jetbrains.com/plugin/21060-nx-console) from the JetBrains Marketplace

### Jetbrains WSL support

The Node interpreter under **Languages & Frameworks** > **Node.js** needs to be configured to use the Node executable
within the WSL distribution.
You can read more on
the [official Jetbrains docs](https://www.jetbrains.com/help/webstorm/how-to-use-wsl-development-environment-in-product.html#ws_wsl_node_interpreter_configure).

## True UI for Nx & Lerna

Nx Console is the UI for all Nx workspaces. It works for any generator or any architect commands. Nx Console does not
Expand All @@ -74,6 +67,12 @@ commands and install extensions without ever touching the terminal or having to
Also, Nx Console highlights the properties you are likely to use for built-in generators and commands, so if you haven't
used the CLI, you don't get overwhelmed.

## Compatibility

The latest version of Nx Console supports all Nx versions starting at Nx 15. For older versions, we cannot guarantee compatibility or full functionality. However, we welcome contributions! If you encounter specific issues with older versions, please consider submitting a PR. Of course, if you discover any problems with newer versions of Nx, please report these issues to help us improve Nx Console.

If you're looking to upgrade your version of Nx easily, refer to the [Nx migrate documentation](https://nx.dev/features/automate-updating-dependencies).

# Learn More

- [Documentation](https://nx.dev/core-features/integrate-with-editors) - Official documentation with video tutorials
Expand All @@ -88,3 +87,10 @@ Please read the [contributing guidelines](https://github.com/nrwl/nx-console/blo
the issues from
the [good first issue](https://github.com/nrwl/nx-console/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
list to get started.

### Jetbrains WSL support

The Node interpreter under **Languages & Frameworks** > **Node.js** needs to be configured to use the Node executable
within the WSL distribution.
You can read more on
the [official Jetbrains docs](https://www.jetbrains.com/help/webstorm/how-to-use-wsl-development-environment-in-product.html#ws_wsl_node_interpreter_configure).
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.intellij.openapi.ui.ValidationInfo
import com.intellij.ui.TextFieldWithAutoCompletion
import com.intellij.ui.components.JBTextField
import com.intellij.ui.dsl.builder.*
import com.intellij.util.applyIf
import dev.nx.console.models.NxGeneratorContext
import dev.nx.console.models.WorkspaceLayout
import java.awt.event.ActionEvent
Expand Down Expand Up @@ -84,6 +85,11 @@ class NxReMoveProjectDialog(
)
.comment(getShortcutHint())
.align(AlignX.FILL)
.applyIf(
reMoveGeneratorContext?.project.isNullOrEmpty()
) {
focused()
}

addDocumentListener(
object : BulkAwareDocumentListener.Simple {
Expand Down Expand Up @@ -115,7 +121,13 @@ class NxReMoveProjectDialog(
updateDestinationDirHint(model.project)

destinationField =
textField().bindText(model::directory).align(AlignX.FILL).component
textField()
.bindText(model::directory)
.align(AlignX.FILL)
.applyIf(!reMoveGeneratorContext?.project.isNullOrEmpty()) {
focused()
}
.component
}
.visible(mode == "move")
.layout(RowLayout.PARENT_GRID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ class NxExecutable {
}

fun getNxPackagePath(project: Project, basePath: String): String {
val nxExecutableName =
if (SystemInfo.isWindows && !WslPath.isWslUncPath(basePath)) "nx.bat" else "nx"
val nxExecutable = File(Paths.get(basePath, nxExecutableName).toString())
if (nxExecutable.exists()) {
return Paths.get(basePath, ".nx", "installation", "node_modules", "nx").toString()
}

val yarnPnpManager = YarnPnpManager.getInstance(project)
val virtualBaseFile = VirtualFileManager.getInstance().findFileByNioPath(Paths.get(basePath))
if (virtualBaseFile != null && yarnPnpManager.isUnderPnp(virtualBaseFile)) {
Expand Down
4 changes: 2 additions & 2 deletions libs/language-server/watcher/src/lib/daemon-watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ export class DaemonWatcher {
data?.changedFiles?.filter((f) => {
const normalized = normalize(f.path);
return !(
normalized.startsWith(normalize('.yarn/cache')) ||
normalized.startsWith(normalize('.nx/cache'))
normalized.includes(normalize('.yarn/cache')) ||
normalized.includes(normalize('.nx/cache'))
);
}) ?? [];
if (filteredChangedFiles.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export async function selectAffectedFlags(target: string): Promise<{
};
}
default: {
const positional = `--target=${target}`;
return {
command: 'affected',
positional,
flags: await selectFlags(`affected ${positional}`, AFFECTED_OPTIONS),
flags: await selectFlags(`affected`, AFFECTED_OPTIONS, {
target,
}),
};
}
}
Expand Down
74 changes: 58 additions & 16 deletions libs/vscode/nx-cli-quickpicks/src/lib/select-flags.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Option } from '@nx-console/shared/schema';
import { QuickPickItem, window } from 'vscode';

export class CliTaskFlagQuickPickItem implements QuickPickItem {
class CliTaskFlagQuickPickItem implements QuickPickItem {
constructor(
readonly flagName: string,
readonly detail = '',
Expand All @@ -11,6 +11,21 @@ export class CliTaskFlagQuickPickItem implements QuickPickItem {
) {}
}

class ExecuteCommandQuickPickItem implements QuickPickItem {
type = 'execute';
picked = true;
alwaysShow = true;

constructor(readonly label: string, readonly description?: string) {}
}

class CustomOptionsQuickPickItem implements QuickPickItem {
type = 'custom';
alwaysShow = true;

constructor(readonly label: string, readonly description?: string) {}
}

/**
* Returns undefined if the user wants to cancel the command.
* Returns an empty array to run the command without flags.
Expand All @@ -19,30 +34,41 @@ export class CliTaskFlagQuickPickItem implements QuickPickItem {
export async function selectFlags(
command: string,
options: Option[],
userSetFlags: { [key: string]: string } = {}
userSetFlags: { [key: string]: string } = {},
customOptions?: string
): Promise<string[] | undefined> {
const flagArray = Object.entries(userSetFlags).map(
([flagName, value]) => `--${flagName}=${value}`
);
if (customOptions) {
flagArray.push(customOptions);
}

const selection = await promptForFlagToSet(
`nx ${command} ${flagArray.join(' ')}`,
options.filter((option) => !userSetFlags[option.name])
);

if (!selection.flag) {
if (selection.execute !== undefined) {
return selection.execute ? flagArray : undefined;
}

const flagValue = await promptForFlagValue(selection.flag);
if (selection.flag) {
const flagValue = await promptForFlagValue(selection.flag);

if (flagValue && flagValue.length > 0) {
userSetFlags[selection.flag.flagName] = flagValue;
} else {
delete userSetFlags[selection.flag.flagName];
if (flagValue && flagValue.length > 0) {
userSetFlags[selection.flag.flagName] = flagValue;
} else {
delete userSetFlags[selection.flag.flagName];
}
} else if (selection.customOptions) {
const customOptionResult = await promptForCustomOptions(customOptions);
if (customOptionResult) {
customOptions = customOptionResult;
}
}

return selectFlags(command, options, userSetFlags);
return selectFlags(command, options, userSetFlags, customOptions);
}

async function promptForFlagToSet(
Expand All @@ -51,13 +77,14 @@ async function promptForFlagToSet(
): Promise<{
execute?: boolean;
flag?: CliTaskFlagQuickPickItem;
customOptions?: boolean;
}> {
const flagItems: Array<QuickPickItem | CliTaskFlagQuickPickItem> = [
{
picked: true,
alwaysShow: true,
label: `Execute: ${currentCommand}`,
},
const flagItems: Array<
| CliTaskFlagQuickPickItem
| ExecuteCommandQuickPickItem
| CustomOptionsQuickPickItem
> = [
new ExecuteCommandQuickPickItem(`Execute: ${currentCommand}`),
...options.map((option) => {
const detail =
option.description ??
Expand All @@ -70,6 +97,10 @@ async function promptForFlagToSet(
option.isRequired ? 'required' : undefined
);
}),
new CustomOptionsQuickPickItem(
'Custom Options',
'Add any additional command text.'
),
];

const selection = await window.showQuickPick(flagItems, {
Expand All @@ -82,7 +113,11 @@ async function promptForFlagToSet(

const flagSelected = Boolean((selection as CliTaskFlagQuickPickItem).option);
if (!flagSelected) {
return { execute: true };
if ((selection as CustomOptionsQuickPickItem).type === 'custom') {
return { customOptions: true };
} else {
return { execute: true };
}
} else {
return {
flag: selection as CliTaskFlagQuickPickItem,
Expand All @@ -107,3 +142,10 @@ function promptForFlagValue(flagToSet: CliTaskFlagQuickPickItem) {
});
}
}

function promptForCustomOptions(oldCustomOptions?: string) {
return window.showInputBox({
value: oldCustomOptions,
placeHolder: 'Enter any additional command text.',
});
}
57 changes: 25 additions & 32 deletions libs/vscode/nx-commands-view/src/lib/nx-commands-provider.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import {
getNxWorkspacePath,
GlobalConfigurationStore,
} from '@nx-console/vscode/configuration';
import { getNxWorkspace } from '@nx-console/vscode/nx-workspace';
import { GlobalConfigurationStore } from '@nx-console/vscode/configuration';
import { onWorkspaceRefreshed } from '@nx-console/vscode/lsp-client';
import { CliTaskProvider } from '@nx-console/vscode/tasks';
import {
AbstractTreeProvider,
getShellExecutionForConfig,
logAndShowTaskCreationError,
} from '@nx-console/vscode/utils';
import { commands, ExtensionContext, Task, tasks, TaskScope } from 'vscode';
import { commands, ExtensionContext } from 'vscode';
import { NxCommandConfig, NxCommandsTreeItem } from './nx-commands-tree-item';
import { onWorkspaceRefreshed } from '@nx-console/vscode/lsp-client';
import { importNxPackagePath } from '@nx-console/shared/npm';

export const EXECUTE_ARBITRARY_COMMAND = 'nxConsole.executeArbitraryCommand';

Expand Down Expand Up @@ -77,31 +72,29 @@ export class NxCommandsTreeProvider extends AbstractTreeProvider<NxCommandsTreeI
}

async executeArbitraryCommand(command: string) {
const prefixedCommand = command.startsWith('nx ')
? command
: `nx ${command}`;
const workspacePath = getNxWorkspacePath();
const isEncapsulatedNx =
(await getNxWorkspace())?.isEncapsulatedNx ?? false;
const { detectPackageManager } = await importNxPackagePath<
typeof import('nx/src/devkit-exports')
>(workspacePath, 'src/devkit-exports');
const pkgManager = detectPackageManager(workspacePath);
let _command: string;
let positional: string | undefined;

const commandBeforeFlags = command.split(' -')[0];
if (commandBeforeFlags.includes(' ')) {
_command = commandBeforeFlags.split(' ')[0];
positional = commandBeforeFlags.replace(_command, '').trim();
} else {
_command = commandBeforeFlags;
positional = undefined;
}

const flags = command
.replace(commandBeforeFlags, '')
.split(' ')
.filter(Boolean);

try {
const task = new Task(
{ type: 'nx' },
TaskScope.Workspace,
prefixedCommand,
pkgManager,
await getShellExecutionForConfig({
cwd: workspacePath,
displayCommand: prefixedCommand,
encapsulatedNx: isEncapsulatedNx,
workspacePath,
})
);
tasks.executeTask(task);
CliTaskProvider.instance.executeTask({
command: _command,
positional,
flags,
});
} catch (e) {
logAndShowTaskCreationError(e);
return;
Expand Down
2 changes: 1 addition & 1 deletion libs/vscode/tasks/src/lib/cli-task-definition.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface CliTaskDefinition {
positional: string;
positional?: string;
command: string;
flags: Array<string>;
cwd?: string;
Expand Down
2 changes: 1 addition & 1 deletion libs/vscode/tasks/src/lib/cli-task-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class CliTaskProvider implements TaskProvider {
}

let task;
const positionals = definition.positional.match(
const positionals = definition.positional?.match(
WORKSPACE_GENERATOR_NAME_REGEX
);
try {
Expand Down
14 changes: 2 additions & 12 deletions libs/vscode/tasks/src/lib/cli-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,6 @@ export class CliTask extends Task {

function getArgs(definition: CliTaskDefinition) {
const { positional, command, flags } = definition;
switch (command) {
case 'add':
case 'build':
case 'lint':
case 'generate':
case 'run':
case 'serve':
case 'test':
return [command, positional, ...flags];
default:
return ['run', `${positional}:${command}`, ...flags];
}
const args = [command, positional, ...flags];
return args.filter((v) => v !== undefined && v !== null);
}

0 comments on commit 433673b

Please sign in to comment.