Skip to content

Commit

Permalink
Improves user experience inside Stateful Cloud Playgrounds (#1786)
Browse files Browse the repository at this point in the history
* Add trusted domains

* Auto Open New terminal

* Removes TrustedDomains Dialog

* Auto open new terminal once

* Consolidate UX features into HostedPlayground

Merged AutoOpenTerminal and AddTrustedDomains into a single feature flag: HostedPlayground, per code review feedback.

* Not a user-setting, make sure it's always default false

* Check feature status top and inside feature for clarity

---------

Co-authored-by: Sebastian Tiedtke <[email protected]>
  • Loading branch information
pastuxso and sourishkrout authored Nov 13, 2024
1 parent aae987a commit 61de6c2
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 7 deletions.
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@
"main": "./out/extension.js",
"runme": {
"features": {
"HostedPlayground": {
"enabled": false,
"conditions": {
"enabledForExtensions": {
"stateful.platform": false,
"stateful.runme": true
}
}
},
"NewTreeProvider": {
"enabled": false,
"conditions": {
Expand Down
7 changes: 7 additions & 0 deletions src/extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import getLogger from './logger'
import { EnvironmentManager } from './environment/manager'
import ContextState from './contextState'
import { RunmeIdentity } from './grpc/serializerTypes'
import * as features from './features'

export class RunmeExtension {
protected serializer?: SerializerBase
Expand Down Expand Up @@ -532,6 +533,12 @@ export class RunmeExtension {
})
}
})

// only ever enabled in hosted playground
if (features.isOnInContextState(FeatureName.HostedPlayground)) {
await features.addTrustedDomains()
await features.autoOpenTerminal()
}
}

protected handleMasking(kernel: Kernel, maskingIsOn: boolean): (e: NotebookUiEvent) => void {
Expand Down
37 changes: 37 additions & 0 deletions src/extension/features/addTrustedDomains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Uri, workspace } from 'vscode'
import { parse as jsoncParse } from 'jsonc-parser'

import { FeatureName } from '../../types'
import getLogger from '../logger'

import { isOnInContextState } from '.'

const logger = getLogger('AddTrustedDomains')
const trustedDomain = 'https://*.stateful.com'

export async function addTrustedDomains() {
if (!isOnInContextState(FeatureName.HostedPlayground)) {
return
}

try {
const uri = Uri.parse('trustedDomains:/Trusted Domains')
const bytes = await workspace.fs.readFile(uri)
const json = jsoncParse(Buffer.from(bytes).toString('utf8')) as string[]
const isTrusted = json.some((entry) => entry === trustedDomain)

if (!isTrusted) {
json.push(trustedDomain)
await workspace.fs.writeFile(uri, Buffer.from(JSON.stringify(json)))
}
} catch (error) {
let message
if (error instanceof Error) {
message = error.message
} else {
message = JSON.stringify(error)
}

logger.error(message)
}
}
17 changes: 17 additions & 0 deletions src/extension/features/autoOpenTerminal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { commands } from 'vscode'

import { FeatureName } from '../../types'
import ContextState from '../contextState'

import { isOnInContextState } from '.'

export async function autoOpenTerminal() {
if (!isOnInContextState(FeatureName.HostedPlayground)) {
return
}

if (!ContextState.getKey<boolean>(`${FeatureName.HostedPlayground}.autoOpenTerminal`)) {
await commands.executeCommand('workbench.action.terminal.new')
await ContextState.addKey(`${FeatureName.HostedPlayground}.autoOpenTerminal`, true)
}
}
16 changes: 9 additions & 7 deletions src/extension/features.ts → src/extension/features/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import features, { FEATURES_CONTEXT_STATE_KEY } from '../features'
import { FeatureName } from '../types'
export * from './addTrustedDomains'
export * from './autoOpenTerminal'

import ContextState from './contextState'
import features, { FEATURES_CONTEXT_STATE_KEY } from '../../features'
import { FeatureName } from '../../types'
import ContextState from '../contextState'

export function isOnInContextState(featureName: FeatureName): boolean {
const snapshot = ContextState.getKey<string>(FEATURES_CONTEXT_STATE_KEY)
Expand All @@ -14,10 +16,6 @@ export function isOnInContextState(featureName: FeatureName): boolean {
return features.isOn(featureName, featureState$)
}

export default {
isOnInContextState,
}

export function getFeaturesContext() {
const snapshot = ContextState.getKey<string>(FEATURES_CONTEXT_STATE_KEY)
if (!snapshot) {
Expand All @@ -28,3 +26,7 @@ export function getFeaturesContext() {

return featureState$.getValue().context
}

export default {
isOnInContextState,
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,7 @@ export enum FeatureName {
RequireStatefulAuth = 'RequireStatefulAuth',
CopySelectionToClipboard = 'CopySelectionToClipboard',
NewTreeProvider = 'NewTreeProvider',
HostedPlayground = 'HostedPlayground',
}

export type Feature = {
Expand Down
30 changes: 30 additions & 0 deletions tests/extension/features.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,33 @@ describe('Feature Store', () => {
expect(features.isOn(FeatureName.Gist, featureState$)).toBe(true)
})
})

describe('Hosted Playground', () => {
let featureState$: FeatureObserver

beforeEach(() => {
featureState$ = features.loadState(packageJSON, {
os: 'linux',
})
})

it('should always be default disabled in Runme', () => {
const initialContext: FeatureContext = {
extensionId: ExtensionName.StatefulRunme,
}

features.updateState(featureState$, initialContext)

expect(features.isOn(FeatureName.HostedPlayground, featureState$)).toBe(false)
})

it('should always be default disabled in Stateful', () => {
const initialContext: FeatureContext = {
extensionId: ExtensionName.StatefulPlatform,
}

features.updateState(featureState$, initialContext)

expect(features.isOn(FeatureName.HostedPlayground, featureState$)).toBe(false)
})
})

0 comments on commit 61de6c2

Please sign in to comment.