Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions packages/cloud/src/CloudService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ export class CloudService extends EventEmitter<CloudServiceEvents> implements Di
return this.settingsService!.updateUserSettings(settings)
}

public isTaskSyncEnabled(): boolean {
this.ensureInitialized()
return this.settingsService!.isTaskSyncEnabled()
}

// TelemetryClient

public captureEvent(event: TelemetryEvent): void {
Expand Down
15 changes: 15 additions & 0 deletions packages/cloud/src/CloudSettingsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,21 @@ export class CloudSettingsService extends EventEmitter<SettingsServiceEvents> im
}
}

public isTaskSyncEnabled(): boolean {
// Org settings take precedence
if (this.authService.getStoredOrganizationId()) {
return this.settings?.cloudSettings?.recordTaskMessages ?? false
}

// User settings default to true if unspecified
const userSettings = this.userSettings
if (userSettings) {
return userSettings.settings.taskSyncEnabled ?? true
}

return false
}

private async removeSettings(): Promise<void> {
this.settings = undefined
this.userSettings = undefined
Expand Down
7 changes: 7 additions & 0 deletions packages/cloud/src/StaticSettingsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class StaticSettingsService implements SettingsService {
},
settings: {
extensionBridgeEnabled: true,
taskSyncEnabled: true,
},
version: 1,
}
Expand All @@ -65,13 +66,19 @@ export class StaticSettingsService implements SettingsService {
public getUserSettingsConfig(): UserSettingsConfig {
return {
extensionBridgeEnabled: true,
taskSyncEnabled: true,
}
}

public async updateUserSettings(_settings: Partial<UserSettingsConfig>): Promise<boolean> {
throw new Error("User settings updates are not supported in static mode")
}

public isTaskSyncEnabled(): boolean {
// Static settings always enable task sync
return true
}

public dispose(): void {
// No resources to clean up for static settings.
}
Expand Down
4 changes: 2 additions & 2 deletions packages/cloud/src/TelemetryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,9 @@ export class CloudTelemetryClient extends BaseTelemetryClient {
return false
}

// Only record message telemetry if a cloud account is present and explicitly configured to record messages
// Only record message telemetry if task sync is enabled
if (eventName === TelemetryEventName.TASK_MESSAGE) {
return this.settingsService.getSettings()?.cloudSettings?.recordTaskMessages || false
return this.settingsService.isTaskSyncEnabled()
}

// Other telemetry types are capturable at this point
Expand Down
8 changes: 8 additions & 0 deletions packages/cloud/src/__tests__/CloudService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe("CloudService", () => {
initialize: ReturnType<typeof vi.fn>
getSettings: ReturnType<typeof vi.fn>
getAllowList: ReturnType<typeof vi.fn>
isTaskSyncEnabled: ReturnType<typeof vi.fn>
dispose: ReturnType<typeof vi.fn>
on: ReturnType<typeof vi.fn>
off: ReturnType<typeof vi.fn>
Expand Down Expand Up @@ -130,6 +131,7 @@ describe("CloudService", () => {
initialize: vi.fn(),
getSettings: vi.fn(),
getAllowList: vi.fn(),
isTaskSyncEnabled: vi.fn().mockReturnValue(true),
dispose: vi.fn(),
on: vi.fn(),
off: vi.fn(),
Expand Down Expand Up @@ -343,6 +345,12 @@ describe("CloudService", () => {
cloudService.getAllowList()
expect(mockSettingsService.getAllowList).toHaveBeenCalled()
})

it("should delegate isTaskSyncEnabled to SettingsService", () => {
const result = cloudService.isTaskSyncEnabled()
expect(mockSettingsService.isTaskSyncEnabled).toHaveBeenCalled()
expect(result).toBe(true)
})
})

describe("error handling", () => {
Expand Down
189 changes: 189 additions & 0 deletions packages/cloud/src/__tests__/CloudSettingsService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe("CloudSettingsService", () => {
getSessionToken: ReturnType<typeof vi.fn>
hasActiveSession: ReturnType<typeof vi.fn>
on: ReturnType<typeof vi.fn>
getStoredOrganizationId: ReturnType<typeof vi.fn>
}
let mockRefreshTimer: {
start: ReturnType<typeof vi.fn>
Expand Down Expand Up @@ -63,6 +64,7 @@ describe("CloudSettingsService", () => {
getSessionToken: vi.fn(),
hasActiveSession: vi.fn().mockReturnValue(false),
on: vi.fn(),
getStoredOrganizationId: vi.fn().mockReturnValue(null),
}

mockRefreshTimer = {
Expand Down Expand Up @@ -532,4 +534,191 @@ describe("CloudSettingsService", () => {
expect(mockContext.globalState.update).toHaveBeenCalledWith("user-settings", undefined)
})
})

describe("isTaskSyncEnabled", () => {
beforeEach(async () => {
await cloudSettingsService.initialize()
})

it("should return true when org recordTaskMessages is true", () => {
// Set up mock settings with org recordTaskMessages = true
const mockSettings = {
version: 1,
cloudSettings: {
recordTaskMessages: true,
},
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

// Mock that user has organization ID (indicating org settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue("org-123")

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(true)
})

it("should return false when org recordTaskMessages is false", () => {
// Set up mock settings with org recordTaskMessages = false
const mockSettings = {
version: 1,
cloudSettings: {
recordTaskMessages: false,
},
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

// Mock that user has organization ID (indicating org settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue("org-123")

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(false)
})

it("should fall back to user taskSyncEnabled when org recordTaskMessages is undefined", () => {
// Set up mock settings with org recordTaskMessages undefined
const mockSettings = {
version: 1,
cloudSettings: {},
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

const mockUserSettings = {
version: 1,
features: {},
settings: {
taskSyncEnabled: true,
},
}

// Mock that user has no organization ID (indicating user settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue(null)

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings
;(cloudSettingsService as unknown as { userSettings: typeof mockUserSettings }).userSettings =
mockUserSettings

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(true)
})

it("should return false when user taskSyncEnabled is false", () => {
// Set up mock settings with org recordTaskMessages undefined
const mockSettings = {
version: 1,
cloudSettings: {},
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

const mockUserSettings = {
version: 1,
features: {},
settings: {
taskSyncEnabled: false,
},
}

// Mock that user has no organization ID (indicating user settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue(null)

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings
;(cloudSettingsService as unknown as { userSettings: typeof mockUserSettings }).userSettings =
mockUserSettings

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(false)
})

it("should return true when user taskSyncEnabled is undefined (default)", () => {
// Set up mock settings with org recordTaskMessages undefined
const mockSettings = {
version: 1,
cloudSettings: {},
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

const mockUserSettings = {
version: 1,
features: {},
settings: {},
}

// Mock that user has no organization ID (indicating user settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue(null)

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings
;(cloudSettingsService as unknown as { userSettings: typeof mockUserSettings }).userSettings =
mockUserSettings

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(true)
})

it("should return false when no settings are available", () => {
// Mock that user has no organization ID
mockAuthService.getStoredOrganizationId.mockReturnValue(null)

// Clear both settings
;(cloudSettingsService as unknown as { settings: undefined }).settings = undefined
;(cloudSettingsService as unknown as { userSettings: undefined }).userSettings = undefined

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(false)
})

it("should return false when only org settings are available but cloudSettings is undefined", () => {
const mockSettings = {
version: 1,
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

// Mock that user has organization ID (indicating org settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue("org-123")

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings
;(cloudSettingsService as unknown as { userSettings: undefined }).userSettings = undefined

expect(cloudSettingsService.isTaskSyncEnabled()).toBe(false)
})

it("should prioritize org settings over user settings", () => {
// Set up conflicting settings: org = false, user = true
const mockSettings = {
version: 1,
cloudSettings: {
recordTaskMessages: false,
},
defaultSettings: {},
allowList: { allowAll: true, providers: {} },
}

const mockUserSettings = {
version: 1,
features: {},
settings: {
taskSyncEnabled: true,
},
}

// Mock that user has organization ID (indicating org settings should be used)
mockAuthService.getStoredOrganizationId.mockReturnValue("org-123")

// Use reflection to set private settings
;(cloudSettingsService as unknown as { settings: typeof mockSettings }).settings = mockSettings
;(cloudSettingsService as unknown as { userSettings: typeof mockUserSettings }).userSettings =
mockUserSettings

// Should return false (org setting takes precedence)
expect(cloudSettingsService.isTaskSyncEnabled()).toBe(false)
})
})
})
23 changes: 23 additions & 0 deletions packages/cloud/src/__tests__/StaticSettingsService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,28 @@ describe("StaticSettingsService", () => {

expect(mockLog).not.toHaveBeenCalled()
})

describe("isTaskSyncEnabled", () => {
it("should always return true", () => {
const service = new StaticSettingsService(validBase64)
expect(service.isTaskSyncEnabled()).toBe(true)
})

it("should return true regardless of settings content", () => {
// Create settings with different content
const differentSettings = {
version: 2,
cloudSettings: {
recordTaskMessages: false,
},
defaultSettings: {},
allowList: { allowAll: false, providers: {} },
}
const differentBase64 = Buffer.from(JSON.stringify(differentSettings)).toString("base64")

const service = new StaticSettingsService(differentBase64)
expect(service.isTaskSyncEnabled()).toBe(true)
})
})
})
})
Loading
Loading