diff --git a/package.json b/package.json index 94c7215ba..94e757ba8 100644 --- a/package.json +++ b/package.json @@ -1028,13 +1028,13 @@ }, { "command": "code-for-ibmi.launchTerminalPicker", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Launch Terminal Picker", "category": "IBM i" }, { "command": "code-for-ibmi.goToFile", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Go to File...", "category": "IBM i", "icon": "$(go-to-file)" @@ -1162,7 +1162,7 @@ }, { "command": "code-for-ibmi.runAction", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Run Action...", "category": "IBM i", "icon": "$(file-binary)" @@ -1259,28 +1259,28 @@ }, { "command": "code-for-ibmi.createMember", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "New Member...", "category": "IBM i", "icon": "$(new-file)" }, { "command": "code-for-ibmi.copyMember", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Copy...", "category": "IBM i", "icon": "$(files)" }, { "command": "code-for-ibmi.updateMemberText", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Change Description...", "category": "IBM i", "icon": "$(symbol-file)" }, { "command": "code-for-ibmi.renameQSYS", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Rename...", "category": "IBM i", "icon": "$(files)" @@ -1293,7 +1293,7 @@ }, { "command": "code-for-ibmi.uploadAndReplaceMemberAsFile", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Upload and Replace...", "category": "IBM i" }, @@ -1325,7 +1325,7 @@ }, { "command": "code-for-ibmi.deleteIFS", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Delete...", "category": "IBM i" }, @@ -1337,14 +1337,14 @@ }, { "command": "code-for-ibmi.moveIFS", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Rename/Move...", "category": "IBM i", "icon": "$(files)" }, { "command": "code-for-ibmi.copyIFS", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Copy...", "category": "IBM i", "icon": "$(files)" @@ -1358,21 +1358,21 @@ }, { "command": "code-for-ibmi.createDirectory", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "New Directory...", "category": "IBM i", "icon": "$(new-folder)" }, { "command": "code-for-ibmi.createStreamfile", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "New File...", "category": "IBM i", "icon": "$(new-file)" }, { "command": "code-for-ibmi.uploadStreamfile", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Upload...", "category": "IBM i", "icon": "$(cloud-upload)" @@ -1382,11 +1382,11 @@ "title": "Deploy Workspace", "category": "IBM i", "icon": "$(cloud-upload)", - "enablement": "code-for-ibmi:connected && workspaceFolderCount >= 1" + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly && workspaceFolderCount >= 1" }, { "command": "code-for-ibmi.setDeployLocation", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Set Deploy Workspace Location", "category": "IBM i", "icon": "$(cloud-upload)" @@ -1476,7 +1476,7 @@ }, { "command": "code-for-ibmi.objectBrowser.delete", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Delete...", "category": "IBM i", "icon": "$(remove)" @@ -1537,35 +1537,35 @@ }, { "command": "code-for-ibmi.createSourceFile", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "New Source File...", "category": "IBM i", "icon": "$(new-file)" }, { "command": "code-for-ibmi.createLibrary", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "New Library...", "category": "IBM i", "icon": "$(file-directory-create)" }, { "command": "code-for-ibmi.changeObjectDesc", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Change Description...", "category": "IBM i", "icon": "$(symbol-file)" }, { "command": "code-for-ibmi.copyObject", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Copy...", "category": "IBM i", "icon": "$(symbol-file)" }, { "command": "code-for-ibmi.moveObject", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Move...", "category": "IBM i", "icon": "$(symbol-file)" @@ -1599,6 +1599,7 @@ }, { "command": "code-for-ibmi.openTerminalHere", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "title": "Open Terminal Here", "category": "IBM i" }, @@ -1616,7 +1617,7 @@ { "command": "code-for-ibmi.edit", "title": "Edit", - "enablement": "code-for-ibmi:connected", + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly", "category": "IBM i" }, { @@ -1692,7 +1693,7 @@ "title": "Reset keyboard", "category": "IBM i", "icon": "$(keyboard)", - "enablement": "code-for-ibmi:connected" + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly" }, { "command": "code-for-ibmi.testing.connectWithFixture", @@ -1706,7 +1707,7 @@ "title": "Generate binder source", "category": "IBM i", "icon": "$(plus)", - "enablement": "code-for-ibmi:connected" + "enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly" } ], "keybindings": [ @@ -1719,7 +1720,7 @@ "command": "code-for-ibmi.launchDeploy", "key": "ctrl+shift+e", "mac": "cmd+shift+e", - "when": "workspaceFolderCount >= 1 && code-for-ibmi:connected" + "when": "workspaceFolderCount >= 1 && code-for-ibmi:connected && !code-for-ibmi:isReadonly" }, { "command": "code-for-ibmi.goToFile", diff --git a/schemas/settings.json b/schemas/settings.json index 965fd6277..9c0c35f64 100644 --- a/schemas/settings.json +++ b/schemas/settings.json @@ -7,7 +7,7 @@ "readOnlyMode": { "type": "boolean", "default": false, - "description": "Always open source members and IFS files in read-only mode." + "description": "Always open source members and IFS files in read-only mode. Content on the server can not be changed." }, "tempLibrary": { "type": "string", diff --git a/src/filesystems/ifsFs.ts b/src/filesystems/ifsFs.ts index 0f25736e5..7efeec8d2 100644 --- a/src/filesystems/ifsFs.ts +++ b/src/filesystems/ifsFs.ts @@ -70,6 +70,10 @@ export class IFSFS implements vscode.FileSystemProvider { const path = uri.path; const connection = instance.getConnection(); if (connection) { + const readonly = connection.getConfig().readOnlyMode; + if (readonly) { + throw new FileSystemError("Connection is in readonly mode"); + } const contentApi = connection.getContent(); if (!content.length) { //Coming from "Save as" this.savedAsFiles.add(path); diff --git a/src/filesystems/local/deployment.ts b/src/filesystems/local/deployment.ts index 1a01606ea..ea2e8ef9d 100644 --- a/src/filesystems/local/deployment.ts +++ b/src/filesystems/local/deployment.ts @@ -56,8 +56,12 @@ export namespace Deployment { const storage = instance.getStorage(); if (workspaces && connection && storage) { - if (workspaces.length > 0) { + const config = connection.getConfig(); + + if (workspaces.length > 0 && !config.readOnlyMode) { button.show(); + } else { + button.hide(); } const existingPaths = storage.getDeployment(); diff --git a/src/instantiate.ts b/src/instantiate.ts index d21254abc..e0f61ceae 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -105,12 +105,12 @@ async function updateConnectedBar() { if (connection) { const config = connection.getConfig(); connectedBarItem.text = `$(${config.readOnlyMode ? "lock" : "settings-gear"}) ${config.name}`; - + const terminalMenuItem = config.readOnlyMode ? `` : `[$(terminal) Terminals](command:code-for-ibmi.launchTerminalPicker)`; const debugRunning = await isDebugEngineRunning(); connectedBarItem.tooltip = new vscode.MarkdownString([ `[$(settings-gear) Settings](command:code-for-ibmi.showAdditionalSettings)`, `[$(file-binary) Actions](command:code-for-ibmi.showActionsMaintenance)`, - `[$(terminal) Terminals](command:code-for-ibmi.launchTerminalPicker)`, + terminalMenuItem, debugPTFInstalled(connection) ? `[$(${debugRunning ? "bug" : "debug"}) Debugger ${((await getDebugServiceDetails(connection)).version)} (${debugRunning ? "on" : "off"})](command:ibmiDebugBrowser.focus)` : @@ -129,6 +129,8 @@ async function onConnected() { updateConnectedBar(); + vscode.commands.executeCommand(`setContext`, `code-for-ibmi:isReadonly`, config?.readOnlyMode); + // Enable the profile view if profiles exist. vscode.commands.executeCommand(`setContext`, `code-for-ibmi:hasProfiles`, (config?.connectionProfiles || []).length > 0); } @@ -154,4 +156,3 @@ async function onDisconnected() { connectedBarItem, ].forEach(barItem => barItem.hide()) } - diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index f5974bfca..889b1fec9 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -68,7 +68,7 @@ export class SettingsUI { if (serverConfig && serverConfig.codefori) { for (const field of currentSection.fields) { if (!field.id) continue; - + if (serverConfig.codefori[field.id] !== undefined) { field.readonly = true; } @@ -76,7 +76,7 @@ export class SettingsUI { } } - const restartFields = [`showDescInLibList`, `tempDir`, `debugCertDirectory`]; + const restartFields = [`readOnlyMode`, `showDescInLibList`, `tempDir`, `debugCertDirectory`]; let restart = false; const featuresTab = new Section(); @@ -88,6 +88,8 @@ export class SettingsUI { } featuresTab + .addCheckbox(`readOnlyMode`, `Read only mode`, `When enabled, content on the server can not be changed. Requires restart when changed.`, config.readOnlyMode) + .addHorizontalRule() .addCheckbox(`quickConnect`, `Quick Connect`, `When enabled, server settings from previous connection will be used, resulting in much quicker connection. If server settings are changed, right-click the connection in Connection Browser and select Connect and Reload Server Settings to refresh the cache.`, config.quickConnect) .addCheckbox(`showDescInLibList`, `Show description of libraries in User Library List view`, `When enabled, library text and attribute will be shown in User Library List. It is recommended to also enable SQL for this.`, config.showDescInLibList) .addCheckbox(`showHiddenFiles`, `Show hidden files and directories in IFS browser.`, `When disabled, hidden files and directories (i.e. names starting with '.') will not be shown in the IFS browser, except for special config files.`, config.showHiddenFiles) @@ -154,7 +156,6 @@ export class SettingsUI { } ], `Set your Default Deployment Method. This is used when deploying from the local workspace to the server.`) .addHorizontalRule() - .addCheckbox(`readOnlyMode`, `Read only mode`, `When enabled, source members and IFS files will always be opened in read-only mode.`, config.readOnlyMode) .addInput(`protectedPaths`, `Protected paths`, `A comma separated list of libraries and/or IFS directories whose members will always be opened in read-only mode. (Example: QGPL, /home/QSECOFR, MYLIB, /QIBM)`, { default: config.protectedPaths.join(`, `) }); setFieldsReadOnly(sourceTab); @@ -204,7 +205,7 @@ export class SettingsUI { .set("Debug port", config.debugPort); debugServiceConfig.set("SEP debug port", config.debugSepPort) - + debuggerTab.addParagraph(``); debuggerTab.addCheckbox(`debugUpdateProductionFiles`, `Update production files`, `Determines whether the job being debugged can update objects in production (*PROD) libraries.`, config.debugUpdateProductionFiles) @@ -338,7 +339,7 @@ export class SettingsUI { } } - if (restartFields.some(item => data[item] && data[item] !== config[item])) { + if (restartFields.some(item => data[item] !== config[item])) { restart = true; } @@ -395,7 +396,7 @@ export class SettingsUI { .addPassword(`password`, `${vscode.l10n.t(`Password`)}${storedPassword ? ` (${vscode.l10n.t(`stored`)})` : ``}`, vscode.l10n.t("Only provide a password if you want to update an existing one or set a new one.")) .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${privateKeyPath})` : ``}`, privateKeyWarning + vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) .addHorizontalRule() - .addInput(`readyTimeout`, vscode.l10n.t(`Connection Timeout (in milliseconds)`), vscode.l10n.t(`How long to wait for the SSH handshake to complete.`), { inputType: "number", min: 1, default: stored.readyTimeout ? String(stored.readyTimeout) : "20000" }) + .addInput(`readyTimeout`, vscode.l10n.t(`Connection Timeout (in milliseconds)`), vscode.l10n.t(`How long to wait for the SSH handshake to complete.`), { inputType: "number", min: 1, default: stored.readyTimeout ? String(stored.readyTimeout) : "20000" }) .addButtons( { id: `submitButton`, label: vscode.l10n.t(`Save`), requiresValidation: true }, { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) }