Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ad5eadc
Initialized context view work
sebjulliand Oct 20, 2025
941a4f8
Added CustomEditor
sebjulliand Oct 23, 2025
a978131
Made resfresh() async
sebjulliand Oct 25, 2025
626817c
Actions management overhaul
sebjulliand Oct 25, 2025
c502113
Call new refresh context command
sebjulliand Oct 25, 2025
3fcea1b
Added custom variable management to context view
sebjulliand Oct 25, 2025
638095c
Implemented Connection Profile management
sebjulliand Oct 26, 2025
a83d44a
Removed header in profile tooltip
sebjulliand Oct 26, 2025
ff974db
Fixed code-for-ibmi:activeProfile not being set
sebjulliand Oct 26, 2025
1e2c035
Fixed library list command exec + retrieve and clear old storage value
sebjulliand Oct 27, 2025
8dc45dd
Fixed filters display in profile editor
sebjulliand Oct 27, 2025
131550d
Only show workspace action node if there are actions in it
sebjulliand Oct 27, 2025
f995092
Put back Actions status command + give focus to Actions node
sebjulliand Oct 27, 2025
744abdd
Moved node classes in their own files
sebjulliand Oct 27, 2025
46b31c5
Put profile merger function in its own file
sebjulliand Oct 27, 2025
f3faead
Fixed typings
sebjulliand Oct 27, 2025
3616a76
Allow prompting of library list command
sebjulliand Nov 1, 2025
ece6b6e
Allow active profile to be edited to change liblist command
sebjulliand Nov 1, 2025
41d39aa
Fixed actions refresh
sebjulliand Nov 5, 2025
d7e6194
Fixed profile being empty on creation
sebjulliand Nov 5, 2025
ec7bc69
Display current profile in status bar (unless profile is default)
sebjulliand Nov 5, 2025
00d6094
Renamed Context view to Environment
sebjulliand Nov 20, 2025
c9fd44f
Merge branch 'master' into profilesOverhaul
sebjulliand Nov 20, 2025
5b6d20a
Changed profiles set/unload icons
sebjulliand Nov 20, 2025
44490e1
Fixed local actions setup + show warning when file exists
sebjulliand Nov 20, 2025
941c394
Fully renamed context view to environment view
sebjulliand Nov 20, 2025
28aceb1
Ensure a document is dirty before saving it
sebjulliand Nov 20, 2025
5806194
Fixed local action creation throwing an error
sebjulliand Nov 20, 2025
6d4bf98
Added onClosed callback for custom editors
sebjulliand Nov 20, 2025
c9fc476
Prevent actions and profiles from being renamed/deleted when being ed…
sebjulliand Nov 20, 2025
a265b36
Merge branch 'master' into profilesOverhaul
sebjulliand Nov 30, 2025
4c4e6bd
Use CustomVariables.getAll where applicable
sebjulliand Nov 30, 2025
55e677d
Fixed variables created with undefined values
sebjulliand Nov 30, 2025
6d1e689
Avoid crash if variable value is undefined
sebjulliand Nov 30, 2025
3e2152d
Added icons on environment Nodes
sebjulliand Nov 30, 2025
67e989e
Enable action run command based on active editor + highlight
sebjulliand Nov 30, 2025
4bff5c3
Save setLibraryList command when changed on active profile
sebjulliand Dec 1, 2025
d930419
Prevent profile from being loaded/unloaded when being edited
sebjulliand Dec 1, 2025
1f393a3
Added 'append' option when generating local actions
sebjulliand Dec 1, 2025
db2abef
Refresh actions when location actions file change
sebjulliand Dec 1, 2025
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
515 changes: 355 additions & 160 deletions package.json

Large diffs are not rendered by default.

81 changes: 81 additions & 0 deletions src/api/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import vscode, { l10n } from "vscode";
import IBMi from "./IBMi";
import { Action } from "./types";

export async function getActions(workspace?: vscode.WorkspaceFolder) {
return workspace ? await getLocalActions(workspace) : (IBMi.connectionManager.get<Action[]>(`actions`) || []);
}

export async function updateAction(action: Action, workspace?: vscode.WorkspaceFolder, options?: { newName?: string, delete?: boolean }) {
const actions = await getActions(workspace);
const currentIndex = actions.findIndex(a => action.name === a.name);

action.name = options?.newName || action.name;

if (options?.delete) {
if (currentIndex >= 0) {
actions.splice(currentIndex, 1);
}
else {
throw new Error(l10n.t("Cannot find action {0} for delete operation", action.name));
}
}
else {
actions[currentIndex >= 0 ? currentIndex : actions.length] = action;
}

if (workspace) {
const actionsFile = (await getLocalActionsFiles(workspace)).at(0);
if (actionsFile) {
await vscode.workspace.fs.writeFile(actionsFile, Buffer.from(JSON.stringify(actions, undefined, 2), "utf-8"));
}
else {
throw new Error(l10n.t("No local actions file defined in workspace {0}", workspace.name));
}
}
else {
await IBMi.connectionManager.set(`actions`, actions);
}
}

export async function getLocalActionsFiles(workspace: vscode.WorkspaceFolder) {
return workspace ? await vscode.workspace.findFiles(new vscode.RelativePattern(workspace, `**/.vscode/actions.json`)) : [];
}

async function getLocalActions(currentWorkspace: vscode.WorkspaceFolder) {
const actions: Action[] = [];

if (currentWorkspace) {
const actionsFiles = await getLocalActionsFiles(currentWorkspace);

for (const file of actionsFiles) {
const actionsContent = await vscode.workspace.fs.readFile(file);
try {
const actionsJson: Action[] = JSON.parse(actionsContent.toString());

// Maybe one day replace this with real schema validation
if (Array.isArray(actionsJson)) {
actionsJson.forEach((action, index) => {
if (
typeof action.name === `string` &&
typeof action.command === `string` &&
[`ile`, `pase`, `qsh`].includes(action.environment) &&
(!action.extensions || Array.isArray(action.extensions))
) {
actions.push({
...action,
type: `file`
});
} else {
throw new Error(`Invalid Action defined at index ${index}.`);
}
})
}
} catch (e: any) {
vscode.window.showErrorMessage(`Error parsing ${file.fsPath}: ${e.message}\n`);
}
};
}

return actions;
}
3 changes: 1 addition & 2 deletions src/api/configuration/config/ConnectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ function initialize(parameters: Partial<ConnectionConfig>): ConnectionConfig {
autoClearTempData: parameters.autoClearTempData || false,
customVariables: parameters.customVariables || [],
connectionProfiles: parameters.connectionProfiles || [],
commandProfiles: parameters.commandProfiles || [],
ifsShortcuts: parameters.ifsShortcuts || [],
/** Default auto sorting of shortcuts to off */
autoSortIFSShortcuts: parameters.autoSortIFSShortcuts || false,
Expand Down Expand Up @@ -87,7 +86,7 @@ export class ConnectionManager {
}

async storeNew(data: ConnectionData) {
const connections = await this.getAll();
const connections = this.getAll();
const newId = connections.length;
connections.push(data);
await this.setAll(connections);
Expand Down
10 changes: 3 additions & 7 deletions src/api/configuration/config/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FilterType } from "../../Filter";
import { DeploymentMethod, ConnectionData } from "../../types";
import { ConnectionData, DeploymentMethod } from "../../types";

export type DefaultOpenMode = "browse" | "edit";
export type ReconnectMode = "always" | "never" | "ask";
Expand All @@ -8,7 +8,6 @@ export interface ConnectionConfig extends ConnectionProfile {
host: string;
autoClearTempData: boolean;
connectionProfiles: ConnectionProfile[];
commandProfiles: CommandProfile[];
autoSortIFSShortcuts: boolean;
tempLibrary: string;
tempDir: string;
Expand All @@ -33,6 +32,7 @@ export interface ConnectionConfig extends ConnectionProfile {
protectedPaths: string[];
showHiddenFiles: boolean;
lastDownloadLocation: string;
currentProfile?: string
[name: string]: any;
}

Expand Down Expand Up @@ -64,11 +64,7 @@ export interface ConnectionProfile {
objectFilters: ObjectFilters[]
ifsShortcuts: string[]
customVariables: CustomVariable[]
}

export interface CommandProfile {
name: string;
command: string;
setLibraryListCommand?: string
}

export interface StoredConnection {
Expand Down
17 changes: 9 additions & 8 deletions src/api/configuration/storage/ConnectionStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,6 @@ export class ConnectionStorage {
await this.internalStorage.set(SOURCE_LIST_KEY, sourceList);
}

getLastProfile() {
return this.internalStorage.get<string>(LAST_PROFILE_KEY);
}

async setLastProfile(lastProfile: string) {
await this.internalStorage.set(LAST_PROFILE_KEY, lastProfile);
}

getPreviousCurLibs() {
return this.internalStorage.get<string[]>(PREVIOUS_CUR_LIBS_KEY) || [];
}
Expand Down Expand Up @@ -94,6 +86,15 @@ export class ConnectionStorage {
await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, undefined);
}

/** @deprecated stored in ConnectionSettings now */
getLastProfile() {
return this.internalStorage.get<string>(LAST_PROFILE_KEY);
}

async clearDeprecatedLastProfile() {
await this.internalStorage.set(LAST_PROFILE_KEY, undefined);
}

async grantExtensionAuthorisation(extensionId: string, displayName: string) {
const extensions = this.getAuthorisedExtensions();
if (!this.getExtensionAuthorisation(extensionId)) {
Expand Down
91 changes: 91 additions & 0 deletions src/api/connectionProfiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { l10n } from "vscode";
import { instance } from "../instantiate";
import IBMi from "./IBMi";
import { ConnectionProfile } from "./types";

export async function updateConnectionProfile(profile: ConnectionProfile, options?: { newName?: string, delete?: boolean }) {
const config = instance.getConnection()?.getConfig();
if (config) {
const profiles = config.connectionProfiles;
const index = profiles.findIndex(p => p.name === profile.name);

if (options?.delete) {
if (index < 0) {
throw new Error(l10n.t("Profile {0} not found for deletion.", profile.name));
}
profiles.splice(index, 1);
}
else {
profile.name = options?.newName || profile.name;
profiles[index < 0 ? profiles.length : index] = profile;
}

if (isActiveProfile(profile)) {
//Only update the setLibraryListCommand in the current config since the editor is the only place it can be changed
config.setLibraryListCommand = profile.setLibraryListCommand;
}

await IBMi.connectionManager.update(config);
}
}

/**
* @returns ann arry of {@link ConnectionProfile} stored in the config; except the default profile (with a blank name), only used internally
*/
export function getConnectionProfiles() {
const config = instance.getConnection()?.getConfig();
if (config) {
return config.connectionProfiles.filter(profile => Boolean(profile.name));
}
else {
throw new Error(l10n.t("Not connected to an IBM i"));
}
}

export function getConnectionProfile(profileName: string) {
return getConnectionProfiles().filter(p => p.name === profileName).at(0);
}

export function getDefaultProfile() {
const config = instance.getConnection()?.getConfig();
if (config) {
let defaultProfile = config.connectionProfiles.filter(profile => !profile.name).at(0);
if (!defaultProfile) {
defaultProfile = {
name: '',
homeDirectory: '',
ifsShortcuts: [],
currentLibrary: '',
objectFilters: [],
customVariables: [],
libraryList: []
};

config.connectionProfiles.push(defaultProfile);
}

return defaultProfile;
}
else {
throw new Error(l10n.t("Not connected to an IBM i"));
}
}

export function assignProfile(fromProfile: ConnectionProfile, toProfile: ConnectionProfile) {
toProfile.homeDirectory = fromProfile.homeDirectory;
toProfile.currentLibrary = fromProfile.currentLibrary;
toProfile.libraryList = fromProfile.libraryList;
toProfile.objectFilters = fromProfile.objectFilters;
toProfile.ifsShortcuts = fromProfile.ifsShortcuts;
toProfile.customVariables = fromProfile.customVariables;
toProfile.setLibraryListCommand = fromProfile.setLibraryListCommand;
return toProfile;
}

export function cloneProfile(fromProfile: ConnectionProfile, newName: string): ConnectionProfile {
return assignProfile(fromProfile, { name: newName } as ConnectionProfile);
}

export function isActiveProfile(profile: ConnectionProfile) {
return instance.getConnection()?.getConfig().currentProfile === profile.name;
}
6 changes: 1 addition & 5 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface CommandData extends StandardIO {

export interface CommandResult {
code: number;
signal?: string|null;
signal?: string | null;
stdout: string;
stderr: string;
command?: string;
Expand Down Expand Up @@ -72,10 +72,6 @@ export interface Server {
name: string
}

export interface Profile {
profile: string
}

export interface QsysPath {
asp?: string,
library: string,
Expand Down
2 changes: 1 addition & 1 deletion src/api/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class Variables extends Map<string, string> {
.set(`&WORKDIR`, config.homeDirectory);

for (const variable of config.customVariables) {
this.set(`&${variable.name.toUpperCase()}`, variable.value);
this.set(`&${variable.name.toUpperCase()}`, variable.value || '');
}
}
}
Expand Down
Loading
Loading