Skip to content

Commit f976283

Browse files
committed
feat: add option to disable all deployment notifications (#852)
Add `coder.disableNotifications` setting that suppresses all notification prompts from the Coder deployment (workspace updates, autostop warnings, deletion warnings, inbox alerts). WebSocket connections remain active so context updates, status bar, and onChange events continue to work. Also introduces a `src/settings/` folder to organize settings accessor utilities: - `settings/notifications.ts` - notification toggle checks - `settings/headers.ts` - header command settings (extracted from headers.ts) - `settings/cli.ts` - CLI flag settings (moved from cliConfig.ts) Adds comprehensive tests for WorkspaceMonitor, Inbox, and notification settings, along with shared MockEventStream and MockContextManager test helpers. Closes #852
1 parent 9f481ff commit f976283

25 files changed

+758
-142
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@
121121
"type": "boolean",
122122
"default": false
123123
},
124+
"coder.disableNotifications": {
125+
"markdownDescription": "Disable all notification prompts from the Coder deployment (workspace updates, scheduling reminders, resource alerts, etc.). Notifications are delivered by your Coder server and displayed by this extension.",
126+
"type": "boolean",
127+
"default": false
128+
},
124129
"coder.disableUpdateNotifications": {
125130
"markdownDescription": "Disable notifications when workspace template updates are available.",
126131
"type": "boolean",

src/api/coderApi.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { watchConfigurationChanges } from "../configWatcher";
2121
import { ClientCertificateError } from "../error/clientCertificateError";
2222
import { toError } from "../error/errorUtils";
2323
import { ServerCertificateError } from "../error/serverCertificateError";
24-
import { getHeaderCommand, getHeaders } from "../headers";
24+
import { getHeaders } from "../headers";
2525
import { EventStreamLogger } from "../logging/eventStreamLogger";
2626
import {
2727
createRequestMeta,
@@ -35,6 +35,7 @@ import {
3535
HttpClientLogLevel,
3636
} from "../logging/types";
3737
import { sizeOf } from "../logging/utils";
38+
import { getHeaderCommand } from "../settings/headers";
3839
import { HttpStatusCode, WebSocketCloseCode } from "../websocket/codes";
3940
import {
4041
type UnidirectionalStream,

src/api/workspace.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
import { spawn } from "node:child_process";
88
import * as vscode from "vscode";
99

10-
import { type CliAuth, getGlobalFlags } from "../cliConfig";
1110
import { type FeatureSet } from "../featureSet";
11+
import { type CliAuth, getGlobalFlags } from "../settings/cli";
1212
import { escapeCommandArg } from "../util";
1313
import { type UnidirectionalStream } from "../websocket/eventStreamConnection";
1414

src/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import * as vscode from "vscode";
99

1010
import { createWorkspaceIdentifier, extractAgents } from "./api/api-helper";
1111
import { type CoderApi } from "./api/coderApi";
12-
import { getGlobalFlags, resolveCliAuth } from "./cliConfig";
1312
import { type CliManager } from "./core/cliManager";
1413
import * as cliUtils from "./core/cliUtils";
1514
import { type ServiceContainer } from "./core/container";
@@ -28,6 +27,7 @@ import {
2827
RECOMMENDED_SSH_SETTINGS,
2928
applySettingOverrides,
3029
} from "./remote/userSettings";
30+
import { getGlobalFlags, resolveCliAuth } from "./settings/cli";
3131
import { escapeCommandArg, toRemoteAuthority, toSafeHost } from "./util";
3232
import { vscodeProposed } from "./vscodeProposed";
3333
import {

src/core/cliCredentialManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import path from "node:path";
55
import { promisify } from "node:util";
66
import * as semver from "semver";
77

8-
import { isKeyringEnabled } from "../cliConfig";
98
import { isAbortError } from "../error/errorUtils";
109
import { featureSetForVersion } from "../featureSet";
11-
import { getHeaderArgs } from "../headers";
10+
import { isKeyringEnabled } from "../settings/cli";
11+
import { getHeaderArgs } from "../settings/headers";
1212
import { renameWithRetry, tempFilePath, toSafeHost } from "../util";
1313

1414
import * as cliUtils from "./cliUtils";

src/core/cliManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import * as semver from "semver";
1010
import * as vscode from "vscode";
1111

1212
import { errToStr } from "../api/api-helper";
13-
import { isKeyringEnabled } from "../cliConfig";
1413
import * as pgp from "../pgp";
1514
import { withCancellableProgress, withOptionalProgress } from "../progress";
15+
import { isKeyringEnabled } from "../settings/cli";
1616
import { tempFilePath, toSafeHost } from "../util";
1717
import { vscodeProposed } from "../vscodeProposed";
1818

src/headers.ts

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,10 @@
1-
import * as os from "node:os";
2-
31
import { execCommand } from "./command/exec";
42
import { type Logger } from "./logging/logger";
5-
import { escapeCommandArg } from "./util";
6-
7-
import type { WorkspaceConfiguration } from "vscode";
8-
9-
export function getHeaderCommand(
10-
config: Pick<WorkspaceConfiguration, "get">,
11-
): string | undefined {
12-
const cmd =
13-
config.get<string>("coder.headerCommand")?.trim() ||
14-
process.env.CODER_HEADER_COMMAND?.trim();
15-
16-
return cmd || undefined;
17-
}
18-
19-
export function getHeaderArgs(
20-
config: Pick<WorkspaceConfiguration, "get">,
21-
): string[] {
22-
// Escape a command line to be executed by the Coder binary, so ssh doesn't substitute variables.
23-
const escapeSubcommand: (str: string) => string =
24-
os.platform() === "win32"
25-
? // On Windows variables are %VAR%, and we need to use double quotes.
26-
(str) => escapeCommandArg(str).replace(/%/g, "%%")
27-
: // On *nix we can use single quotes to escape $VARS.
28-
// Note single quotes cannot be escaped inside single quotes.
29-
(str) => `'${str.replace(/'/g, "'\\''")}'`;
30-
31-
const command = getHeaderCommand(config);
32-
if (!command) {
33-
return [];
34-
}
35-
return ["--header-command", escapeSubcommand(command)];
36-
}
373

384
/**
39-
* getHeaders executes the header command and parses the headers from stdout.
40-
* Both stdout and stderr are logged on error but stderr is otherwise ignored.
41-
* Throws an error if the process exits with non-zero or the JSON is invalid.
42-
* Returns undefined if there is no header command set. No effort is made to
43-
* validate the JSON other than making sure it can be parsed.
5+
* Executes the header command and parses headers from stdout.
6+
* Throws on non-zero exit or malformed output. Returns empty headers if no
7+
* command is set.
448
*/
459
export async function getHeaders(
4610
url: string | undefined,

src/inbox.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as vscode from "vscode";
22

3+
import { areNotificationsDisabled } from "./settings/notifications";
4+
35
import type {
46
Workspace,
57
GetInboxNotificationResponse,
@@ -53,7 +55,9 @@ export class Inbox implements vscode.Disposable {
5355
socket.addEventListener("message", (data) => {
5456
if (data.parseError) {
5557
logger.error("Failed to parse inbox message", data.parseError);
56-
} else {
58+
} else if (
59+
!areNotificationsDisabled(vscode.workspace.getConfiguration())
60+
) {
5761
vscode.window.showInformationMessage(
5862
data.parsedMessage.notification.title,
5963
);

src/login/loginCoordinator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import * as vscode from "vscode";
44

55
import { CoderApi } from "../api/coderApi";
66
import { needToken } from "../api/utils";
7-
import { isKeyringEnabled } from "../cliConfig";
87
import { CertificateError } from "../error/certificateError";
98
import { OAuthAuthorizer } from "../oauth/authorizer";
109
import { buildOAuthTokenData } from "../oauth/utils";
1110
import { withOptionalProgress } from "../progress";
1211
import { maybeAskAuthMethod, maybeAskUrl } from "../promptUtils";
12+
import { isKeyringEnabled } from "../settings/cli";
1313
import { vscodeProposed } from "../vscodeProposed";
1414

1515
import type { User } from "coder/site/src/api/typesGenerated";

src/remote/remote.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ import { extractAgents } from "../api/api-helper";
2020
import { AuthInterceptor } from "../api/authInterceptor";
2121
import { CoderApi } from "../api/coderApi";
2222
import { needToken } from "../api/utils";
23-
import {
24-
type CliAuth,
25-
getGlobalFlags,
26-
getGlobalFlagsRaw,
27-
getSshFlags,
28-
resolveCliAuth,
29-
} from "../cliConfig";
3023
import { type Commands } from "../commands";
3124
import { watchConfigurationChanges } from "../configWatcher";
3225
import { type CliManager } from "../core/cliManager";
@@ -37,11 +30,18 @@ import { type PathResolver } from "../core/pathResolver";
3730
import { type SecretsManager } from "../core/secretsManager";
3831
import { toError } from "../error/errorUtils";
3932
import { featureSetForVersion, type FeatureSet } from "../featureSet";
40-
import { getHeaderCommand } from "../headers";
4133
import { Inbox } from "../inbox";
4234
import { type Logger } from "../logging/logger";
4335
import { type LoginCoordinator } from "../login/loginCoordinator";
4436
import { OAuthSessionManager } from "../oauth/sessionManager";
37+
import {
38+
type CliAuth,
39+
getGlobalFlags,
40+
getGlobalFlagsRaw,
41+
getSshFlags,
42+
resolveCliAuth,
43+
} from "../settings/cli";
44+
import { getHeaderCommand } from "../settings/headers";
4545
import {
4646
AuthorityPrefix,
4747
escapeCommandArg,

0 commit comments

Comments
 (0)