Skip to content

Commit 125c753

Browse files
authored
Merge pull request #2942 from codefori/profilesOverhaul
Actions/Custom Variables/Profiles overhaul
2 parents a624a09 + 47af944 commit 125c753

38 files changed

+1966
-1302
lines changed

package.json

Lines changed: 359 additions & 164 deletions
Large diffs are not rendered by default.

src/api/IBMiContent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ export default class IBMiContent {
475475
lines.forEach(line => {
476476
const isNotFound = line.includes(`CPF2110`);
477477
if (isNotFound) {
478-
const libraryReference = sanitized.find(lib => line.includes(lib));
478+
const libraryReference = sanitized.find(library => line.includes(` ${library} `));
479479

480480
// If there is an error about the library, remove it
481481
if (libraryReference) {

src/api/actions.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import vscode, { l10n } from "vscode";
2+
import IBMi from "./IBMi";
3+
import { Action } from "./types";
4+
5+
export async function getActions(workspace?: vscode.WorkspaceFolder) {
6+
return workspace ? await getLocalActions(workspace) : (IBMi.connectionManager.get<Action[]>(`actions`) || []);
7+
}
8+
9+
export async function updateAction(action: Action, workspace?: vscode.WorkspaceFolder, options?: { newName?: string, delete?: boolean }) {
10+
const actions = await getActions(workspace);
11+
const currentIndex = actions.findIndex(a => action.name === a.name);
12+
13+
action.name = options?.newName || action.name;
14+
15+
if (options?.delete) {
16+
if (currentIndex >= 0) {
17+
actions.splice(currentIndex, 1);
18+
}
19+
else {
20+
throw new Error(l10n.t("Cannot find action {0} for delete operation", action.name));
21+
}
22+
}
23+
else {
24+
actions[currentIndex >= 0 ? currentIndex : actions.length] = action;
25+
}
26+
27+
if (workspace) {
28+
const actionsFile = (await getLocalActionsFiles(workspace)).at(0);
29+
if (actionsFile) {
30+
await vscode.workspace.fs.writeFile(actionsFile, Buffer.from(JSON.stringify(actions, undefined, 2), "utf-8"));
31+
}
32+
else {
33+
throw new Error(l10n.t("No local actions file defined in workspace {0}", workspace.name));
34+
}
35+
}
36+
else {
37+
await IBMi.connectionManager.set(`actions`, actions);
38+
}
39+
}
40+
41+
export async function getLocalActionsFiles(workspace: vscode.WorkspaceFolder) {
42+
return workspace ? await vscode.workspace.findFiles(new vscode.RelativePattern(workspace, `**/.vscode/actions.json`)) : [];
43+
}
44+
45+
async function getLocalActions(currentWorkspace: vscode.WorkspaceFolder) {
46+
const actions: Action[] = [];
47+
48+
if (currentWorkspace) {
49+
const actionsFiles = await getLocalActionsFiles(currentWorkspace);
50+
51+
for (const file of actionsFiles) {
52+
const actionsContent = await vscode.workspace.fs.readFile(file);
53+
try {
54+
const actionsJson: Action[] = JSON.parse(actionsContent.toString());
55+
56+
// Maybe one day replace this with real schema validation
57+
if (Array.isArray(actionsJson)) {
58+
actionsJson.forEach((action, index) => {
59+
if (
60+
typeof action.name === `string` &&
61+
typeof action.command === `string` &&
62+
[`ile`, `pase`, `qsh`].includes(action.environment) &&
63+
(!action.extensions || Array.isArray(action.extensions))
64+
) {
65+
actions.push({
66+
...action,
67+
type: `file`
68+
});
69+
} else {
70+
throw new Error(`Invalid Action defined at index ${index}.`);
71+
}
72+
})
73+
}
74+
} catch (e: any) {
75+
vscode.window.showErrorMessage(`Error parsing ${file.fsPath}: ${e.message}\n`);
76+
}
77+
};
78+
}
79+
80+
return actions;
81+
}

src/api/configuration/config/ConnectionManager.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ function initialize(parameters: Partial<ConnectionConfig>): ConnectionConfig {
1414
autoClearTempData: parameters.autoClearTempData || false,
1515
customVariables: parameters.customVariables || [],
1616
connectionProfiles: parameters.connectionProfiles || [],
17-
commandProfiles: parameters.commandProfiles || [],
1817
ifsShortcuts: parameters.ifsShortcuts || [],
1918
/** Default auto sorting of shortcuts to off */
2019
autoSortIFSShortcuts: parameters.autoSortIFSShortcuts || false,
@@ -87,7 +86,7 @@ export class ConnectionManager {
8786
}
8887

8988
async storeNew(data: ConnectionData) {
90-
const connections = await this.getAll();
89+
const connections = this.getAll();
9190
const newId = connections.length;
9291
connections.push(data);
9392
await this.setAll(connections);

src/api/configuration/config/types.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FilterType } from "../../Filter";
2-
import { DeploymentMethod, ConnectionData } from "../../types";
2+
import { ConnectionData, DeploymentMethod } from "../../types";
33

44
export type DefaultOpenMode = "browse" | "edit";
55
export type ReconnectMode = "always" | "never" | "ask";
@@ -8,7 +8,6 @@ export interface ConnectionConfig extends ConnectionProfile {
88
host: string;
99
autoClearTempData: boolean;
1010
connectionProfiles: ConnectionProfile[];
11-
commandProfiles: CommandProfile[];
1211
autoSortIFSShortcuts: boolean;
1312
tempLibrary: string;
1413
tempDir: string;
@@ -33,6 +32,7 @@ export interface ConnectionConfig extends ConnectionProfile {
3332
protectedPaths: string[];
3433
showHiddenFiles: boolean;
3534
lastDownloadLocation: string;
35+
currentProfile?: string
3636
[name: string]: any;
3737
}
3838

@@ -64,11 +64,7 @@ export interface ConnectionProfile {
6464
objectFilters: ObjectFilters[]
6565
ifsShortcuts: string[]
6666
customVariables: CustomVariable[]
67-
}
68-
69-
export interface CommandProfile {
70-
name: string;
71-
command: string;
67+
setLibraryListCommand?: string
7268
}
7369

7470
export interface StoredConnection {

src/api/configuration/storage/ConnectionStorage.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,6 @@ export class ConnectionStorage {
4545
await this.internalStorage.set(SOURCE_LIST_KEY, sourceList);
4646
}
4747

48-
getLastProfile() {
49-
return this.internalStorage.get<string>(LAST_PROFILE_KEY);
50-
}
51-
52-
async setLastProfile(lastProfile: string) {
53-
await this.internalStorage.set(LAST_PROFILE_KEY, lastProfile);
54-
}
55-
5648
getPreviousCurLibs() {
5749
return this.internalStorage.get<string[]>(PREVIOUS_CUR_LIBS_KEY) || [];
5850
}
@@ -94,6 +86,15 @@ export class ConnectionStorage {
9486
await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, undefined);
9587
}
9688

89+
/** @deprecated stored in ConnectionSettings now */
90+
getLastProfile() {
91+
return this.internalStorage.get<string>(LAST_PROFILE_KEY);
92+
}
93+
94+
async clearDeprecatedLastProfile() {
95+
await this.internalStorage.set(LAST_PROFILE_KEY, undefined);
96+
}
97+
9798
async grantExtensionAuthorisation(extensionId: string, displayName: string) {
9899
const extensions = this.getAuthorisedExtensions();
99100
if (!this.getExtensionAuthorisation(extensionId)) {

src/api/connectionProfiles.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { l10n } from "vscode";
2+
import { instance } from "../instantiate";
3+
import IBMi from "./IBMi";
4+
import { ConnectionProfile } from "./types";
5+
6+
export async function updateConnectionProfile(profile: ConnectionProfile, options?: { newName?: string, delete?: boolean }) {
7+
const config = instance.getConnection()?.getConfig();
8+
if (config) {
9+
const profiles = config.connectionProfiles;
10+
const index = profiles.findIndex(p => p.name === profile.name);
11+
12+
if (options?.delete) {
13+
if (index < 0) {
14+
throw new Error(l10n.t("Profile {0} not found for deletion.", profile.name));
15+
}
16+
profiles.splice(index, 1);
17+
}
18+
else {
19+
profile.name = options?.newName || profile.name;
20+
profiles[index < 0 ? profiles.length : index] = profile;
21+
}
22+
23+
if (isActiveProfile(profile)) {
24+
//Only update the setLibraryListCommand in the current config since the editor is the only place it can be changed
25+
config.setLibraryListCommand = profile.setLibraryListCommand;
26+
}
27+
28+
await IBMi.connectionManager.update(config);
29+
}
30+
}
31+
32+
/**
33+
* @returns ann arry of {@link ConnectionProfile} stored in the config; except the default profile (with a blank name), only used internally
34+
*/
35+
export function getConnectionProfiles() {
36+
const config = instance.getConnection()?.getConfig();
37+
if (config) {
38+
return config.connectionProfiles.filter(profile => Boolean(profile.name));
39+
}
40+
else {
41+
throw new Error(l10n.t("Not connected to an IBM i"));
42+
}
43+
}
44+
45+
export function getConnectionProfile(profileName: string) {
46+
return getConnectionProfiles().filter(p => p.name === profileName).at(0);
47+
}
48+
49+
export function getDefaultProfile() {
50+
const config = instance.getConnection()?.getConfig();
51+
if (config) {
52+
let defaultProfile = config.connectionProfiles.filter(profile => !profile.name).at(0);
53+
if (!defaultProfile) {
54+
defaultProfile = {
55+
name: '',
56+
homeDirectory: '',
57+
ifsShortcuts: [],
58+
currentLibrary: '',
59+
objectFilters: [],
60+
customVariables: [],
61+
libraryList: []
62+
};
63+
64+
config.connectionProfiles.push(defaultProfile);
65+
}
66+
67+
return defaultProfile;
68+
}
69+
else {
70+
throw new Error(l10n.t("Not connected to an IBM i"));
71+
}
72+
}
73+
74+
export function assignProfile(fromProfile: ConnectionProfile, toProfile: ConnectionProfile) {
75+
toProfile.homeDirectory = fromProfile.homeDirectory;
76+
toProfile.currentLibrary = fromProfile.currentLibrary;
77+
toProfile.libraryList = fromProfile.libraryList;
78+
toProfile.objectFilters = fromProfile.objectFilters;
79+
toProfile.ifsShortcuts = fromProfile.ifsShortcuts;
80+
toProfile.customVariables = fromProfile.customVariables;
81+
toProfile.setLibraryListCommand = fromProfile.setLibraryListCommand;
82+
return toProfile;
83+
}
84+
85+
export function cloneProfile(fromProfile: ConnectionProfile, newName: string): ConnectionProfile {
86+
return assignProfile(fromProfile, { name: newName } as ConnectionProfile);
87+
}
88+
89+
export function isActiveProfile(profile: ConnectionProfile) {
90+
return instance.getConnection()?.getConfig().currentProfile === profile.name;
91+
}

src/api/types.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export interface CommandData extends StandardIO {
3737

3838
export interface CommandResult {
3939
code: number;
40-
signal?: string|null;
40+
signal?: string | null;
4141
stdout: string;
4242
stderr: string;
4343
command?: string;
@@ -72,10 +72,6 @@ export interface Server {
7272
name: string
7373
}
7474

75-
export interface Profile {
76-
profile: string
77-
}
78-
7975
export interface QsysPath {
8076
asp?: string,
8177
library: string,

src/api/variables.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class Variables extends Map<string, string> {
2222
.set(`&WORKDIR`, config.homeDirectory);
2323

2424
for (const variable of config.customVariables) {
25-
this.set(`&${variable.name.toUpperCase()}`, variable.value);
25+
this.set(`&${variable.name.toUpperCase()}`, variable.value || '');
2626
}
2727
}
2828
}

0 commit comments

Comments
 (0)