services work in react

This commit is contained in:
Andrew Pareles 2024-11-10 19:39:22 -08:00
parent 289da6bd6d
commit 9fc3e413a9
8 changed files with 285 additions and 255 deletions

View file

@ -1,46 +1,18 @@
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import { mountFnGenerator } from '../util/mountFnGenerator'
import { VIEWPANE_FILTER_ACTION } from '../../../../../browser/parts/views/viewPane.js'
import { ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation'
import { SidebarSettings } from './SidebarSettings.js';
import { useServices } from '../util/contextForServices.js';
import { IVoidSidebarStateService, VoidSidebarState } from '../../registerSidebar.js';
// import { SidebarThreadSelector } from './SidebarThreadSelector.js';
// import { SidebarChat } from './SidebarChat.js';
// import { SidebarSettings } from './SidebarSettings.js';
console.log('!!filteraction', VIEWPANE_FILTER_ACTION)
const Sidebar = ({ accessor }: { accessor: ServicesAccessor }) => {
// const chatInputRef = useRef<HTMLTextAreaElement | null>(null)
const [tab, setTab] = useState<'threadSelector' | 'chat' | 'settings'>('chat')
// // if they pressed the + to add a new chat
// useOnVSCodeMessage('startNewThread', (m) => {
// setTab('chat');
// chatInputRef.current?.focus();
// })
// // ctrl+l should switch back to chat
// useOnVSCodeMessage('ctrl+l', (m) => {
// setTab('chat');
// chatInputRef.current?.focus();
// })
// // if they toggled thread selector
// useOnVSCodeMessage('toggleThreadSelector', (m) => {
// if (tab === 'threadSelector') {
// setTab('chat')
// chatInputRef.current?.blur();
// } else
// setTab('threadSelector')
// })
// // if they toggled settings
// useOnVSCodeMessage('toggleSettings', (m) => {
// if (tab === 'settings') {
// setTab('chat')
// chatInputRef.current?.blur();
// } else
// setTab('settings')
// })
const Sidebar = () => {
// state should come from sidebarStateService
const { sidebarStateService } = useServices()
const [sidebarState, setSideBarState] = useState<VoidSidebarState>(sidebarStateService.state)
const { isHistoryOpen, currentTab: tab } = sidebarState
useEffect(() => { sidebarStateService.onDidChangeState(() => setSideBarState(sidebarStateService.state)) }, [sidebarStateService])
return <>
<div className={`flex flex-col h-screen w-full`}>
@ -48,20 +20,19 @@ const Sidebar = ({ accessor }: { accessor: ServicesAccessor }) => {
<span onClick={() => {
const tabs = ['chat', 'settings', 'threadSelector']
const index = tabs.indexOf(tab)
setTab(tabs[(index + 1) % tabs.length] as any)
sidebarStateService.setState({ currentTab: tabs[(index + 1) % tabs.length] as any })
}}>clickme {tab}</span>
<div className={`mb-2 h-[30vh] ${tab !== 'threadSelector' ? 'hidden' : ''}`}>
hi
<div className={`mb-2 h-[30vh] ${isHistoryOpen ? '' : 'hidden'}`}>
{/* <SidebarThreadSelector onClose={() => setTab('chat')} /> */}
</div>
<div className={`${tab !== 'chat' && tab !== 'threadSelector' ? 'hidden' : ''}`}>
<div className={`${tab === 'chat' ? '' : 'hidden'}`}>
{/* <SidebarChat chatInputRef={chatInputRef} /> */}
</div>
<div className={`${tab !== 'settings' ? 'hidden' : ''}`}>
{/* <SidebarSettings /> */}
<div className={`${tab === 'settings' ? '' : 'hidden'}`}>
<SidebarSettings />
</div>
</div>

View file

@ -1,6 +1,11 @@
// import React, { FormEvent, useCallback, useRef, useState } from "react";
// sidebarStateService.onDidFocusChat(() => {})
// sidebarStateService.onDidBlurChat(() => {})
// import MarkdownRender from "../../sidebar/markdown/!MarkdownRender";
// import BlockCode from "../../sidebar/markdown/!BlockCode";
// import { ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation';

View file

@ -1,105 +1,119 @@
// import React, { useState } from "react";
// import { configFields, useVoidConfig, VoidConfigField } from "../util/contextForConfig";
import React, { useEffect, useState } from 'react';
import { useServices } from '../util/contextForServices.js';
import { IVoidConfigStateService, nonDefaultConfigFields, PartialVoidConfig, VoidConfig, VoidConfigField, VoidConfigInfo, SetFieldFnType, ConfigState } from '../../../browser/registerConfig.js';
// const SettingOfFieldAndParam = ({ field, param }: { field: VoidConfigField, param: string }) => {
// const { voidConfig, partialVoidConfig, voidConfigInfo, setConfigParam } = useVoidConfig()
// const { enumArr, defaultVal, description } = voidConfigInfo[field][param]
// const val = partialVoidConfig[field]?.[param] ?? defaultVal // current value of this item
const SettingOfFieldAndParam = ({ field, param, configState, configStateService }:
{ field: VoidConfigField; param: string; configState: NonNullable<ConfigState>; configStateService: IVoidConfigStateService }) => {
// const updateState = (newValue: string) => { setConfigParam(field, param, newValue) }
// const resetButton = <button
// disabled={val === defaultVal}
// title={val === defaultVal ? 'This is the default value.' : `Revert value to '${defaultVal}'?`}
// className='group btn btn-sm disabled:opacity-75 disabled:cursor-default'
// onClick={() => updateState(defaultVal)}
// >
// <svg
// className='size-5 group-disabled:stroke-current group-disabled:fill-current group-hover:stroke-red-600 group-hover:fill-red-600 duration-200'
// fill="currentColor" strokeWidth="0" viewBox="0 0 16 16" height="200px" width="200px" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M3.5 2v3.5L4 6h3.5V5H4.979l.941-.941a3.552 3.552 0 1 1 5.023 5.023L5.746 14.28l.72.72 5.198-5.198A4.57 4.57 0 0 0 5.2 3.339l-.7.7V2h-1z"></path>
// </svg>
// </button>
// const inputElement = enumArr === undefined ?
// // string
// (<input
// className='input p-1 w-full'
// type="text"
// value={val}
// onChange={(e) => updateState(e.target.value)}
// />)
// :
// // enum
// (<select
// className='dropdown p-1 w-full'
// value={val}
// onChange={(e) => updateState(e.target.value)}
// >
// {enumArr.map((option) => (
// <option key={option} value={option}>
// {option}
// </option>
// ))}
// </select>)
// return <div>
// <label className='hidden'>{param}</label>
// <span>{description}</span>
// <div className='flex items-center'>
// {inputElement}
// {resetButton}
// </div>
// </div>
// }
// export const SidebarSettings = () => {
// const { voidConfig, voidConfigInfo } = useVoidConfig()
// const current_field = voidConfig.default['whichApi'] as VoidConfigField
const { partialVoidConfig } = configState
// return (
// <div className='space-y-4 py-2 overflow-y-auto'>
const { enumArr, defaultVal, description } = configStateService.voidConfigInfo[field][param]
const val = partialVoidConfig[field]?.[param] ?? defaultVal // current value of this item
// {/* choose the field */}
// <div className='outline-vscode-input-bg'>
// <SettingOfFieldAndParam
// field='default'
// param='whichApi'
// />
// <SettingOfFieldAndParam
// field='default'
// param='maxTokens'
// />
// </div>
const updateState = (newValue: string) => { configStateService.setField(field, param, newValue) }
// <hr />
const resetButton = <button
disabled={val === defaultVal}
title={val === defaultVal ? 'This is the default value.' : `Revert value to '${defaultVal}'?`}
className='group btn btn-sm disabled:opacity-75 disabled:cursor-default'
onClick={() => updateState(defaultVal)}
>
<svg
className='size-5 group-disabled:stroke-current group-disabled:fill-current group-hover:stroke-red-600 group-hover:fill-red-600 duration-200'
fill='currentColor' strokeWidth='0' viewBox='0 0 16 16' height='200px' width='200px' xmlns='http://www.w3.org/2000/svg'><path fillRule='evenodd' clipRule='evenodd' d='M3.5 2v3.5L4 6h3.5V5H4.979l.941-.941a3.552 3.552 0 1 1 5.023 5.023L5.746 14.28l.72.72 5.198-5.198A4.57 4.57 0 0 0 5.2 3.339l-.7.7V2h-1z'></path>
</svg>
</button>
// {/* render all fields, but hide the ones not visible for fast tab switching */}
// {configFields.map(field => {
// return <div
// key={field}
// className={`flex flex-col gap-y-2 ${field !== current_field ? 'hidden' : ''}`}
// >
// {Object.keys(voidConfigInfo[field]).map((param) => (
// <SettingOfFieldAndParam
// key={param}
// field={field}
// param={param}
// />
// ))}
// </div>
// })}
const inputElement = enumArr === undefined ?
// string
(<input
className='input p-1 w-full'
type='text'
value={val}
onChange={(e) => updateState(e.target.value)}
/>)
:
// enum
(<select
className='dropdown p-1 w-full'
value={val}
onChange={(e) => updateState(e.target.value)}
>
{enumArr.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>)
// {/* Remove this after 10/21/24, this is just to give developers a heads up about the recent change */}
// <div className='pt-20'>
// {`We recently updated Settings. To copy your old Void settings over, press Ctrl+Shift+P, `}
// {`type 'Open User Settings (JSON)',`}
// {` and look for 'void.'. `}
// </div>
// </div>
// )
// }
return <div>
<label className='hidden'>{param}</label>
<span>{description}</span>
<div className='flex items-center'>
{inputElement}
{resetButton}
</div>
</div>
}
export const SidebarSettings = () => {
// track the config state using React state so visual updates happen
const { configStateService } = useServices()
const [configState, setConfigState] = useState<ConfigState>(configStateService.state)
const { voidConfig } = configState
useEffect(() => { configStateService.onDidChangeState(() => setConfigState(configStateService.state)) }, [configStateService])
const current_field = voidConfig.default['whichApi'] as VoidConfigField
return (
<div className='space-y-4 py-2 overflow-y-auto'>
{/* choose the field */}
<div className='outline-vscode-input-bg'>
<SettingOfFieldAndParam
configState={configState}
configStateService={configStateService}
field='default'
param='whichApi'
/>
<SettingOfFieldAndParam
configState={configState}
configStateService={configStateService}
field='default'
param='maxTokens'
/>
</div>
<hr />
{/* render all fields, but hide the ones not visible for fast tab switching */}
{nonDefaultConfigFields.map(field => {
return <div
key={field}
className={`flex flex-col gap-y-2 ${field !== current_field ? 'hidden' : ''}`}
>
{Object.keys(configStateService.voidConfigInfo[field]).map((param) => (
<SettingOfFieldAndParam
key={param}
configState={configState}
configStateService={configStateService}
field={field}
param={param}
/>
))}
</div>
})}
{/* Remove this after 10/21/24, this is just to give developers a heads up about the recent change */}
<div className='pt-20'>
{`We recently updated Settings. To copy your old Void settings over, press Ctrl+Shift+P, `}
{`type 'Open User Settings (JSON)',`}
{` and look for 'void.'. `}
</div>
</div>
)
}

View file

@ -0,0 +1,20 @@
import React, { createContext, useContext } from 'react'
import { ReactServicesType } from '../../registerSidebar.js';
const AccessorContext = createContext<ReactServicesType | undefined>(undefined)
export const AccessorProvider = ({ children, services }: { children: React.ReactNode; services: ReactServicesType }) => {
return <AccessorContext.Provider value={services}>
{children}
</AccessorContext.Provider>
}
export const useServices = (): ReactServicesType => {
const context = useContext(AccessorContext)
if (context === undefined) {
throw new Error('useAccessor must be used within an AccessorProvider')
}
return context;
}

View file

@ -1,43 +1,18 @@
import React from 'react';
import * as ReactDOM from 'react-dom/client'
import { ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation';
// import { initPosthog, identifyUser } from './posthog';
// const ListenersAndTracking = () => {
// // initialize posthog
// useEffect(() => {
// initPosthog()
// }, [])
// // // when we get the deviceid, identify the user
// // useEffect(() => {
// // getVSCodeAPI().postMessage({ type: 'getDeviceId' });
// // awaitVSCodeResponse('deviceId').then((m => {
// // identifyUser(m.deviceId)
// // }))
// // }, [])
// // // Receive messages from the VSCode extension
// // useEffect(() => {
// // const listener = (event: MessageEvent) => {
// // const m = event.data as MessageToSidebar;
// // onMessageFromVSCode(m)
// // }
// // window.addEventListener('message', listener);
// // return () => window.removeEventListener('message', listener)
// // }, [])
// return null
// }
import { AccessorProvider } from './contextForServices';
import { ReactServicesType } from '../../registerSidebar';
export const mountFnGenerator = (Component: React.FC<{ accessor: ServicesAccessor }>) => (rootElement: HTMLElement, accessor: ServicesAccessor) => {
export const mountFnGenerator = (Component: React.FC) => (rootElement: HTMLElement, services: ReactServicesType) => {
if (typeof document === 'undefined') {
console.error('index.tsx error: document was undefined')
return
}
const root = ReactDOM.createRoot(rootElement)
root.render(<Component accessor={accessor} />);
root.render(
<AccessorProvider services={services}>
<Component />
</AccessorProvider>
);
}

View file

@ -38,10 +38,10 @@ export const nonDefaultConfigFields = [
const voidConfigInfo: Record<
typeof nonDefaultConfigFields[number] | 'default', {
[prop: string]: {
description: string,
enumArr?: readonly string[] | undefined,
defaultVal: string,
},
description: string;
enumArr?: readonly string[] | undefined;
defaultVal: string;
};
}
> = {
default: {
@ -186,7 +186,7 @@ const voidConfigInfo: Record<
// this is the type that comes with metadata like desc, default val, etc
type VoidConfigInfo = typeof voidConfigInfo
export type VoidConfigInfo = typeof voidConfigInfo
export type VoidConfigField = keyof typeof voidConfigInfo // typeof configFields[number]
// this is the type that specifies the user's actual config
@ -203,27 +203,48 @@ export type VoidConfig = {
}
const VOID_CONFIG_KEY = 'void.partialVoidConfig'
type setFieldType = <K extends VoidConfigField>(field: K, param: keyof VoidConfigInfo[K], newVal: string) => Promise<void>;
export interface IVoidSettingsService {
readonly _serviceBrand: undefined;
onDidChange: Event<void>;
getPartialVoidConfig(): Promise<PartialVoidConfig>;
getVoidConfig(): Promise<VoidConfig>;
setField: setFieldType;
const getVoidConfig = (partialVoidConfig: PartialVoidConfig): VoidConfig => {
const config = {} as PartialVoidConfig
for (const field of [...nonDefaultConfigFields, 'default'] as const) {
config[field] = {}
for (const prop in voidConfigInfo[field]) {
config[field][prop] = partialVoidConfig[field]?.[prop]?.trim() || voidConfigInfo[field][prop].defaultVal
}
}
return config as VoidConfig
}
export const IVoidSettingsService = createDecorator<IVoidSettingsService>('voidSettingsService');
class VoidSettingsService extends Disposable implements IVoidSettingsService {
const VOID_CONFIG_KEY = 'void.partialVoidConfig'
export type SetFieldFnType = <K extends VoidConfigField>(field: K, param: keyof VoidConfigInfo[K], newVal: string) => Promise<void>;
export type ConfigState = {
partialVoidConfig: PartialVoidConfig;
voidConfig: VoidConfig;
}
export interface IVoidConfigStateService {
readonly _serviceBrand: undefined;
readonly state: ConfigState;
readonly voidConfigInfo: VoidConfigInfo;
onDidChangeState: Event<void>;
setField: SetFieldFnType;
}
export const IVoidConfigStateService = createDecorator<IVoidConfigStateService>('VoidConfigStateService');
class VoidConfigStateService extends Disposable implements IVoidConfigStateService {
_serviceBrand: undefined;
private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = this._onDidChange.event;
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
state: ConfigState;
voidConfigInfo: VoidConfigInfo = voidConfigInfo;
async getPartialVoidConfig(): Promise<PartialVoidConfig> {
private async _readPartialVoidConfig(): Promise<PartialVoidConfig> {
const encryptedPartialConfig = this._storageService.get(VOID_CONFIG_KEY, StorageScope.APPLICATION)
if (!encryptedPartialConfig)
@ -234,28 +255,15 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
}
async getVoidConfig(): Promise<VoidConfig> {
const partialVoidConfig = await this.getPartialVoidConfig()
const config = {} as PartialVoidConfig
for (let field of [...nonDefaultConfigFields, 'default'] as const) {
config[field] = {}
for (let prop in voidConfigInfo[field]) {
config[field][prop] = partialVoidConfig[field]?.[prop]?.trim() || voidConfigInfo[field][prop].defaultVal
}
}
return config as VoidConfig
}
private async storePartialVoidConfig(partialVoidConfig: PartialVoidConfig) {
private async _storePartialVoidConfig(partialVoidConfig: PartialVoidConfig) {
const encryptedPartialConfigStr = await this._encryptionService.encrypt(JSON.stringify(partialVoidConfig))
this._storageService.store(VOID_CONFIG_KEY, encryptedPartialConfigStr, StorageScope.APPLICATION, StorageTarget.USER)
}
// Set field on PartialVoidConfig
setField: setFieldType = async <K extends VoidConfigField>(field: K, param: keyof VoidConfigInfo[K], newVal: string) => {
const partialVoidConfig = await this.getPartialVoidConfig()
setField: SetFieldFnType = async <K extends VoidConfigField>(field: K, param: keyof VoidConfigInfo[K], newVal: string) => {
const partialVoidConfig = await this._readPartialVoidConfig()
const newPartialConfig: PartialVoidConfig = {
...partialVoidConfig,
@ -264,19 +272,41 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
[param]: newVal
}
}
await this.storePartialVoidConfig(newPartialConfig)
this._onDidChange.fire()
await this._storePartialVoidConfig(newPartialConfig)
this._setState(newPartialConfig)
}
// internal function to update state, should be called every time state changes
private async _setState(partialVoidConfig: PartialVoidConfig) {
this.state = {
partialVoidConfig: partialVoidConfig,
voidConfig: getVoidConfig(partialVoidConfig),
}
this._onDidChangeState.fire()
}
constructor(
@IStorageService private readonly _storageService: IStorageService,
@IEncryptionService private readonly _encryptionService: IEncryptionService,
// @ISecretStorageService private readonly _secretStorageService: ISecretStorageService, // could have used this, but it's clearer the way it is (+ slightly different eg StorageTarget.USER)
// could have used this, but it's clearer the way it is (+ slightly different eg StorageTarget.USER)
// @ISecretStorageService private readonly _secretStorageService: ISecretStorageService,
) {
super()
// at the start, we haven't read the partial config yet, but we need to set state to something, just treat partialVoidConfig like it's empty
this.state = {
partialVoidConfig: {},
voidConfig: getVoidConfig({}),
}
// read and update the actual state immediately
this._readPartialVoidConfig().then(partialVoidConfig => {
this._setState(partialVoidConfig)
})
}
}
registerSingleton(IVoidSettingsService, VoidSettingsService, InstantiationType.Eager);
registerSingleton(IVoidConfigStateService, VoidConfigStateService, InstantiationType.Eager);

View file

@ -36,9 +36,10 @@ import { IKeybindingService } from '../../../../platform/keybinding/common/keybi
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
// import { IVoidSettingsService } from './registerSettings.js';
// import { IVoidConfigService } from './registerSettings.js';
// import { IEditorService } from '../../../services/editor/common/editorService.js';
import mountFn from './react/out/Sidebar.js';
import { IVoidConfigStateService } from './registerConfig.js';
// import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
// const mountFn = (...params: any) => { }
@ -47,11 +48,16 @@ import mountFn from './react/out/Sidebar.js';
// compare against search.contribution.ts and https://app.greptile.com/chat/w1nsmt3lauwzculipycpn?repo=github%3Amain%3Amicrosoft%2Fvscode
// and debug.contribution.ts, scm.contribution.ts (source control)
type VoidSidebarState = {
export type VoidSidebarState = {
isHistoryOpen: boolean;
currentTab: 'chat' | 'settings';
}
export type ReactServicesType = {
sidebarStateService: IVoidSidebarStateService;
configStateService: IVoidConfigStateService;
threadHistoryService: IThreadHistoryService;
}
// ---------- Define viewpane ----------
@ -89,10 +95,13 @@ class VoidSidebarViewPane extends ViewPane {
dom.append(parent, root);
// gets set immediately
let accessor_: ServicesAccessor = null as unknown as ServicesAccessor
this.instantiationService.invokeFunction(accessor => { accessor_ = accessor });
mountFn(root, accessor_);
this.instantiationService.invokeFunction(accessor => {
mountFn(root, {
configStateService: accessor.get(IVoidConfigStateService),
sidebarStateService: accessor.get(IVoidSidebarStateService),
threadHistoryService: accessor.get(IThreadHistoryService),
});
});
}
@ -184,37 +193,53 @@ viewsRegistry.registerViews([{
// ---------- Register service that manages sidebar's state ----------
interface IVoidSidebarStateService {
export interface IVoidSidebarStateService {
readonly _serviceBrand: undefined;
setState(newState: Partial<VoidSidebarState>): void;
state: VoidSidebarState;
focusChat(): void;
blurChat(): void;
onDidChange: Event<void>;
onFocusChat: Event<void>;
onBlurChat: Event<void>;
state: VoidSidebarState;
setState(newState: Partial<VoidSidebarState>): void;
onDidChangeState: Event<void>;
onDidFocusChat: Event<void>;
onDidBlurChat: Event<void>;
fireFocusChat(): void;
fireBlurChat(): void;
}
const IVoidSidebarStateService = createDecorator<IVoidSidebarStateService>('voidSidebarStateService');
export const IVoidSidebarStateService = createDecorator<IVoidSidebarStateService>('voidSidebarStateService');
class VoidSidebarStateService extends Disposable implements IVoidSidebarStateService {
_serviceBrand: undefined;
private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = this._onDidChange.event;
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
private readonly _onFocusChat = new Emitter<void>();
readonly onFocusChat: Event<void> = this._onFocusChat.event;
readonly onDidFocusChat: Event<void> = this._onFocusChat.event;
private readonly _onBlurChat = new Emitter<void>();
readonly onBlurChat: Event<void> = this._onBlurChat.event;
readonly onDidBlurChat: Event<void> = this._onBlurChat.event;
// state
state: VoidSidebarState = {
isHistoryOpen: false,
currentTab: 'chat',
state: VoidSidebarState
setState(newState: Partial<VoidSidebarState>) {
// make sure view is open if the tab changes
if ('currentTab' in newState)
this._viewsService.openView(SIDEBAR_VIEW_ID);
this.state = { ...this.state, ...newState }
this._onDidChangeState.fire()
}
fireFocusChat() {
this._onFocusChat.fire()
}
fireBlurChat() {
this._onBlurChat.fire()
}
constructor(
@ -223,23 +248,13 @@ class VoidSidebarStateService extends Disposable implements IVoidSidebarStateSer
super()
// auto open the view on mount (if it bothers you this is here, this is technically just initializing the state of the view)
this._viewsService.openView(SIDEBAR_VIEW_ID);
}
setState(newState: Partial<VoidSidebarState>) {
// make sure view is open if the tab changes
if ('currentTab' in newState)
this._viewsService.openView(SIDEBAR_VIEW_ID);
// initial state
this.state = {
isHistoryOpen: false,
currentTab: 'chat',
}
this.state = { ...this.state, ...newState }
this._onDidChange.fire()
}
focusChat() {
this._onFocusChat.fire()
}
blurChat() {
this._onBlurChat.fire()
}
}
@ -258,7 +273,7 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const stateService = accessor.get(IVoidSidebarStateService)
stateService.setState({ isHistoryOpen: false, currentTab: 'chat' })
stateService.focusChat()
stateService.fireFocusChat()
// const selection = accessor.get(IEditorService).activeTextEditorControl?.getSelection()
@ -292,7 +307,7 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const stateService = accessor.get(IVoidSidebarStateService)
stateService.setState({ isHistoryOpen: false, currentTab: 'chat' })
stateService.focusChat()
stateService.fireFocusChat()
const historyService = accessor.get(IThreadHistoryService)
historyService.startNewThread()
@ -312,7 +327,7 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const stateService = accessor.get(IVoidSidebarStateService)
stateService.setState({ isHistoryOpen: !stateService.state.isHistoryOpen })
stateService.blurChat()
stateService.fireBlurChat()
}
})
@ -329,6 +344,6 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const stateService = accessor.get(IVoidSidebarStateService)
stateService.setState({ isHistoryOpen: false, currentTab: 'settings' })
stateService.blurChat()
stateService.fireBlurChat()
}
})

View file

@ -1,5 +1,5 @@
// register Settings
import './registerSettings.js'
import './registerConfig.js'
// register Sidebar chat
import './registerSidebar.js'