diff --git a/src/commands/LifecycleCommands.ts b/src/commands/LifecycleCommands.ts index 73207577..f4870fe0 100644 --- a/src/commands/LifecycleCommands.ts +++ b/src/commands/LifecycleCommands.ts @@ -1052,7 +1052,7 @@ export class LifecycleCommands implements IDisposable { }); const connectorQueryFiles: vscode.Uri[] = await vscode.workspace.findFiles( - "**/*.query.pq", + "**/*.{query,test}.pq", "**/{bin,obj}/**", 1e2, ); @@ -1075,6 +1075,10 @@ export class LifecycleCommands implements IDisposable { label: one, })); + items.push({ + label: extensionI18n["PQSdk.lifecycle.command.choose.customizedDataSourceKind.label"], + }); + const picked: vscode.QuickPickItem = await input.showQuickPick({ title, step: 1, @@ -1085,9 +1089,17 @@ export class LifecycleCommands implements IDisposable { }); state.DataSourceKind = picked.label; - } else { - // we did not get a list of data source candidates, - // thus have to allow users inputting freely + } + + if ( + !state.DataSourceKind || + state.DataSourceKind === + extensionI18n["PQSdk.lifecycle.command.choose.customizedDataSourceKind.label"] + ) { + // we did not have the DataSourceKind populated, + // or it was set to customized dataSourceKind label + // then we should allow users to input arbitrarily + // eslint-disable-next-line require-atomic-updates state.DataSourceKind = await input.showInputBox({ title, step: 1, @@ -1114,22 +1126,75 @@ export class LifecycleCommands implements IDisposable { input: MultiStepInput, state: Partial, ): Promise { - const items: vscode.QuickPickItem[] = connectorQueryFiles.map((one: vscode.Uri) => ({ - label: vscode.workspace.asRelativePath(one), - detail: one.fsPath, - })); + if (connectorQueryFiles.length) { + const items: vscode.QuickPickItem[] = connectorQueryFiles.map((one: vscode.Uri) => ({ + label: vscode.workspace.asRelativePath(one), + detail: one.fsPath, + })); - const picked: vscode.QuickPickItem = await input.showQuickPick({ - title, - step: 2, - totalSteps: 3, - placeholder: extensionI18n["PQSdk.lifecycle.command.choose.connectorFile"], - activeItem: items[0], - items, - }); + items.push({ + label: extensionI18n["PQSdk.lifecycle.command.choose.customizedQueryFilePath.label"], + detail: extensionI18n["PQSdk.lifecycle.command.choose.customizedQueryFilePath.detail"], + }); - // eslint-disable-next-line require-atomic-updates - state.PathToQueryFile = picked.detail; + const picked: vscode.QuickPickItem = await input.showQuickPick({ + title, + step: 2, + totalSteps: 3, + placeholder: extensionI18n["PQSdk.lifecycle.command.choose.queryFile"], + activeItem: items[0], + items, + }); + + // eslint-disable-next-line require-atomic-updates + state.PathToQueryFile = picked.detail; + } + + if ( + !state.PathToQueryFile || + state.PathToQueryFile === + extensionI18n["PQSdk.lifecycle.command.choose.customizedQueryFilePath.detail"] + ) { + // we did not have the PathToQueryFile populated, + // or it was set to customized PathToQueryFile detail + // then we should allow users to input arbitrarily + // eslint-disable-next-line require-atomic-updates + state.PathToQueryFile = await input.showInputBox({ + title, + step: 2, + totalSteps: 3, + value: "", + prompt: extensionI18n["PQSdk.lifecycle.command.choose.queryFilePath.label"], + ignoreFocusOut: true, + validate: (key: string) => + Promise.resolve( + key.length + ? undefined + : extensionI18n["PQSdk.lifecycle.error.empty.PathToQueryFilePath"], + ), + }); + + // we also need to populate the state.PathToConnectorFile + // since the PathToQueryFilePath might be another query file + state.PathToConnectorFile = path.dirname(state.PathToQueryFile); + + // need to populate the PathToConnectorFile to re-verify + // eslint-disable-next-line require-atomic-updates + state.PathToConnectorFile = await input.showInputBox({ + title, + step: 2, + totalSteps: 3, + value: state.PathToConnectorFile, + prompt: extensionI18n["PQSdk.lifecycle.command.choose.extensionFilePath.label"], + ignoreFocusOut: true, + validate: (key: string) => + Promise.resolve( + key.length + ? undefined + : extensionI18n["PQSdk.lifecycle.error.empty.PathToConnectorFile"], + ), + }); + } progress.report({ increment: 10 }); diff --git a/src/common/PQTestService.ts b/src/common/PQTestService.ts index 1472d37c..58d58e1a 100644 --- a/src/common/PQTestService.ts +++ b/src/common/PQTestService.ts @@ -102,6 +102,7 @@ export interface ExtensionInfo { export interface CreateAuthState { DataSourceKind: string; AuthenticationKind: string; + PathToConnectorFile?: string; PathToQueryFile: string; // for the key template $$KEY$$?: string; diff --git a/src/i18n/extension.json b/src/i18n/extension.json index 041400da..bfc2a2f2 100644 --- a/src/i18n/extension.json +++ b/src/i18n/extension.json @@ -32,8 +32,13 @@ "PQSdk.lifecycle.command.generate.credentials.title": "Generating credential", "PQSdk.lifecycle.command.generate.credentials.result": "GenerateCredentialTemplate {result} ", "PQSdk.lifecycle.command.choose.dataSourceKind.label": "Data source kind", + "PQSdk.lifecycle.command.choose.customizedDataSourceKind.label": "Input a data source kind", "PQSdk.lifecycle.command.choose.dataSourceKind": "Choose the data source kind", - "PQSdk.lifecycle.command.choose.connectorFile": "Choose a connector file", + "PQSdk.lifecycle.command.choose.queryFile": "Choose a query/test file", + "PQSdk.lifecycle.command.choose.extensionFilePath.label": "Extension file path", + "PQSdk.lifecycle.command.choose.queryFilePath.label": "Query/test file path", + "PQSdk.lifecycle.command.choose.customizedQueryFilePath.label": "Input a query/test file path", + "PQSdk.lifecycle.command.choose.customizedQueryFilePath.detail": "Arbitrary query/test file path using the credential", "PQSdk.lifecycle.command.choose.auth": "Choose an authentication method", "PQSdk.lifecycle.command.choose.authKind.prompt": "Authentication key value", "PQSdk.lifecycle.command.set.credentials.result": "SetCredential {result} ", @@ -61,6 +66,8 @@ "PQSdk.lifecycle.warning.pqtest.set.failed": "SDK Tools location has not been configured", "PQSdk.lifecycle.warning.pqtest.required": "SDK Tools location must be provided before continuing", "PQSdk.lifecycle.error.empty.dataSourceKind": "Data source kind cannot be empty", + "PQSdk.lifecycle.error.empty.PathToConnectorFile": "Extension file path cannot be empty", + "PQSdk.lifecycle.error.empty.PathToQueryFilePath": "Query/test file path cannot be empty", "PQSdk.lifecycle.error.empty.project.name": "A project name value must be set before continuing", "PQSdk.lifecycle.error.invalid.project.name": "Only alphanumeric are allowed.", "PQSdk.lifecycle.error.invalid.empty.value": "Value {valueName} cannot be empty.", diff --git a/src/pqTestConnector/PqServiceHostClient.ts b/src/pqTestConnector/PqServiceHostClient.ts index f5dba8bc..6d9b7778 100644 --- a/src/pqTestConnector/PqServiceHostClient.ts +++ b/src/pqTestConnector/PqServiceHostClient.ts @@ -776,7 +776,7 @@ export class PqServiceHostClient implements IPQTestService, IDisposable { params: [ { SessionId: this.sessionId, - PathToConnector: getFirstWorkspaceFolder()?.uri.fsPath, + PathToConnector: createAuthState.PathToConnectorFile || getFirstWorkspaceFolder()?.uri.fsPath, PathToQueryFile: resolveSubstitutedValues(createAuthState.PathToQueryFile), // DataSourceKind: createAuthState.DataSourceKind, AuthenticationKind: createAuthState.AuthenticationKind, diff --git a/src/pqTestConnector/PqTestExecutableTaskQueue.ts b/src/pqTestConnector/PqTestExecutableTaskQueue.ts index 4f4d451a..4cfa97f7 100644 --- a/src/pqTestConnector/PqTestExecutableTaskQueue.ts +++ b/src/pqTestConnector/PqTestExecutableTaskQueue.ts @@ -584,7 +584,9 @@ export class PqTestExecutableTaskQueue implements IPQTestService, IDisposable { return this.doEnqueueOneTask({ operation: "set-credential", additionalArgs, - pathToConnector: resolveSubstitutedValues(ExtensionConfigurations.DefaultExtensionLocation), + pathToConnector: + createAuthState.PathToConnectorFile || + resolveSubstitutedValues(ExtensionConfigurations.DefaultExtensionLocation), pathToQueryFile: resolveSubstitutedValues(createAuthState.PathToQueryFile), stdinStr: payloadStr, });