In the middle of replacing fs and project functions

This commit is contained in:
49lf
2024-07-23 17:16:26 -04:00
parent a1aadd3fb8
commit 15698c6d42
40 changed files with 281 additions and 148 deletions

View File

@ -16,7 +16,7 @@ import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubsc
import { engineCommandManager } from 'lib/singletons' import { engineCommandManager } from 'lib/singletons'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath' import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useLspContext } from 'components/LspProvider' import { useLspContext } from 'components/LspProvider'
import { useRefreshSettings } from 'hooks/useRefreshSettings' import { useRefreshSettings } from 'hooks/useRefreshSettings'
import { ModelingSidebar } from 'components/ModelingSidebar/ModelingSidebar' import { ModelingSidebar } from 'components/ModelingSidebar/ModelingSidebar'
@ -62,7 +62,7 @@ export function App() {
e.preventDefault() e.preventDefault()
}) })
useHotkeyWrapper( useHotkeyWrapper(
[isTauri() ? 'mod + ,' : 'shift + mod + ,'], [isDesktop() ? 'mod + ,' : 'shift + mod + ,'],
() => navigate(filePath + paths.SETTINGS), () => navigate(filePath + paths.SETTINGS),
{ {
splitKey: '|', splitKey: '|',

View File

@ -10,7 +10,7 @@ import { Settings } from './routes/Settings'
import Onboarding, { onboardingRoutes } from './routes/Onboarding' import Onboarding, { onboardingRoutes } from './routes/Onboarding'
import SignIn from './routes/SignIn' import SignIn from './routes/SignIn'
import { Auth } from './Auth' import { Auth } from './Auth'
import { isTauri } from './lib/isTauri' import { isDesktop } from './lib/isDesktop'
import Home from './routes/Home' import Home from './routes/Home'
import { NetworkContext } from './hooks/useNetworkContext' import { NetworkContext } from './hooks/useNetworkContext'
import { useNetworkStatus } from './hooks/useNetworkStatus' import { useNetworkStatus } from './hooks/useNetworkStatus'
@ -32,7 +32,7 @@ import SettingsAuthProvider from 'components/SettingsAuthProvider'
import LspProvider from 'components/LspProvider' import LspProvider from 'components/LspProvider'
import { KclContextProvider } from 'lang/KclProvider' import { KclContextProvider } from 'lang/KclProvider'
import { BROWSER_PROJECT_NAME } from 'lib/constants' import { BROWSER_PROJECT_NAME } from 'lib/constants'
import { getState, setState } from 'lib/tauri' import { getState, setState } from 'lib/desktop'
import { CoreDumpManager } from 'lib/coredump' import { CoreDumpManager } from 'lib/coredump'
import { engineCommandManager } from 'lib/singletons' import { engineCommandManager } from 'lib/singletons'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
@ -66,8 +66,8 @@ const router = createBrowserRouter([
{ {
path: paths.INDEX, path: paths.INDEX,
loader: async () => { loader: async () => {
const inTauri = isTauri() const onDesktop = isDesktop()
if (inTauri) { if (onDesktop) {
const appState = await getState() const appState = await getState()
if (appState) { if (appState) {
@ -84,7 +84,7 @@ const router = createBrowserRouter([
} }
} }
return inTauri return onDesktop
? redirect(paths.HOME) ? redirect(paths.HOME)
: redirect(paths.FILE + '/%2F' + BROWSER_PROJECT_NAME) : redirect(paths.FILE + '/%2F' + BROWSER_PROJECT_NAME)
}, },
@ -101,7 +101,7 @@ const router = createBrowserRouter([
<Outlet /> <Outlet />
<App /> <App />
<CommandBar /> <CommandBar />
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />} {!isDesktop() && import.meta.env.PROD && <DownloadAppBanner />}
</ModelingMachineProvider> </ModelingMachineProvider>
<WasmErrBanner /> <WasmErrBanner />
</FileMachineProvider> </FileMachineProvider>

View File

@ -1,4 +1,4 @@
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useRouteError, isRouteErrorResponse } from 'react-router-dom' import { useRouteError, isRouteErrorResponse } from 'react-router-dom'
import { ActionButton } from './ActionButton' import { ActionButton } from './ActionButton'
import { import {
@ -25,7 +25,7 @@ export const ErrorPage = () => {
</p> </p>
)} )}
<div className="flex justify-between gap-2 mt-6"> <div className="flex justify-between gap-2 mt-6">
{isTauri() && ( {isDesktop() && (
<ActionButton <ActionButton
Element="link" Element="link"
to={'/'} to={'/'}

View File

@ -16,7 +16,7 @@ import {
import { useCommandsContext } from 'hooks/useCommandsContext' import { useCommandsContext } from 'hooks/useCommandsContext'
import { fileMachine } from 'machines/fileMachine' import { fileMachine } from 'machines/fileMachine'
import { mkdir, remove, rename, create } from '@tauri-apps/plugin-fs' import { mkdir, remove, rename, create } from '@tauri-apps/plugin-fs'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { join, sep } from '@tauri-apps/api/path' import { join, sep } from '@tauri-apps/api/path'
import { DEFAULT_FILE_NAME, FILE_EXT } from 'lib/constants' import { DEFAULT_FILE_NAME, FILE_EXT } from 'lib/constants'
import { getProjectInfo } from 'lib/tauri' import { getProjectInfo } from 'lib/tauri'
@ -86,7 +86,7 @@ export const FileMachineProvider = ({
}, },
services: { services: {
readFiles: async (context: ContextFrom<typeof fileMachine>) => { readFiles: async (context: ContextFrom<typeof fileMachine>) => {
const newFiles = isTauri() const newFiles = isDesktop()
? (await getProjectInfo(context.project.path)).children ? (await getProjectInfo(context.project.path)).children
: [] : []
return { return {

View File

@ -25,7 +25,7 @@ import {
import { wasmUrl } from 'lang/wasm' import { wasmUrl } from 'lang/wasm'
import { PROJECT_ENTRYPOINT } from 'lib/constants' import { PROJECT_ENTRYPOINT } from 'lib/constants'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { codeManager } from 'lib/singletons' import { codeManager } from 'lib/singletons'
function getWorkspaceFolders(): LSP.WorkspaceFolder[] { function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
@ -125,7 +125,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
]) ])
useMemo(() => { useMemo(() => {
if (!isTauri() && isKclLspReady && kclLspClient && codeManager.code) { if (!isDesktop() && isKclLspReady && kclLspClient && codeManager.code) {
kclLspClient.textDocumentDidOpen({ kclLspClient.textDocumentDidOpen({
textDocument: { textDocument: {
uri: `file:///${PROJECT_ENTRYPOINT}`, uri: `file:///${PROJECT_ENTRYPOINT}`,

View File

@ -7,7 +7,7 @@ import Tooltip from 'components/Tooltip'
import { ActionIcon } from 'components/ActionIcon' import { ActionIcon } from 'components/ActionIcon'
import styles from './ModelingSidebar.module.css' import styles from './ModelingSidebar.module.css'
import { ModelingPane } from './ModelingPane' import { ModelingPane } from './ModelingPane'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { CustomIconName } from 'components/CustomIcon' import { CustomIconName } from 'components/CustomIcon'
import { useCommandsContext } from 'hooks/useCommandsContext' import { useCommandsContext } from 'hooks/useCommandsContext'
@ -142,7 +142,110 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
}} }}
> >
<div id="app-sidebar" className={styles.grid + ' flex-1'}> <div id="app-sidebar" className={styles.grid + ' flex-1'}>
<ul <ModelingSidebarSection id="sidebar-top" panes={topPanes} />
<ModelingSidebarSection
id="sidebar-bottom"
panes={bottomPanes}
alignButtons="end"
/>
</div>
</Resizable>
)
}
interface ModelingSidebarSectionProps extends HTMLAttributes<HTMLDivElement> {
panes: SidebarPane[]
alignButtons?: 'start' | 'end'
}
function ModelingSidebarSection({
panes,
alignButtons = 'start',
className,
...props
}: ModelingSidebarSectionProps) {
const { settings } = useSettingsAuthContext()
const showDebugPanel = settings.context.modeling.showDebugPanel
const paneIds = panes.map((pane) => pane.id)
const { send, context } = useModelingContext()
const foundOpenPane = context.store?.openPanes.find((pane) =>
paneIds.includes(pane)
)
const [currentPane, setCurrentPane] = useState(
foundOpenPane || ('none' as SidebarType | 'none')
)
const togglePane = useCallback(
(newPane: SidebarType | 'none') => {
if (newPane === 'none') {
send({
type: 'Set context',
data: {
openPanes: context.store?.openPanes.filter(
(p) => p !== currentPane
),
},
})
setCurrentPane('none')
} else if (newPane === currentPane) {
setCurrentPane('none')
send({
type: 'Set context',
data: {
openPanes: context.store?.openPanes.filter((p) => p !== newPane),
},
})
} else {
send({
type: 'Set context',
data: {
openPanes: [
...context.store?.openPanes.filter((p) => p !== currentPane),
newPane,
],
},
})
setCurrentPane(newPane)
}
},
[context.store?.openPanes, send, currentPane, setCurrentPane]
)
// Filter out the debug panel if it's not supposed to be shown
// TODO: abstract out for allowing user to configure which panes to show
const filteredPanes = (
showDebugPanel.current ? panes : panes.filter((pane) => pane.id !== 'debug')
).filter(
(pane) =>
!pane.hideOnPlatform ||
(isDesktop()
? pane.hideOnPlatform === 'web'
: pane.hideOnPlatform === 'desktop')
)
useEffect(() => {
if (
!showDebugPanel.current &&
currentPane === 'debug' &&
context.store?.openPanes.includes('debug')
) {
togglePane('debug')
}
}, [showDebugPanel.current, togglePane, context.store?.openPanes])
return (
<div className={'group contents ' + className} {...props}>
<Tab.Group
vertical
selectedIndex={
currentPane === 'none' ? 0 : paneIds.indexOf(currentPane) + 1
}
onChange={(index) => {
const newPane = index === 0 ? 'none' : paneIds[index - 1]
togglePane(newPane)
}}
>
<Tab.List
id={`${props.id}-ribbon`}
className={ className={
(context.store?.openPanes.length === 0 ? 'rounded-r ' : '') + (context.store?.openPanes.length === 0 ? 'rounded-r ' : '') +
'relative z-[2] pointer-events-auto p-0 col-start-1 col-span-1 h-fit w-fit flex flex-col ' + 'relative z-[2] pointer-events-auto p-0 col-start-1 col-span-1 h-fit w-fit flex flex-col ' +

View File

@ -2,7 +2,7 @@ import { Popover, Transition } from '@headlessui/react'
import { ActionButton, ActionButtonProps } from './ActionButton' import { ActionButton, ActionButtonProps } from './ActionButton'
import { type IndexLoaderData } from 'lib/types' import { type IndexLoaderData } from 'lib/types'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { isTauri } from '../lib/isTauri' import { isDesktop } from '../lib/isDesktop'
import { Link, useLocation, useNavigate } from 'react-router-dom' import { Link, useLocation, useNavigate } from 'react-router-dom'
import { Fragment, useMemo } from 'react' import { Fragment, useMemo } from 'react'
import { sep } from '@tauri-apps/api/path' import { sep } from '@tauri-apps/api/path'
@ -55,7 +55,7 @@ function AppLogoLink({
"relative h-full grid place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-2.5 before:z-[-1] before:bg-primary before:rounded-b-sm" "relative h-full grid place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-2.5 before:z-[-1] before:bg-primary before:rounded-b-sm"
const logoClassName = 'w-auto h-4 text-chalkboard-10' const logoClassName = 'w-auto h-4 text-chalkboard-10'
return isTauri() ? ( return isDesktop() ? (
<Link <Link
data-testid="app-logo" data-testid="app-logo"
onClick={() => { onClick={() => {
@ -111,7 +111,7 @@ function ProjectMenuPopover({
<> <>
<span className="flex-1">Project settings</span> <span className="flex-1">Project settings</span>
<kbd className="hotkey">{`${platform === 'macos' ? '⌘' : 'Ctrl'}${ <kbd className="hotkey">{`${platform === 'macos' ? '⌘' : 'Ctrl'}${
isTauri() ? '' : '⬆' isDesktop() ? '' : '⬆'
},`}</kbd> },`}</kbd>
</> </>
), ),
@ -177,7 +177,7 @@ function ProjectMenuPopover({
id: 'go-home', id: 'go-home',
Element: 'button', Element: 'button',
children: 'Go to Home', children: 'Go to Home',
className: !isTauri() ? 'hidden' : '', className: !isDesktop() ? 'hidden' : '',
onClick: () => { onClick: () => {
onProjectClose(file || null, project?.path || null, true) onProjectClose(file || null, project?.path || null, true)
// Clear the scene and end the session. // Clear the scene and end the session.
@ -195,7 +195,7 @@ function ProjectMenuPopover({
commandBarSend, commandBarSend,
engineCommandManager, engineCommandManager,
onProjectClose, onProjectClose,
isTauri, isDesktop,
] ]
) )
@ -207,11 +207,11 @@ function ProjectMenuPopover({
> >
<div className="flex flex-col items-start py-0.5"> <div className="flex flex-col items-start py-0.5">
<span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"> <span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block">
{isTauri() && file?.name {isDesktop() && file?.name
? file.name.slice(file.name.lastIndexOf(sep()) + 1) ? file.name.slice(file.name.lastIndexOf(sep()) + 1)
: APP_NAME} : APP_NAME}
</span> </span>
{isTauri() && project?.name && ( {isDesktop() && project?.name && (
<span className="hidden text-xs text-chalkboard-70 dark:text-chalkboard-40 whitespace-nowrap lg:block"> <span className="hidden text-xs text-chalkboard-70 dark:text-chalkboard-40 whitespace-nowrap lg:block">
{project.name} {project.name}
</span> </span>

View File

@ -9,7 +9,7 @@ import {
import { Fragment } from 'react/jsx-runtime' import { Fragment } from 'react/jsx-runtime'
import { SettingsSection } from './SettingsSection' import { SettingsSection } from './SettingsSection'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { ActionButton } from 'components/ActionButton' import { ActionButton } from 'components/ActionButton'
import { SettingsFieldInput } from './SettingsFieldInput' import { SettingsFieldInput } from './SettingsFieldInput'
import { getInitialDefaultDir, showInFolder } from 'lib/tauri' import { getInitialDefaultDir, showInFolder } from 'lib/tauri'
@ -41,7 +41,7 @@ export const AllSettingsFields = forwardRef(
} = useSettingsAuthContext() } = useSettingsAuthContext()
const projectPath = const projectPath =
isFileSettings && isTauri() isFileSettings && isDesktop()
? decodeURI( ? decodeURI(
location.pathname location.pathname
.replace(paths.FILE + '/', '') .replace(paths.FILE + '/', '')
@ -176,14 +176,14 @@ export const AllSettingsFields = forwardRef(
title="Reset settings" title="Reset settings"
description={`Restore settings to their default values. Your settings are saved in description={`Restore settings to their default values. Your settings are saved in
${ ${
isTauri() isDesktop()
? ' a file in the app data folder for your OS.' ? ' a file in the app data folder for your OS.'
: " your browser's local storage." : " your browser's local storage."
} }
`} `}
> >
<div className="flex flex-col items-start gap-4"> <div className="flex flex-col items-start gap-4">
{isTauri() && ( {isDesktop() && (
<ActionButton <ActionButton
Element="button" Element="button"
onClick={async () => { onClick={async () => {

View File

@ -21,7 +21,7 @@ import {
Prop, Prop,
StateFrom, StateFrom,
} from 'xstate' } from 'xstate'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig' import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig'
import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons' import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
@ -341,7 +341,7 @@ export default SettingsAuthProvider
export function logout() { export function logout() {
localStorage.removeItem(TOKEN_PERSIST_KEY) localStorage.removeItem(TOKEN_PERSIST_KEY)
return ( return (
!isTauri() && !isDesktop() &&
fetch(withBaseUrl('/logout'), { fetch(withBaseUrl('/logout'), {
method: 'POST', method: 'POST',
credentials: 'include', credentials: 'include',

View File

@ -8,7 +8,7 @@ import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath' import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
import Tooltip from './Tooltip' import Tooltip from './Tooltip'
import usePlatform from 'hooks/usePlatform' import usePlatform from 'hooks/usePlatform'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { CustomIcon } from './CustomIcon' import { CustomIcon } from './CustomIcon'
type User = Models['User_type'] type User = Models['User_type']
@ -33,7 +33,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
<> <>
<span className="flex-1">User settings</span> <span className="flex-1">User settings</span>
<kbd className="hotkey">{`${platform === 'macos' ? '⌘' : 'Ctrl'}${ <kbd className="hotkey">{`${platform === 'macos' ? '⌘' : 'Ctrl'}${
isTauri() ? '' : '⬆' isDesktop() ? '' : '⬆'
},`}</kbd> },`}</kbd>
</> </>
), ),

View File

@ -1,5 +1,5 @@
import { Platform, platform } from '@tauri-apps/plugin-os' import { Platform, platform } from '@tauri-apps/plugin-os'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
export default function usePlatform() { export default function usePlatform() {
@ -10,7 +10,7 @@ export default function usePlatform() {
setPlatformName(await platform()) setPlatformName(await platform())
} }
if (isTauri()) { if (isDesktop()) {
void getPlatform() void getPlatform()
} else { } else {
if (navigator.userAgent.indexOf('Mac') !== -1) { if (navigator.userAgent.indexOf('Mac') !== -1) {

View File

@ -6,7 +6,7 @@ import { Router } from './Router'
import { HotkeysProvider } from 'react-hotkeys-hook' import { HotkeysProvider } from 'react-hotkeys-hook'
import ModalContainer from 'react-modal-promise' import ModalContainer from 'react-modal-promise'
import { UpdaterModal, createUpdaterModal } from 'components/UpdaterModal' import { UpdaterModal, createUpdaterModal } from 'components/UpdaterModal'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { relaunch } from '@tauri-apps/plugin-process' import { relaunch } from '@tauri-apps/plugin-process'
import { check } from '@tauri-apps/plugin-updater' import { check } from '@tauri-apps/plugin-updater'
import { import {
@ -84,4 +84,4 @@ const runTauriUpdater = async () => {
} }
} }
isTauri() && runTauriUpdater() isDesktop() && runTauriUpdater()

View File

@ -2,7 +2,7 @@
// NOT updating the code state when we don't need to. // NOT updating the code state when we don't need to.
// This prevents re-renders of the codemirror editor, when typing. // This prevents re-renders of the codemirror editor, when typing.
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { writeTextFile } from '@tauri-apps/plugin-fs' import { writeTextFile } from '@tauri-apps/plugin-fs'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { editorManager } from 'lib/singletons' import { editorManager } from 'lib/singletons'
@ -21,7 +21,7 @@ export default class CodeManager {
private _hotkeys: { [key: string]: () => void } = {} private _hotkeys: { [key: string]: () => void } = {}
constructor() { constructor() {
if (isTauri()) { if (isDesktop()) {
this.code = '' this.code = ''
return return
} }
@ -115,7 +115,7 @@ export default class CodeManager {
} }
async writeToFile() { async writeToFile() {
if (isTauri()) { if (isDesktop()) {
setTimeout(() => { setTimeout(() => {
// Wait one event loop to give a chance for params to be set // Wait one event loop to give a chance for params to be set
// Save the file to disk // Save the file to disk

View File

@ -1,7 +1,4 @@
import { readFile, exists as tauriExists } from '@tauri-apps/plugin-fs' import { isDesktop } from 'lib/isDesktop'
import { isTauri } from 'lib/isTauri'
import { join } from '@tauri-apps/api/path'
import { readDirRecursive } from 'lib/tauri'
/// FileSystemManager is a class that provides a way to read files from the local file system. /// FileSystemManager is a class that provides a way to read files from the local file system.
/// It assumes that you are in a project since it is solely used by the std lib /// It assumes that you are in a project since it is solely used by the std lib
@ -17,54 +14,58 @@ class FileSystemManager {
this._dir = dir this._dir = dir
} }
async join(dir: string, path: string): Promise<string> {
return window.electron.ipcRenderer.invoke('join', [dir, path]);
}
async readFile(path: string): Promise<Uint8Array | void> { async readFile(path: string): Promise<Uint8Array | void> {
// Using local file system only works from Tauri. // Using local file system only works from desktop.
if (!isTauri()) { if (!isDesktop()) {
return Promise.reject( return Promise.reject(
new Error('This function can only be called from a Tauri application') new Error('This function can only be called from the desktop application')
) )
} }
return join(this.dir, path) return this.join(this.dir, path)
.catch((error) => { .catch((error) => {
return Promise.reject(new Error(`Error reading file: ${error}`)) return Promise.reject(new Error(`Error reading file: ${error}`))
}) })
.then((file) => { .then((file) => {
return readFile(file) return window.electron.ipcRenderer.invoke('readFile', [filepath])
}) })
} }
async exists(path: string): Promise<boolean | void> { async exists(path: string): Promise<boolean | void> {
// Using local file system only works from Tauri. // Using local file system only works from desktop.
if (!isTauri()) { if (!isDesktop()) {
return Promise.reject( return Promise.reject(
new Error('This function can only be called from a Tauri application') new Error('This function can only be called from the desktop application')
) )
} }
return join(this.dir, path) return this.join(this.dir, path)
.catch((error) => { .catch((error) => {
return Promise.reject(new Error(`Error checking file exists: ${error}`)) return Promise.reject(new Error(`Error checking file exists: ${error}`))
}) })
.then((file) => { .then((file) => {
return tauriExists(file) return window.electron.ipcRenderer.invoke('exists', [file])
}) })
} }
async getAllFiles(path: string): Promise<string[] | void> { async getAllFiles(path: string): Promise<string[] | void> {
// Using local file system only works from Tauri. // Using local file system only works from desktop.
if (!isTauri()) { if (!isDesktop()) {
return Promise.reject( return Promise.reject(
new Error('This function can only be called from a Tauri application') new Error('This function can only be called from the desktop application')
) )
} }
return join(this.dir, path) return this.join(this.dir, path)
.catch((error) => { .catch((error) => {
return Promise.reject(new Error(`Error joining dir: ${error}`)) return Promise.reject(new Error(`Error joining dir: ${error}`))
}) })
.then((p) => { .then((filepath) => {
readDirRecursive(p) return window.electron.ipcRenderer.invoke('readdir', [filepath])
.catch((error) => { .catch((error) => {
return Promise.reject(new Error(`Error reading dir: ${error}`)) return Promise.reject(new Error(`Error reading dir: ${error}`))
}) })

View File

@ -14,7 +14,7 @@ import { AnyStateMachine, ContextFrom, InterpreterFrom } from 'xstate'
import { getPropertyByPath } from 'lib/objectPropertyByPath' import { getPropertyByPath } from 'lib/objectPropertyByPath'
import { buildCommandArgument } from 'lib/createMachineCommand' import { buildCommandArgument } from 'lib/createMachineCommand'
import decamelize from 'decamelize' import decamelize from 'decamelize'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { Setting } from 'lib/settings/initialSettings' import { Setting } from 'lib/settings/initialSettings'
// An array of the paths to all of the settings that have commandConfigs // An array of the paths to all of the settings that have commandConfigs
@ -78,7 +78,7 @@ export function createSettingsCommand({
settingConfig?.hideOnLevel === 'user' && !isProjectAvailable settingConfig?.hideOnLevel === 'user' && !isProjectAvailable
const shouldHideOnThisPlatform = const shouldHideOnThisPlatform =
settingConfig.hideOnPlatform && settingConfig.hideOnPlatform &&
(isTauri() (isDesktop()
? settingConfig.hideOnPlatform === 'desktop' ? settingConfig.hideOnPlatform === 'desktop'
: settingConfig.hideOnPlatform === 'web') : settingConfig.hideOnPlatform === 'web')
if ( if (

View File

@ -1,7 +1,7 @@
import { CommandLog, EngineCommandManager } from 'lang/std/engineConnection' import { CommandLog, EngineCommandManager } from 'lang/std/engineConnection'
import { WebrtcStats } from 'wasm-lib/kcl/bindings/WebrtcStats' import { WebrtcStats } from 'wasm-lib/kcl/bindings/WebrtcStats'
import { OsInfo } from 'wasm-lib/kcl/bindings/OsInfo' import { OsInfo } from 'wasm-lib/kcl/bindings/OsInfo'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { import {
platform as tauriPlatform, platform as tauriPlatform,
arch as tauriArch, arch as tauriArch,
@ -68,7 +68,7 @@ export class CoreDumpManager {
// Get the os information. // Get the os information.
getOsInfo(): Promise<string> { getOsInfo(): Promise<string> {
if (this.isTauri()) { if (this.isDesktop()) {
const osinfo: OsInfo = { const osinfo: OsInfo = {
platform: tauriPlatform(), platform: tauriPlatform(),
arch: tauriArch(), arch: tauriArch(),
@ -101,8 +101,8 @@ export class CoreDumpManager {
return new Promise((resolve) => resolve(JSON.stringify(osinfo))) return new Promise((resolve) => resolve(JSON.stringify(osinfo)))
} }
isTauri(): boolean { isDesktop(): boolean {
return isTauri() return isDesktop()
} }
getWebrtcStats(): Promise<string> { getWebrtcStats(): Promise<string> {

View File

@ -5,7 +5,7 @@ import {
InterpreterFrom, InterpreterFrom,
StateFrom, StateFrom,
} from 'xstate' } from 'xstate'
import { isTauri } from './isTauri' import { isDesktop } from './isDesktop'
import { import {
Command, Command,
CommandArgument, CommandArgument,
@ -76,8 +76,8 @@ export function createMachineCommand<
if ('hide' in commandConfig) { if ('hide' in commandConfig) {
const { hide } = commandConfig const { hide } = commandConfig
if (hide === 'both') return null if (hide === 'both') return null
else if (hide === 'desktop' && isTauri()) return null else if (hide === 'desktop' && isDesktop()) return null
else if (hide === 'web' && !isTauri()) return null else if (hide === 'web' && !isDesktop()) return null
} }
const icon = ('icon' in commandConfig && commandConfig.icon) || undefined const icon = ('icon' in commandConfig && commandConfig.icon) || undefined

View File

@ -1,30 +1,31 @@
// This file contains wrappers around the tauri commands we define in rust code.
import { Models } from '@kittycad/lib/dist/types/src' import { Models } from '@kittycad/lib/dist/types/src'
import { invoke } from '@tauri-apps/api/core'
import { Configuration } from 'wasm-lib/kcl/bindings/Configuration' import { Configuration } from 'wasm-lib/kcl/bindings/Configuration'
import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration' import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration'
import { Project } from 'wasm-lib/kcl/bindings/Project' import { Project } from 'wasm-lib/kcl/bindings/Project'
import { FileEntry } from 'wasm-lib/kcl/bindings/FileEntry' import { FileEntry } from 'wasm-lib/kcl/bindings/FileEntry'
import { ProjectState } from 'wasm-lib/kcl/bindings/ProjectState' import { ProjectState } from 'wasm-lib/kcl/bindings/ProjectState'
import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute' import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute'
import { isTauri } from './isTauri'
import { components } from './machine-api' import { components } from './machine-api'
import { isDesktop } from './isDesktop'
// Get the app state from tauri. // All these functions call into lib/electron since many require filesystem
// access, and the second half is the original tauri code also stored app
// state on the "desktop" side.
// Get the app state from desktop.
export async function getState(): Promise<ProjectState | undefined> { export async function getState(): Promise<ProjectState | undefined> {
if (!isTauri()) { if (!isDesktop()) {
return undefined return undefined
} }
return await invoke<ProjectState | undefined>('get_state') return await window.electron.ipcRenderer.invoke('get_state')
} }
// Set the app state in tauri. // Set the app state in desktop.
export async function setState(state: ProjectState | undefined): Promise<void> { export async function setState(state: ProjectState | undefined): Promise<void> {
if (!isTauri()) { if (!isDesktop()) {
return return
} }
return await invoke('set_state', { state }) return window.electron.ipcRenderer.invoke('set_state', { state })
} }
// List machines on the local network. // List machines on the local network.
@ -49,30 +50,30 @@ export async function renameProjectDirectory(
// Get the initial default dir for holding all projects. // Get the initial default dir for holding all projects.
export async function getInitialDefaultDir(): Promise<string> { export async function getInitialDefaultDir(): Promise<string> {
if (!isTauri()) { if (!isDesktop()) {
return '' return ''
} }
return invoke<string>('get_initial_default_dir') return invoke<string>('get_initial_default_dir')
} }
export async function showInFolder(path: string | undefined): Promise<void> { export async function showInFolder(path: string | undefined): Promise<void> {
if (!isTauri()) { if (!isDesktop()) {
return return
} }
if (!path) { if (!path) {
console.error('path is undefined cannot call tauri showInFolder') console.error('path is undefined cannot call desktop showInFolder')
return return
} }
return await invoke('show_in_folder', { path }) return window.electron.ipcRenderer.invoke('show_in_folder', { path })
} }
export async function initializeProjectDirectory( export async function initializeProjectDirectory(
settings: Configuration settings: Configuration
): Promise<string | undefined> { ): Promise<string | undefined> {
if (!isTauri()) { if (!isDesktop()) {
return undefined return undefined
} }
return await invoke<string>('initialize_project_directory', { return window.electron.ipcRenderer.invoke('initialize_project_directory', {
configuration: settings, configuration: settings,
}) })
} }
@ -85,7 +86,7 @@ export async function createNewProjectDirectory(
if (!configuration) { if (!configuration) {
configuration = await readAppSettingsFile() configuration = await readAppSettingsFile()
} }
return await invoke<Project>('create_new_project_directory', { return window.electron.ipcRenderer.invoke('create_new_project_directory', {
configuration, configuration,
projectName, projectName,
initialCode, initialCode,
@ -98,7 +99,7 @@ export async function listProjects(
if (!configuration) { if (!configuration) {
configuration = await readAppSettingsFile() configuration = await readAppSettingsFile()
} }
return await invoke<Project[]>('list_projects', { configuration }) return window.electron.ipcRenderer.invoke('list_projects', { configuration })
} }
export async function getProjectInfo( export async function getProjectInfo(
@ -108,21 +109,21 @@ export async function getProjectInfo(
if (!configuration) { if (!configuration) {
configuration = await readAppSettingsFile() configuration = await readAppSettingsFile()
} }
return await invoke<Project>('get_project_info', { return window.electron.ipcRenderer.invoke('get_project_info', {
configuration, configuration,
projectPath, projectPath,
}) })
} }
export async function login(host: string): Promise<string> { export async function login(host: string): Promise<string> {
return await invoke('login', { host }) return window.electron.ipcRenderer.invoke('login', { host })
} }
export async function parseProjectRoute( export async function parseProjectRoute(
configuration: Configuration, configuration: Configuration,
route: string route: string
): Promise<ProjectRoute> { ): Promise<ProjectRoute> {
return await invoke<ProjectRoute>('parse_project_route', { return window.electron.ipcRenderer.invoke('parse_project_route', {
configuration, configuration,
route, route,
}) })
@ -133,11 +134,11 @@ export async function getUser(
host: string host: string
): Promise<Models['User_type'] | Record<'error_code', unknown> | void> { ): Promise<Models['User_type'] | Record<'error_code', unknown> | void> {
if (!token) { if (!token) {
console.error('token is undefined cannot call tauri getUser') console.error('token is undefined cannot call desktop getUser')
return return
} }
return await invoke<Models['User_type'] | Record<'error_code', unknown>>( return window.electron.ipcRenderer.invoke>(
'get_user', 'get_user',
{ {
token: token, token: token,
@ -147,26 +148,26 @@ export async function getUser(
} }
export async function readDirRecursive(path: string): Promise<FileEntry[]> { export async function readDirRecursive(path: string): Promise<FileEntry[]> {
return await invoke<FileEntry[]>('read_dir_recursive', { path }) return window.electron.ipcRenderer.invoke('read_dir_recursive', { path })
} }
// Read the contents of the app settings. // Read the contents of the app settings.
export async function readAppSettingsFile(): Promise<Configuration> { export async function readAppSettingsFile(): Promise<Configuration> {
return await invoke<Configuration>('read_app_settings_file') return window.electron.ipcRenderer.invoke('read_app_settings_file')
} }
// Write the contents of the app settings. // Write the contents of the app settings.
export async function writeAppSettingsFile( export async function writeAppSettingsFile(
settings: Configuration settings: Configuration
): Promise<void> { ): Promise<void> {
return await invoke('write_app_settings_file', { configuration: settings }) return window.electron.ipcRenderer.invoke('write_app_settings_file', { configuration: settings })
} }
// Read project settings file. // Read project settings file.
export async function readProjectSettingsFile( export async function readProjectSettingsFile(
projectPath: string projectPath: string
): Promise<ProjectConfiguration> { ): Promise<ProjectConfiguration> {
return await invoke<ProjectConfiguration>('read_project_settings_file', { return window.electron.ipcRenderer.invoke('read_project_settings_file', {
projectPath, projectPath,
}) })
} }
@ -176,7 +177,7 @@ export async function writeProjectSettingsFile(
projectPath: string, projectPath: string,
settings: ProjectConfiguration settings: ProjectConfiguration
): Promise<void> { ): Promise<void> {
return await invoke('write_project_settings_file', { return window.electron.ipcRenderer.invoke('write_project_settings_file', {
projectPath, projectPath,
configuration: settings, configuration: settings,
}) })

8
src/lib/electron.ts Normal file
View File

@ -0,0 +1,8 @@
import { app, ipcMain } from 'electron'
const DEFAULT_HOST = "https://api.zoo.dev"
const SETTINGS_FILE_NAME = "settings.toml"
const PROJECT_SETTINGS_FILE_NAME = "project.toml"
const PROJECT_FOLDER = "zoo-modeling-app-projects"

View File

@ -1,4 +1,4 @@
import { isTauri } from './isTauri' import { isDesktop } from './isDesktop'
import { deserialize_files } from '../wasm-lib/pkg/wasm_lib' import { deserialize_files } from '../wasm-lib/pkg/wasm_lib'
import { browserSaveFile } from './browserSaveFile' import { browserSaveFile } from './browserSaveFile'
import { save } from '@tauri-apps/plugin-dialog' import { save } from '@tauri-apps/plugin-dialog'
@ -9,7 +9,7 @@ import ModelingAppFile from './modelingAppFile'
const save_ = async (file: ModelingAppFile) => { const save_ = async (file: ModelingAppFile) => {
try { try {
if (isTauri()) { if (isDesktop()) {
const extension = file.name.split('.').pop() || null const extension = file.name.split('.').pop() || null
let extensions: string[] = [] let extensions: string[] = []
if (extension !== null) { if (extension !== null) {

18
src/lib/fs.ts Normal file
View File

@ -0,0 +1,18 @@
const { app, ipcMain } = require('electron')
const path = require('node:path')
const fs = require('node:fs')
app.whenReady().then(() => {
ipcMain.handle('readFile', async (event) => {
return fs.readFile(event.data[0], 'utf-8')
})
ipcMain.handle('readdir', async (event) => {
return fs.readdir(event.data[0], 'utf-8')
})
ipcMain.handle('join', async (event) => {
return path.join(event.data[0])
})
ipcMain.handle('exists', async (event) => {
return fs.exists(event.data[0])
})
})

5
src/lib/isDesktop.ts Normal file
View File

@ -0,0 +1,5 @@
// https://github.com/electron/electron/issues/2288#issuecomment-337858978
// Thank you
export function isDesktop(): boolean {
return navigator.userAgent.toLowerCase().indexOf("electron") > -1;
}

View File

@ -1,6 +0,0 @@
export function isTauri(): boolean {
if (globalThis.window && typeof globalThis.window !== 'undefined') {
return '__TAURI_INTERNALS__' in globalThis.window
}
return false
}

View File

@ -1,9 +1,9 @@
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { open as tauriOpen } from '@tauri-apps/plugin-shell' import { open as tauriOpen } from '@tauri-apps/plugin-shell'
// Open a new browser window tauri style or browser style. // Open a new browser window tauri style or browser style.
export default async function openWindow(url: string) { export default async function openWindow(url: string) {
if (isTauri()) { if (isDesktop()) {
await tauriOpen(url) await tauriOpen(url)
} else { } else {
window.open(url, '_blank') window.open(url, '_blank')

View File

@ -1,6 +1,6 @@
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { BROWSER_FILE_NAME, BROWSER_PROJECT_NAME, FILE_EXT } from './constants' import { BROWSER_FILE_NAME, BROWSER_PROJECT_NAME, FILE_EXT } from './constants'
import { isTauri } from './isTauri' import { isDesktop } from './isDesktop'
import { Configuration } from 'wasm-lib/kcl/bindings/Configuration' import { Configuration } from 'wasm-lib/kcl/bindings/Configuration'
import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute' import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute'
import { parseProjectRoute, readAppSettingsFile } from './tauri' import { parseProjectRoute, readAppSettingsFile } from './tauri'
@ -38,7 +38,7 @@ export async function getProjectMetaByRouteId(
): Promise<ProjectRoute | undefined> { ): Promise<ProjectRoute | undefined> {
if (!id) return undefined if (!id) return undefined
const inTauri = isTauri() const inTauri = isDesktop()
if (configuration === undefined) { if (configuration === undefined) {
configuration = inTauri configuration = inTauri

View File

@ -1,6 +1,6 @@
import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom' import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'
import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types' import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types'
import { isTauri } from './isTauri' import { isDesktop } from './isDesktop'
import { getProjectMetaByRouteId, paths } from './paths' import { getProjectMetaByRouteId, paths } from './paths'
import { BROWSER_PATH } from 'lib/paths' import { BROWSER_PATH } from 'lib/paths'
import { import {
@ -90,7 +90,7 @@ export const fileLoader: LoaderFunction = async ({
if (!current_file_name || !current_file_path || !project_name) { if (!current_file_name || !current_file_path || !project_name) {
return redirect( return redirect(
`${paths.FILE}/${encodeURIComponent( `${paths.FILE}/${encodeURIComponent(
`${params.id}${isTauri() ? sep() : '/'}${PROJECT_ENTRYPOINT}` `${params.id}${isDesktop() ? sep() : '/'}${PROJECT_ENTRYPOINT}`
)}` )}`
) )
} }
@ -114,7 +114,7 @@ export const fileLoader: LoaderFunction = async ({
const projectData: IndexLoaderData = { const projectData: IndexLoaderData = {
code, code,
project: isTauri() project: isDesktop()
? await getProjectInfo(project_path, configuration) ? await getProjectInfo(project_path, configuration)
: { : {
name: project_name, name: project_name,
@ -157,7 +157,7 @@ export const fileLoader: LoaderFunction = async ({
export const homeLoader: LoaderFunction = async (): Promise< export const homeLoader: LoaderFunction = async (): Promise<
HomeLoaderData | Response HomeLoaderData | Response
> => { > => {
if (!isTauri()) { if (!isDesktop()) {
return redirect(paths.FILE + '/%2F' + BROWSER_PROJECT_NAME) return redirect(paths.FILE + '/%2F' + BROWSER_PROJECT_NAME)
} }
const { configuration } = await loadAndValidateSettings() const { configuration } = await loadAndValidateSettings()

View File

@ -1,4 +1,4 @@
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
export type InteractionMapItem = { export type InteractionMapItem = {
name: string name: string
@ -38,7 +38,7 @@ export const interactionMap: Record<
Settings: [ Settings: [
{ {
name: 'toggle-settings', name: 'toggle-settings',
sequence: isTauri() ? 'Meta+,' : 'Shift+Meta+,', sequence: isDesktop() ? 'Meta+,' : 'Shift+Meta+,',
title: 'Toggle Settings', title: 'Toggle Settings',
description: 'Opens the settings dialog. Always available.', description: 'Opens the settings dialog. Always available.',
}, },

View File

@ -12,7 +12,7 @@ import {
cameraMouseDragGuards, cameraMouseDragGuards,
cameraSystems, cameraSystems,
} from 'lib/cameraControls' } from 'lib/cameraControls'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useRef } from 'react' import { useRef } from 'react'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { CustomIcon } from 'components/CustomIcon' import { CustomIcon } from 'components/CustomIcon'
@ -192,7 +192,7 @@ export function createSettings() {
description: 'The directory to save and load projects from', description: 'The directory to save and load projects from',
hideOnLevel: 'project', hideOnLevel: 'project',
hideOnPlatform: 'web', hideOnPlatform: 'web',
validate: (v) => typeof v === 'string' && (v.length > 0 || !isTauri()), validate: (v) => typeof v === 'string' && (v.length > 0 || !isDesktop()),
Component: ({ value, updateValue }) => { Component: ({ value, updateValue }) => {
const inputRef = useRef<HTMLInputElement>(null) const inputRef = useRef<HTMLInputElement>(null)
return ( return (

View File

@ -1,6 +1,6 @@
import { Setting, createSettings, settings } from 'lib/settings/initialSettings' import { Setting, createSettings, settings } from 'lib/settings/initialSettings'
import { SaveSettingsPayload, SettingsLevel } from './settingsTypes' import { SaveSettingsPayload, SettingsLevel } from './settingsTypes'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { import {
defaultAppSettings, defaultAppSettings,
@ -18,7 +18,7 @@ import {
readProjectSettingsFile, readProjectSettingsFile,
writeAppSettingsFile, writeAppSettingsFile,
writeProjectSettingsFile, writeProjectSettingsFile,
} from 'lib/tauri' } from 'lib/desktop'
import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration' import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration'
import { BROWSER_PROJECT_NAME } from 'lib/constants' import { BROWSER_PROJECT_NAME } from 'lib/constants'
@ -159,15 +159,15 @@ export async function loadAndValidateSettings(
projectPath?: string projectPath?: string
): Promise<AppSettings> { ): Promise<AppSettings> {
const settings = createSettings() const settings = createSettings()
const inTauri = isTauri() const onDesktop = isDesktop()
if (!inTauri) { if (!onDesktop) {
// Make sure we have wasm initialized. // Make sure we have wasm initialized.
await initPromise await initPromise
} }
// Load the app settings from the file system or localStorage. // Load the app settings from the file system or localStorage.
const appSettings = inTauri const appSettings = onDesktop
? await readAppSettingsFile() ? await readAppSettingsFile()
: readLocalStorageAppSettingsFile() : readLocalStorageAppSettingsFile()
@ -179,7 +179,7 @@ export async function loadAndValidateSettings(
// Load the project settings if they exist // Load the project settings if they exist
if (projectPath) { if (projectPath) {
const projectSettings = inTauri const projectSettings = onDesktop
? await readProjectSettingsFile(projectPath) ? await readProjectSettingsFile(projectPath)
: readLocalStorageProjectSettingsFile() : readLocalStorageProjectSettingsFile()
@ -201,7 +201,7 @@ export async function saveSettings(
) { ) {
// Make sure we have wasm initialized. // Make sure we have wasm initialized.
await initPromise await initPromise
const inTauri = isTauri() const onDesktop = isDesktop()
// Get the user settings. // Get the user settings.
const jsAppSettings = getChangedSettingsAtLevel(allSettings, 'user') const jsAppSettings = getChangedSettingsAtLevel(allSettings, 'user')
@ -216,7 +216,7 @@ export async function saveSettings(
if (err(tomlString2)) return if (err(tomlString2)) return
// Write the app settings. // Write the app settings.
if (inTauri) { if (onDesktop) {
await writeAppSettingsFile(appSettings) await writeAppSettingsFile(appSettings)
} else { } else {
localStorage.setItem(localStorageAppSettingsPath(), tomlString2) localStorage.setItem(localStorageAppSettingsPath(), tomlString2)
@ -241,7 +241,7 @@ export async function saveSettings(
if (err(tomlStr)) return if (err(tomlStr)) return
// Write the project settings. // Write the project settings.
if (inTauri) { if (onDesktop) {
await writeProjectSettingsFile(projectPath, projectSettings) await writeProjectSettingsFile(projectPath, projectSettings)
} else { } else {
localStorage.setItem(localStorageProjectSettingsPath(), tomlStr) localStorage.setItem(localStorageProjectSettingsPath(), tomlStr)
@ -315,7 +315,7 @@ export function shouldHideSetting(
return ( return (
setting.hideOnLevel === settingsLevel || setting.hideOnLevel === settingsLevel ||
setting.hideOnPlatform === 'both' || setting.hideOnPlatform === 'both' ||
(setting.hideOnPlatform && isTauri() (setting.hideOnPlatform && isDesktop()
? setting.hideOnPlatform === 'desktop' ? setting.hideOnPlatform === 'desktop'
: setting.hideOnPlatform === 'web') : setting.hideOnPlatform === 'web')
) )

View File

@ -1,5 +1,5 @@
import { appConfigDir } from '@tauri-apps/api/path' import { appConfigDir } from '@tauri-apps/api/path'
import { isTauri } from './isTauri' import { isDesktop } from './isDesktop'
import type { FileEntry } from 'lib/types' import type { FileEntry } from 'lib/types'
import { import {
INDEX_IDENTIFIER, INDEX_IDENTIFIER,
@ -108,7 +108,7 @@ function getPaddedIdentifierRegExp() {
} }
export async function getSettingsFolderPaths(projectPath?: string) { export async function getSettingsFolderPaths(projectPath?: string) {
const user = isTauri() ? await appConfigDir() : '/' const user = isDesktop() ? await appConfigDir() : '/'
const project = projectPath !== undefined ? projectPath : undefined const project = projectPath !== undefined ? projectPath : undefined
return { return {

View File

@ -1,7 +1,7 @@
import { createMachine, assign } from 'xstate' import { createMachine, assign } from 'xstate'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import withBaseURL from '../lib/withBaseURL' import withBaseURL from '../lib/withBaseURL'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { VITE_KC_API_BASE_URL, VITE_KC_DEV_TOKEN } from 'env' import { VITE_KC_API_BASE_URL, VITE_KC_DEV_TOKEN } from 'env'
import { getUser as getUserTauri } from 'lib/tauri' import { getUser as getUserTauri } from 'lib/tauri'
@ -123,7 +123,7 @@ async function getUser(context: UserContext) {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
} }
if (!token && isTauri()) return Promise.reject(new Error('No token found')) if (!token && isDesktop()) return Promise.reject(new Error('No token found'))
if (token) headers['Authorization'] = `Bearer ${context.token}` if (token) headers['Authorization'] = `Bearer ${context.token}`
if (SKIP_AUTH) { if (SKIP_AUTH) {
@ -138,7 +138,7 @@ async function getUser(context: UserContext) {
} }
} }
const userPromise = !isTauri() const userPromise = !isDesktop()
? fetch(url, { ? fetch(url, {
method: 'GET', method: 'GET',
credentials: 'include', credentials: 'include',
@ -164,7 +164,7 @@ async function getUser(context: UserContext) {
} }
function getCookie(cname: string): string | null { function getCookie(cname: string): string | null {
if (isTauri()) { if (isDesktop()) {
return null return null
} }

View File

@ -3,6 +3,7 @@
import { app, BrowserWindow } from 'electron' import { app, BrowserWindow } from 'electron'
import path from 'path' import path from 'path'
import 'lib/fs'
// Handle creating/removing shortcuts on Windows when installing/uninstalling. // Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { if (require('electron-squirrel-startup')) {
@ -41,3 +42,4 @@ app.on('window-all-closed', () => {
// initialization and is ready to create browser windows. // initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs. // Some APIs can only be used after this event occurs.
app.on('ready', createWindow) app.on('ready', createWindow)

View File

@ -28,7 +28,7 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
import { join, sep } from '@tauri-apps/api/path' import { join, sep } from '@tauri-apps/api/path'
import { homeCommandBarConfig } from 'lib/commandBarConfigs/homeCommandConfig' import { homeCommandBarConfig } from 'lib/commandBarConfigs/homeCommandConfig'
import { useHotkeys } from 'react-hotkeys-hook' import { useHotkeys } from 'react-hotkeys-hook'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { useLspContext } from 'components/LspProvider' import { useLspContext } from 'components/LspProvider'
import { useRefreshSettings } from 'hooks/useRefreshSettings' import { useRefreshSettings } from 'hooks/useRefreshSettings'
@ -38,7 +38,7 @@ import {
createNewProjectDirectory, createNewProjectDirectory,
listProjects, listProjects,
renameProjectDirectory, renameProjectDirectory,
} from 'lib/tauri' } from 'lib/desktop'
import { ProjectSearchBar, useProjectSearch } from 'components/ProjectSearchBar' import { ProjectSearchBar, useProjectSearch } from 'components/ProjectSearchBar'
// This route only opens in the Tauri desktop context for now, // This route only opens in the Tauri desktop context for now,
@ -62,7 +62,7 @@ const Home = () => {
e.preventDefault() e.preventDefault()
}) })
useHotkeys( useHotkeys(
isTauri() ? 'mod+,' : 'shift+mod+,', isDesktop() ? 'mod+,' : 'shift+mod+,',
() => navigate(paths.HOME + paths.SETTINGS), () => navigate(paths.HOME + paths.SETTINGS),
{ {
splitKey: '|', splitKey: '|',

View File

@ -4,8 +4,9 @@ import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { Themes, getSystemTheme } from 'lib/theme' import { Themes, getSystemTheme } from 'lib/theme'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { createAndOpenNewProject } from 'lib/tauriFS' import { createAndOpenNewProject } from 'lib/tauriFS'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useNavigate, useRouteLoaderData } from 'react-router-dom' import { useNavigate, useRouteLoaderData } from 'react-router-dom'
import { paths } from 'lib/paths'
import { codeManager, kclManager } from 'lib/singletons' import { codeManager, kclManager } from 'lib/singletons'
import { APP_NAME } from 'lib/constants' import { APP_NAME } from 'lib/constants'
import { useState } from 'react' import { useState } from 'react'

View File

@ -1,13 +1,13 @@
import { OnboardingButtons, useDismiss, useNextClick } from '.' import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
export default function ProjectMenu() { export default function ProjectMenu() {
const { context } = useModelingContext() const { context } = useModelingContext()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.EXPORT) const next = useNextClick(onboardingPaths.EXPORT)
const tauri = isTauri() const tauri = isDesktop()
return ( return (
<div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none"> <div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none">

View File

@ -12,9 +12,9 @@ import { SettingsSectionsList } from 'components/Settings/SettingsSectionsList'
import { AllSettingsFields } from 'components/Settings/AllSettingsFields' import { AllSettingsFields } from 'components/Settings/AllSettingsFields'
import { AllKeybindingsFields } from 'components/Settings/AllKeybindingsFields' import { AllKeybindingsFields } from 'components/Settings/AllKeybindingsFields'
import { KeybindingsSectionsList } from 'components/Settings/KeybindingsSectionsList' import { KeybindingsSectionsList } from 'components/Settings/KeybindingsSectionsList'
import { isTauri } from 'lib/isTauri' import { isDesktop } from 'lib/isDesktop'
export const APP_VERSION = isTauri() export const APP_VERSION = isDesktop()
? import.meta.env.PACKAGE_VERSION || 'unknown' ? import.meta.env.PACKAGE_VERSION || 'unknown'
: 'main' : 'main'

View File

@ -1,5 +1,5 @@
import { ActionButton } from '../components/ActionButton' import { ActionButton } from '../components/ActionButton'
import { isTauri } from '../lib/isTauri' import { isDesktop } from '../lib/isDesktop'
import { VITE_KC_SITE_BASE_URL, VITE_KC_API_BASE_URL } from '../env' import { VITE_KC_SITE_BASE_URL, VITE_KC_API_BASE_URL } from '../env'
import { Themes, getSystemTheme } from '../lib/theme' import { Themes, getSystemTheme } from '../lib/theme'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
@ -61,7 +61,7 @@ const SignIn = () => {
ZMA is ready for production, please sign up for our mailing list at{' '} ZMA is ready for production, please sign up for our mailing list at{' '}
<a href="https://zoo.dev">zoo.dev</a>. <a href="https://zoo.dev">zoo.dev</a>.
</p> </p>
{isTauri() ? ( {isDesktop() ? (
<ActionButton <ActionButton
Element="button" Element="button"
onClick={signInTauri} onClick={signInTauri}

View File

@ -47,7 +47,7 @@ impl CoreDump for CoreDumper {
}) })
} }
fn is_tauri(&self) -> Result<bool> { fn is_desktop(&self) -> Result<bool> {
Ok(false) Ok(false)
} }

View File

@ -29,7 +29,7 @@ pub trait CoreDump: Clone {
async fn os(&self) -> Result<OsInfo>; async fn os(&self) -> Result<OsInfo>;
fn is_tauri(&self) -> Result<bool>; fn is_desktop(&self) -> Result<bool>;
async fn get_webrtc_stats(&self) -> Result<WebrtcStats>; async fn get_webrtc_stats(&self) -> Result<WebrtcStats>;
@ -81,7 +81,7 @@ pub trait CoreDump: Clone {
version: self.version()?, version: self.version()?,
git_rev: git_rev::try_revision_string!().map_or_else(|| "unknown".to_string(), |s| s.to_string()), git_rev: git_rev::try_revision_string!().map_or_else(|| "unknown".to_string(), |s| s.to_string()),
timestamp: chrono::Utc::now(), timestamp: chrono::Utc::now(),
tauri: self.is_tauri()?, tauri: self.is_desktop()?,
os, os,
webrtc_stats, webrtc_stats,
github_issue_url: None, github_issue_url: None,

View File

@ -26,8 +26,8 @@ extern "C" {
#[wasm_bindgen(method, js_name = getOsInfo, catch)] #[wasm_bindgen(method, js_name = getOsInfo, catch)]
fn get_os_info(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; fn get_os_info(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>;
#[wasm_bindgen(method, js_name = isTauri, catch)] #[wasm_bindgen(method, js_name = isDesktop, catch)]
fn is_tauri(this: &CoreDumpManager) -> Result<bool, js_sys::Error>; fn is_desktop(this: &CoreDumpManager) -> Result<bool, js_sys::Error>;
#[wasm_bindgen(method, js_name = getWebrtcStats, catch)] #[wasm_bindgen(method, js_name = getWebrtcStats, catch)]
fn get_webrtc_stats(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; fn get_webrtc_stats(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>;
@ -100,9 +100,9 @@ impl CoreDump for CoreDumper {
Ok(os) Ok(os)
} }
fn is_tauri(&self) -> Result<bool> { fn is_desktop(&self) -> Result<bool> {
self.manager self.manager
.is_tauri() .is_desktop()
.map_err(|e| anyhow::anyhow!("Failed to get response from is tauri: {:?}", e)) .map_err(|e| anyhow::anyhow!("Failed to get response from is tauri: {:?}", e))
} }