Merge branch 'main' into pierremtb/issue2805
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.24.0",
|
"version": "0.24.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.17.0",
|
"@codemirror/autocomplete": "^6.17.0",
|
||||||
|
|||||||
@ -93,23 +93,10 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
private doSemanticTokens: boolean = false
|
private doSemanticTokens: boolean = false
|
||||||
private doFoldingRanges: boolean = false
|
private doFoldingRanges: boolean = false
|
||||||
|
|
||||||
private _defferer = deferExecution((code: string) => {
|
// When a doc update needs to be sent to the server, this holds the
|
||||||
try {
|
// timeout handle for it. When null, the server has the up-to-date
|
||||||
// Update the state (not the editor) with the new code.
|
// document.
|
||||||
this.client.textDocumentDidChange({
|
private sendScheduled: number | null = null
|
||||||
textDocument: {
|
|
||||||
uri: this.getDocUri(),
|
|
||||||
version: this.documentVersion++,
|
|
||||||
},
|
|
||||||
contentChanges: [{ text: code }],
|
|
||||||
})
|
|
||||||
|
|
||||||
this.requestSemanticTokens()
|
|
||||||
this.updateFoldingRanges()
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}, this.changesDelay)
|
|
||||||
|
|
||||||
constructor(options: LanguageServerOptions, private view: EditorView) {
|
constructor(options: LanguageServerOptions, private view: EditorView) {
|
||||||
this.client = options.client
|
this.client = options.client
|
||||||
@ -152,14 +139,9 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(viewUpdate: ViewUpdate) {
|
update(viewUpdate: ViewUpdate) {
|
||||||
// If the doc didn't change we can return early.
|
if (viewUpdate.docChanged) {
|
||||||
if (!viewUpdate.docChanged) {
|
this.scheduleSendDoc()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendChange({
|
|
||||||
documentText: viewUpdate.state.doc.toString(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -184,16 +166,6 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
this.updateFoldingRanges()
|
this.updateFoldingRanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendChange({ documentText }: { documentText: string }) {
|
|
||||||
if (!this.client.ready) return
|
|
||||||
|
|
||||||
this._defferer(documentText)
|
|
||||||
}
|
|
||||||
|
|
||||||
requestDiagnostics() {
|
|
||||||
this.sendChange({ documentText: this.getDocText() })
|
|
||||||
}
|
|
||||||
|
|
||||||
async requestHoverTooltip(
|
async requestHoverTooltip(
|
||||||
view: EditorView,
|
view: EditorView,
|
||||||
{ line, character }: { line: number; character: number }
|
{ line, character }: { line: number; character: number }
|
||||||
@ -204,7 +176,7 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
this.sendChange({ documentText: this.getDocText() })
|
this.ensureDocSent()
|
||||||
const result = await this.client.textDocumentHover({
|
const result = await this.client.textDocumentHover({
|
||||||
textDocument: { uri: this.getDocUri() },
|
textDocument: { uri: this.getDocUri() },
|
||||||
position: { line, character },
|
position: { line, character },
|
||||||
@ -227,6 +199,42 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
return { pos, end, create: (view) => ({ dom }), above: true }
|
return { pos, end, create: (view) => ({ dom }), above: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheduleSendDoc() {
|
||||||
|
if (this.sendScheduled != null) window.clearTimeout(this.sendScheduled)
|
||||||
|
this.sendScheduled = window.setTimeout(
|
||||||
|
() => this.sendDoc(),
|
||||||
|
this.changesDelay
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendDoc() {
|
||||||
|
if (this.sendScheduled != null) {
|
||||||
|
window.clearTimeout(this.sendScheduled)
|
||||||
|
this.sendScheduled = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.client.ready) return
|
||||||
|
try {
|
||||||
|
// Update the state (not the editor) with the new code.
|
||||||
|
this.client.textDocumentDidChange({
|
||||||
|
textDocument: {
|
||||||
|
uri: this.getDocUri(),
|
||||||
|
version: this.documentVersion++,
|
||||||
|
},
|
||||||
|
contentChanges: [{ text: this.view.state.doc.toString() }],
|
||||||
|
})
|
||||||
|
|
||||||
|
this.requestSemanticTokens()
|
||||||
|
this.updateFoldingRanges()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureDocSent() {
|
||||||
|
if (this.sendScheduled != null) this.sendDoc()
|
||||||
|
}
|
||||||
|
|
||||||
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
|
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
|
||||||
if (
|
if (
|
||||||
!this.doFoldingRanges ||
|
!this.doFoldingRanges ||
|
||||||
@ -284,13 +292,7 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
this.client.textDocumentDidChange({
|
this.ensureDocSent()
|
||||||
textDocument: {
|
|
||||||
uri: this.getDocUri(),
|
|
||||||
version: this.documentVersion++,
|
|
||||||
},
|
|
||||||
contentChanges: [{ text: this.getDocText() }],
|
|
||||||
})
|
|
||||||
|
|
||||||
const result = await this.client.textDocumentFormatting({
|
const result = await this.client.textDocumentFormatting({
|
||||||
textDocument: { uri: this.getDocUri() },
|
textDocument: { uri: this.getDocUri() },
|
||||||
@ -330,9 +332,7 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
this.sendChange({
|
this.ensureDocSent()
|
||||||
documentText: context.state.doc.toString(),
|
|
||||||
})
|
|
||||||
|
|
||||||
const result = await this.client.textDocumentCompletion({
|
const result = await this.client.textDocumentCompletion({
|
||||||
textDocument: { uri: this.getDocUri() },
|
textDocument: { uri: this.getDocUri() },
|
||||||
|
|||||||
15
src-tauri/Cargo.lock
generated
@ -3681,9 +3681,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num"
|
name = "num"
|
||||||
version = "0.4.3"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-complex",
|
"num-complex",
|
||||||
@ -3695,10 +3695,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.6"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
@ -3780,9 +3781,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"libm",
|
"libm",
|
||||||
@ -3834,7 +3835,7 @@ version = "0.7.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
|
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 3.1.0",
|
"proc-macro-crate 1.3.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.70",
|
||||||
|
|||||||
@ -80,5 +80,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"version": "0.24.0"
|
"version": "0.24.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,3 +39,32 @@ export const AppStateProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
</AppStateContext.Provider>
|
</AppStateContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AppStream {
|
||||||
|
mediaStream: MediaStream
|
||||||
|
setMediaStream: (mediaStream: MediaStream) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppStreamContext = createContext<AppStream>({
|
||||||
|
mediaStream: undefined as unknown as MediaStream,
|
||||||
|
setMediaStream: () => {},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const useAppStream = () => useContext(AppStreamContext)
|
||||||
|
|
||||||
|
export const AppStreamProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
const [mediaStream, setMediaStream] = useState<MediaStream>(
|
||||||
|
undefined as unknown as MediaStream
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppStreamContext.Provider
|
||||||
|
value={{
|
||||||
|
mediaStream,
|
||||||
|
setMediaStream,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AppStreamContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@ -114,7 +114,7 @@ export function Toolbar({
|
|||||||
() =>
|
() =>
|
||||||
commandBarSend({
|
commandBarSend({
|
||||||
type: 'Find and select command',
|
type: 'Find and select command',
|
||||||
data: { name: 'Extrude', ownerMachine: 'modeling' },
|
data: { name: 'Extrude', groupId: 'modeling' },
|
||||||
}),
|
}),
|
||||||
{ enabled: !disableAllButtons, scopes: ['modeling'] }
|
{ enabled: !disableAllButtons, scopes: ['modeling'] }
|
||||||
)
|
)
|
||||||
@ -378,7 +378,7 @@ export function Toolbar({
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
commandBarSend({
|
commandBarSend({
|
||||||
type: 'Find and select command',
|
type: 'Find and select command',
|
||||||
data: { name: 'Extrude', ownerMachine: 'modeling' },
|
data: { name: 'Extrude', groupId: 'modeling' },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
disabled={!state.can('Extrude') || disableAllButtons}
|
disabled={!state.can('Extrude') || disableAllButtons}
|
||||||
|
|||||||
@ -82,11 +82,11 @@ function ProjectMenuPopover({
|
|||||||
}) {
|
}) {
|
||||||
const { commandBarState, commandBarSend } = useCommandsContext()
|
const { commandBarState, commandBarSend } = useCommandsContext()
|
||||||
const { onProjectClose } = useLspContext()
|
const { onProjectClose } = useLspContext()
|
||||||
const exportCommandInfo = { name: 'Export', ownerMachine: 'modeling' }
|
const exportCommandInfo = { name: 'Export', groupId: 'modeling' }
|
||||||
const findCommand = (obj: { name: string; ownerMachine: string }) =>
|
const findCommand = (obj: { name: string; groupId: string }) =>
|
||||||
Boolean(
|
Boolean(
|
||||||
commandBarState.context.commands.find(
|
commandBarState.context.commands.find(
|
||||||
(c) => c.name === obj.name && c.ownerMachine === obj.ownerMachine
|
(c) => c.name === obj.name && c.groupId === obj.groupId
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
|||||||
import { btnName } from 'lib/cameraControls'
|
import { btnName } from 'lib/cameraControls'
|
||||||
import { sendSelectEventToEngine } from 'lib/selections'
|
import { sendSelectEventToEngine } from 'lib/selections'
|
||||||
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
||||||
|
import { useAppStream } from 'AppState'
|
||||||
|
|
||||||
export const Stream = () => {
|
export const Stream = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
@ -17,6 +18,7 @@ export const Stream = () => {
|
|||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
const videoRef = useRef<HTMLVideoElement>(null)
|
||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const { state, send, context } = useModelingContext()
|
const { state, send, context } = useModelingContext()
|
||||||
|
const { mediaStream } = useAppStream()
|
||||||
const { overallState } = useNetworkContext()
|
const { overallState } = useNetworkContext()
|
||||||
const [isFreezeFrame, setIsFreezeFrame] = useState(false)
|
const [isFreezeFrame, setIsFreezeFrame] = useState(false)
|
||||||
|
|
||||||
@ -124,10 +126,10 @@ export const Stream = () => {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return
|
||||||
if (!context.store?.mediaStream) return
|
if (!mediaStream) return
|
||||||
|
|
||||||
// Do not immediately play the stream!
|
// Do not immediately play the stream!
|
||||||
videoRef.current.srcObject = context.store.mediaStream
|
videoRef.current.srcObject = mediaStream
|
||||||
videoRef.current.pause()
|
videoRef.current.pause()
|
||||||
|
|
||||||
send({
|
send({
|
||||||
@ -136,7 +138,7 @@ export const Stream = () => {
|
|||||||
videoElement: videoRef.current,
|
videoElement: videoRef.current,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}, [context.store?.mediaStream])
|
}, [mediaStream])
|
||||||
|
|
||||||
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
if (!isNetworkOkay) return
|
if (!isNetworkOkay) return
|
||||||
|
|||||||
@ -195,14 +195,15 @@ export class CompletionRequester implements PluginValue {
|
|||||||
|
|
||||||
private queuedUids: string[] = []
|
private queuedUids: string[] = []
|
||||||
|
|
||||||
private _deffererCodeUpdate = deferExecution(() => {
|
|
||||||
this.requestCompletions()
|
|
||||||
}, changesDelay)
|
|
||||||
|
|
||||||
private _deffererUserSelect = deferExecution(() => {
|
private _deffererUserSelect = deferExecution(() => {
|
||||||
this.rejectSuggestionCommand()
|
this.rejectSuggestionCommand()
|
||||||
}, changesDelay)
|
}, changesDelay)
|
||||||
|
|
||||||
|
// When a doc update needs to be sent to the server, this holds the
|
||||||
|
// timeout handle for it. When null, the server has the up-to-date
|
||||||
|
// document.
|
||||||
|
private sendScheduledInput: number | null = null
|
||||||
|
|
||||||
constructor(readonly view: EditorView, client: LanguageServerClient) {
|
constructor(readonly view: EditorView, client: LanguageServerClient) {
|
||||||
this.client = client
|
this.client = client
|
||||||
}
|
}
|
||||||
@ -245,7 +246,34 @@ export class CompletionRequester implements PluginValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.lastPos = this.view.state.selection.main.head
|
this.lastPos = this.view.state.selection.main.head
|
||||||
if (viewUpdate.docChanged) this._deffererCodeUpdate(true)
|
if (viewUpdate.docChanged) this.scheduleUpdateDoc()
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleUpdateDoc() {
|
||||||
|
if (this.sendScheduledInput != null)
|
||||||
|
window.clearTimeout(this.sendScheduledInput)
|
||||||
|
this.sendScheduledInput = window.setTimeout(
|
||||||
|
() => this.updateDoc(),
|
||||||
|
changesDelay
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDoc() {
|
||||||
|
if (this.sendScheduledInput != null) {
|
||||||
|
window.clearTimeout(this.sendScheduledInput)
|
||||||
|
this.sendScheduledInput = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.client.ready) return
|
||||||
|
try {
|
||||||
|
this.requestCompletions()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureDocUpdated() {
|
||||||
|
if (this.sendScheduledInput != null) this.updateDoc()
|
||||||
}
|
}
|
||||||
|
|
||||||
ghostText(): GhostText | null {
|
ghostText(): GhostText | null {
|
||||||
|
|||||||
@ -27,13 +27,10 @@ export class KclPlugin implements PluginValue {
|
|||||||
this.client = client
|
this.client = client
|
||||||
}
|
}
|
||||||
|
|
||||||
private _deffererCodeUpdate = deferExecution(() => {
|
// When a doc update needs to be sent to the server, this holds the
|
||||||
if (this.viewUpdate === null) {
|
// timeout handle for it. When null, the server has the up-to-date
|
||||||
return
|
// document.
|
||||||
}
|
private sendScheduledInput: number | null = null
|
||||||
|
|
||||||
kclManager.executeCode()
|
|
||||||
}, changesDelay)
|
|
||||||
|
|
||||||
private _deffererUserSelect = deferExecution(() => {
|
private _deffererUserSelect = deferExecution(() => {
|
||||||
if (this.viewUpdate === null) {
|
if (this.viewUpdate === null) {
|
||||||
@ -101,7 +98,34 @@ export class KclPlugin implements PluginValue {
|
|||||||
codeManager.code = newCode
|
codeManager.code = newCode
|
||||||
codeManager.writeToFile()
|
codeManager.writeToFile()
|
||||||
|
|
||||||
this._deffererCodeUpdate(true)
|
this.scheduleUpdateDoc()
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleUpdateDoc() {
|
||||||
|
if (this.sendScheduledInput != null)
|
||||||
|
window.clearTimeout(this.sendScheduledInput)
|
||||||
|
this.sendScheduledInput = window.setTimeout(
|
||||||
|
() => this.updateDoc(),
|
||||||
|
changesDelay
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDoc() {
|
||||||
|
if (this.sendScheduledInput != null) {
|
||||||
|
window.clearTimeout(this.sendScheduledInput)
|
||||||
|
this.sendScheduledInput = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.client.ready) return
|
||||||
|
try {
|
||||||
|
kclManager.executeCode()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureDocUpdated() {
|
||||||
|
if (this.sendScheduledInput != null) this.updateDoc()
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateUnits(
|
async updateUnits(
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { deferExecution } from 'lib/utils'
|
|||||||
import { Themes } from 'lib/theme'
|
import { Themes } from 'lib/theme'
|
||||||
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
|
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
|
||||||
import { useModelingContext } from './useModelingContext'
|
import { useModelingContext } from './useModelingContext'
|
||||||
import { useAppState } from 'AppState'
|
import { useAppState, useAppStream } from 'AppState'
|
||||||
|
|
||||||
export function useSetupEngineManager(
|
export function useSetupEngineManager(
|
||||||
streamRef: React.RefObject<HTMLDivElement>,
|
streamRef: React.RefObject<HTMLDivElement>,
|
||||||
@ -28,6 +28,7 @@ export function useSetupEngineManager(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const { setAppState } = useAppState()
|
const { setAppState } = useAppState()
|
||||||
|
const { setMediaStream } = useAppStream()
|
||||||
|
|
||||||
const streamWidth = streamRef?.current?.offsetWidth
|
const streamWidth = streamRef?.current?.offsetWidth
|
||||||
const streamHeight = streamRef?.current?.offsetHeight
|
const streamHeight = streamRef?.current?.offsetHeight
|
||||||
@ -54,11 +55,7 @@ export function useSetupEngineManager(
|
|||||||
settings.modelingSend
|
settings.modelingSend
|
||||||
) {
|
) {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
setMediaStream: (mediaStream) =>
|
setMediaStream: setMediaStream,
|
||||||
settings.modelingSend({
|
|
||||||
type: 'Set context',
|
|
||||||
data: { mediaStream },
|
|
||||||
}),
|
|
||||||
setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }),
|
setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }),
|
||||||
width: quadWidth,
|
width: quadWidth,
|
||||||
height: quadHeight,
|
height: quadHeight,
|
||||||
|
|||||||
@ -60,7 +60,8 @@ export default function useStateMachineCommands<
|
|||||||
.filter((e) => !['done.', 'error.'].some((n) => e.includes(n)))
|
.filter((e) => !['done.', 'error.'].some((n) => e.includes(n)))
|
||||||
.map((type) =>
|
.map((type) =>
|
||||||
createMachineCommand<T, S>({
|
createMachineCommand<T, S>({
|
||||||
ownerMachine: machineId,
|
// The group is the owner machine's ID.
|
||||||
|
groupId: machineId,
|
||||||
type,
|
type,
|
||||||
state,
|
state,
|
||||||
send,
|
send,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
UpdaterRestartModal,
|
UpdaterRestartModal,
|
||||||
createUpdaterRestartModal,
|
createUpdaterRestartModal,
|
||||||
} from 'components/UpdaterRestartModal'
|
} from 'components/UpdaterRestartModal'
|
||||||
|
import { AppStreamProvider } from 'AppState'
|
||||||
|
|
||||||
// uncomment for xstate inspector
|
// uncomment for xstate inspector
|
||||||
// import { DEV } from 'env'
|
// import { DEV } from 'env'
|
||||||
@ -26,28 +27,30 @@ const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
|
|||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<HotkeysProvider>
|
<HotkeysProvider>
|
||||||
<Router />
|
<AppStreamProvider>
|
||||||
<Toaster
|
<Router />
|
||||||
position="bottom-center"
|
<Toaster
|
||||||
toastOptions={{
|
position="bottom-center"
|
||||||
style: {
|
toastOptions={{
|
||||||
borderRadius: '3px',
|
style: {
|
||||||
},
|
borderRadius: '3px',
|
||||||
className:
|
|
||||||
'bg-chalkboard-10 dark:bg-chalkboard-90 text-chalkboard-110 dark:text-chalkboard-10 rounded-sm border-chalkboard-20/50 dark:border-chalkboard-80/50',
|
|
||||||
success: {
|
|
||||||
iconTheme: {
|
|
||||||
primary: 'oklch(89% 0.16 143.4deg)',
|
|
||||||
secondary: 'oklch(48.62% 0.1654 142.5deg)',
|
|
||||||
},
|
},
|
||||||
duration:
|
className:
|
||||||
window?.localStorage.getItem('playwright') === 'true'
|
'bg-chalkboard-10 dark:bg-chalkboard-90 text-chalkboard-110 dark:text-chalkboard-10 rounded-sm border-chalkboard-20/50 dark:border-chalkboard-80/50',
|
||||||
? 10 // speed up e2e tests
|
success: {
|
||||||
: 1500,
|
iconTheme: {
|
||||||
},
|
primary: 'oklch(89% 0.16 143.4deg)',
|
||||||
}}
|
secondary: 'oklch(48.62% 0.1654 142.5deg)',
|
||||||
/>
|
},
|
||||||
<ModalContainer />
|
duration:
|
||||||
|
window?.localStorage.getItem('playwright') === 'true'
|
||||||
|
? 10 // speed up e2e tests
|
||||||
|
: 1500,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ModalContainer />
|
||||||
|
</AppStreamProvider>
|
||||||
</HotkeysProvider>
|
</HotkeysProvider>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,7 @@ export function createSettingsCommand({
|
|||||||
displayName: `Settings · ${decamelize(type.replaceAll('.', ' · '), {
|
displayName: `Settings · ${decamelize(type.replaceAll('.', ' · '), {
|
||||||
separator: ' ',
|
separator: ' ',
|
||||||
})}`,
|
})}`,
|
||||||
ownerMachine: 'settings',
|
groupId: 'settings',
|
||||||
icon: 'settings',
|
icon: 'settings',
|
||||||
needsReview: false,
|
needsReview: false,
|
||||||
onSubmit: (data) => {
|
onSubmit: (data) => {
|
||||||
|
|||||||
@ -65,7 +65,7 @@ export type Command<
|
|||||||
CommandSchema extends CommandSetSchema<T>[CommandName] = CommandSetSchema<T>[CommandName]
|
CommandSchema extends CommandSetSchema<T>[CommandName] = CommandSetSchema<T>[CommandName]
|
||||||
> = {
|
> = {
|
||||||
name: CommandName
|
name: CommandName
|
||||||
ownerMachine: T['id']
|
groupId: T['id']
|
||||||
needsReview: boolean
|
needsReview: boolean
|
||||||
onSubmit: (data?: CommandSchema) => void
|
onSubmit: (data?: CommandSchema) => void
|
||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
@ -84,7 +84,7 @@ export type CommandConfig<
|
|||||||
CommandSchema extends CommandSetSchema<T>[CommandName] = CommandSetSchema<T>[CommandName]
|
CommandSchema extends CommandSetSchema<T>[CommandName] = CommandSetSchema<T>[CommandName]
|
||||||
> = Omit<
|
> = Omit<
|
||||||
Command<T, CommandName, CommandSchema>,
|
Command<T, CommandName, CommandSchema>,
|
||||||
'name' | 'ownerMachine' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview'
|
'name' | 'groupId' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview'
|
||||||
> & {
|
> & {
|
||||||
needsReview?: true
|
needsReview?: true
|
||||||
args?: {
|
args?: {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ interface CreateMachineCommandProps<
|
|||||||
S extends CommandSetSchema<T>
|
S extends CommandSetSchema<T>
|
||||||
> {
|
> {
|
||||||
type: EventFrom<T>['type']
|
type: EventFrom<T>['type']
|
||||||
ownerMachine: T['id']
|
groupId: T['id']
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
send: Function
|
send: Function
|
||||||
actor: InterpreterFrom<T>
|
actor: InterpreterFrom<T>
|
||||||
@ -34,7 +34,7 @@ export function createMachineCommand<
|
|||||||
T extends AnyStateMachine,
|
T extends AnyStateMachine,
|
||||||
S extends CommandSetSchema<T>
|
S extends CommandSetSchema<T>
|
||||||
>({
|
>({
|
||||||
ownerMachine,
|
groupId,
|
||||||
type,
|
type,
|
||||||
state,
|
state,
|
||||||
send,
|
send,
|
||||||
@ -62,7 +62,7 @@ export function createMachineCommand<
|
|||||||
|
|
||||||
const command: Command<T, typeof type, S[typeof type]> = {
|
const command: Command<T, typeof type, S[typeof type]> = {
|
||||||
name: type,
|
name: type,
|
||||||
ownerMachine: ownerMachine,
|
groupId,
|
||||||
icon,
|
icon,
|
||||||
needsReview: commandConfig.needsReview || false,
|
needsReview: commandConfig.needsReview || false,
|
||||||
onSubmit: (data?: S[typeof type]) => {
|
onSubmit: (data?: S[typeof type]) => {
|
||||||
|
|||||||
@ -57,7 +57,7 @@ export type CommandBarMachineEvent =
|
|||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'Find and select command'
|
type: 'Find and select command'
|
||||||
data: { name: string; ownerMachine: string }
|
data: { name: string; groupId: string }
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'Change current argument'
|
type: 'Change current argument'
|
||||||
@ -120,9 +120,7 @@ export const commandBarMachine = createMachine(
|
|||||||
context.commands.filter(
|
context.commands.filter(
|
||||||
(c) =>
|
(c) =>
|
||||||
!event.data.commands.some(
|
!event.data.commands.some(
|
||||||
(c2) =>
|
(c2) => c2.name === c.name && c2.groupId === c.groupId
|
||||||
c2.name === c.name &&
|
|
||||||
c2.ownerMachine === c.ownerMachine
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
@ -393,9 +391,7 @@ export const commandBarMachine = createMachine(
|
|||||||
selectedCommand: (c, e) => {
|
selectedCommand: (c, e) => {
|
||||||
if (e.type !== 'Find and select command') return c.selectedCommand
|
if (e.type !== 'Find and select command') return c.selectedCommand
|
||||||
const found = c.commands.find(
|
const found = c.commands.find(
|
||||||
(cmd) =>
|
(cmd) => cmd.name === e.data.name && cmd.groupId === e.data.groupId
|
||||||
cmd.name === e.data.name &&
|
|
||||||
cmd.ownerMachine === e.data.ownerMachine
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return !!found ? found : c.selectedCommand
|
return !!found ? found : c.selectedCommand
|
||||||
@ -514,7 +510,7 @@ export const commandBarMachine = createMachine(
|
|||||||
)
|
)
|
||||||
|
|
||||||
function sortCommands(a: Command, b: Command) {
|
function sortCommands(a: Command, b: Command) {
|
||||||
if (b.ownerMachine === 'auth') return -1
|
if (b.groupId === 'auth') return -1
|
||||||
if (a.ownerMachine === 'auth') return 1
|
if (a.groupId === 'auth') return 1
|
||||||
return a.name.localeCompare(b.name)
|
return a.name.localeCompare(b.name)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -138,7 +138,6 @@ export type SegmentOverlayPayload =
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Store {
|
interface Store {
|
||||||
mediaStream?: MediaStream
|
|
||||||
videoElement?: HTMLVideoElement
|
videoElement?: HTMLVideoElement
|
||||||
buttonDownInStream: number | undefined
|
buttonDownInStream: number | undefined
|
||||||
didDragInStream: boolean
|
didDragInStream: boolean
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |