At implementing login and getUser
This commit is contained in:
@ -60,6 +60,9 @@ root.render(
|
||||
reportWebVitals()
|
||||
|
||||
const runTauriUpdater = async () => {
|
||||
console.log('STUB: @pierre')
|
||||
return
|
||||
|
||||
try {
|
||||
const update = await check()
|
||||
if (update && update.available) {
|
||||
|
@ -15,14 +15,16 @@ class FileSystemManager {
|
||||
}
|
||||
|
||||
async join(dir: string, path: string): Promise<string> {
|
||||
return window.electron.ipcRenderer.invoke('join', [dir, path]);
|
||||
return window.electron.ipcRenderer.invoke('join', [dir, path])
|
||||
}
|
||||
|
||||
async readFile(path: string): Promise<Uint8Array | void> {
|
||||
// Using local file system only works from desktop.
|
||||
if (!isDesktop()) {
|
||||
return Promise.reject(
|
||||
new Error('This function can only be called from the desktop application')
|
||||
new Error(
|
||||
'This function can only be called from the desktop application'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -39,7 +41,9 @@ class FileSystemManager {
|
||||
// Using local file system only works from desktop.
|
||||
if (!isDesktop()) {
|
||||
return Promise.reject(
|
||||
new Error('This function can only be called from the desktop application')
|
||||
new Error(
|
||||
'This function can only be called from the desktop application'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -56,7 +60,9 @@ class FileSystemManager {
|
||||
// Using local file system only works from desktop.
|
||||
if (!isDesktop()) {
|
||||
return Promise.reject(
|
||||
new Error('This function can only be called from the desktop application')
|
||||
new Error(
|
||||
'This function can only be called from the desktop application'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -65,7 +71,8 @@ class FileSystemManager {
|
||||
return Promise.reject(new Error(`Error joining dir: ${error}`))
|
||||
})
|
||||
.then((filepath) => {
|
||||
return window.electron.ipcRenderer.invoke('readdir', [filepath])
|
||||
return window.electron.ipcRenderer
|
||||
.invoke('readdir', [filepath])
|
||||
.catch((error) => {
|
||||
return Promise.reject(new Error(`Error reading dir: ${error}`))
|
||||
})
|
||||
|
@ -17,6 +17,7 @@ import init, {
|
||||
parse_project_settings,
|
||||
default_project_settings,
|
||||
parse_project_route,
|
||||
serialize_project_settings,
|
||||
} from '../wasm-lib/pkg/wasm_lib'
|
||||
import { KCLError } from './errors'
|
||||
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
|
||||
@ -558,7 +559,7 @@ export function tomlStringify(toml: any): string | Error {
|
||||
return toml_stringify(JSON.stringify(toml))
|
||||
}
|
||||
|
||||
export function defaultAppSettings(): Configuration | Error {
|
||||
export function defaultAppSettings(): Configuration {
|
||||
return default_app_settings()
|
||||
}
|
||||
|
||||
@ -582,3 +583,79 @@ export function parseProjectRoute(
|
||||
): ProjectRoute | Error {
|
||||
return parse_project_route(JSON.stringify(configuration), route_str)
|
||||
}
|
||||
|
||||
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'
|
||||
|
||||
const getAppSettingsFilePath = async () => {
|
||||
const appConfig = await window.electron.getPath('appData')
|
||||
const fullPath = window.electron.path.join(
|
||||
appConfig,
|
||||
window.electron.packageJson.name
|
||||
)
|
||||
try {
|
||||
await window.electron.exists(fullPath)
|
||||
} catch (e) {
|
||||
// File/path doesn't exist
|
||||
if (e.code === 'ENOENT') {
|
||||
window.electron.mkdir(fullPath, { recursive: true })
|
||||
}
|
||||
}
|
||||
return window.electron.path.join(fullPath, SETTINGS_FILE_NAME)
|
||||
}
|
||||
|
||||
const getInitialDefaultDir = async () => {
|
||||
const dir = await window.electron.getPath('documents')
|
||||
return window.electron.path.join(dir, PROJECT_FOLDER)
|
||||
}
|
||||
|
||||
export const readAppSettingsFile = async () => {
|
||||
let settingsPath = await getAppSettingsFilePath()
|
||||
try {
|
||||
await window.electron.exists(settingsPath)
|
||||
} catch (e) {
|
||||
if (e === 'ENOENT') {
|
||||
const config = defaultAppSettings()
|
||||
config.settings.project.directory = await getInitialDefaultDir()
|
||||
console.log(config)
|
||||
return config
|
||||
}
|
||||
}
|
||||
const configToml = await window.electron.readFile(settingsPath)
|
||||
const configObj = parseProjectSettings(configStr)
|
||||
return configObj
|
||||
}
|
||||
|
||||
export const writeAppSettingsFile = async () => {
|
||||
debugger
|
||||
console.log("STUB")
|
||||
}
|
||||
|
||||
let appStateStore = undefined
|
||||
|
||||
export const getState = async (): Promise<ProjectState | undefined> => {
|
||||
return Promise.resolve(appStateStore)
|
||||
}
|
||||
|
||||
export const setState = async (
|
||||
state: ProjectState | undefined
|
||||
): Promise<void> => {
|
||||
appStateStore = state
|
||||
}
|
||||
|
||||
const initializeProjectDirectory = () => {
|
||||
debugger
|
||||
console.log('STUB')
|
||||
}
|
||||
|
||||
export const login = () => {
|
||||
debugger
|
||||
console.log('STUB')
|
||||
}
|
||||
|
||||
export const getUser = (token: string, host: string) => {
|
||||
debugger
|
||||
console.log("STUB")
|
||||
}
|
||||
|
@ -8,21 +8,14 @@ import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute'
|
||||
import { components } from './machine-api'
|
||||
import { isDesktop } from './isDesktop'
|
||||
|
||||
// Get the app state from desktop.
|
||||
export async function getState(): Promise<ProjectState | undefined> {
|
||||
if (!isDesktop()) {
|
||||
return undefined
|
||||
}
|
||||
return await window.electron.ipcRenderer.invoke('get_state')
|
||||
}
|
||||
|
||||
// Set the app state in desktop.
|
||||
export async function setState(state: ProjectState | undefined): Promise<void> {
|
||||
if (!isDesktop()) {
|
||||
return
|
||||
}
|
||||
return window.electron.ipcRenderer.invoke('set_state', { state })
|
||||
}
|
||||
export {
|
||||
readAppSettingsFile,
|
||||
writeAppSettingsFile,
|
||||
getState,
|
||||
setState,
|
||||
getUser,
|
||||
login,
|
||||
} from 'lang/wasm'
|
||||
|
||||
// List machines on the local network.
|
||||
export async function listMachines(): Promise<{
|
||||
@ -41,21 +34,18 @@ export async function renameProjectDirectory(
|
||||
projectPath: string,
|
||||
newName: string
|
||||
): Promise<string> {
|
||||
return window.electron.ipcRenderer.invoke<string>('rename_project_directory', { projectPath, newName })
|
||||
return window.electron.ipcRenderer.invoke<string>(
|
||||
'rename_project_directory',
|
||||
{ projectPath, newName }
|
||||
)
|
||||
}
|
||||
|
||||
// Get the initial default dir for holding all projects.
|
||||
export async function getInitialDefaultDir(): Promise<string> {
|
||||
if (!isDesktop()) {
|
||||
return ''
|
||||
}
|
||||
return invoke<string>('get_initial_default_dir')
|
||||
return window.electron.getInitialDefaultDir()
|
||||
}
|
||||
|
||||
export async function showInFolder(path: string | undefined): Promise<void> {
|
||||
if (!isDesktop()) {
|
||||
return
|
||||
}
|
||||
if (!path) {
|
||||
console.error('path is undefined cannot call desktop showInFolder')
|
||||
return
|
||||
@ -64,14 +54,20 @@ export async function showInFolder(path: string | undefined): Promise<void> {
|
||||
}
|
||||
|
||||
export async function initializeProjectDirectory(
|
||||
settings: Configuration
|
||||
config: Configuration
|
||||
): Promise<string | undefined> {
|
||||
if (!isDesktop()) {
|
||||
return undefined
|
||||
}
|
||||
return window.electron.ipcRenderer.invoke('initialize_project_directory', {
|
||||
configuration: settings,
|
||||
const projectDir = config.settings.project.directory
|
||||
try {
|
||||
await window.electron.exists(projectDir)
|
||||
} catch (e) {
|
||||
if (e === 'ENOENT') {
|
||||
window.electron.mkdir(projectDir, { recursive: true }, (e) => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return projectDir
|
||||
}
|
||||
|
||||
export async function createNewProjectDirectory(
|
||||
@ -92,10 +88,13 @@ export async function createNewProjectDirectory(
|
||||
export async function listProjects(
|
||||
configuration?: Configuration
|
||||
): Promise<Project[]> {
|
||||
if (!configuration) {
|
||||
configuration = await readAppSettingsFile()
|
||||
const projectDir = await initializeProjectDirectory(configuration)
|
||||
const projects = []
|
||||
const entries = await window.electron.readdir(projectDir)
|
||||
for (let entry of entries) {
|
||||
// Ignore directories
|
||||
console.log(entry)
|
||||
}
|
||||
return window.electron.ipcRenderer.invoke('list_projects', { configuration })
|
||||
}
|
||||
|
||||
export async function getProjectInfo(
|
||||
@ -111,10 +110,6 @@ export async function getProjectInfo(
|
||||
})
|
||||
}
|
||||
|
||||
export async function login(host: string): Promise<string> {
|
||||
return window.electron.ipcRenderer.invoke('login', { host })
|
||||
}
|
||||
|
||||
export async function parseProjectRoute(
|
||||
configuration: Configuration,
|
||||
route: string
|
||||
@ -125,40 +120,10 @@ export async function parseProjectRoute(
|
||||
})
|
||||
}
|
||||
|
||||
export async function getUser(
|
||||
token: string | undefined,
|
||||
host: string
|
||||
): Promise<Models['User_type'] | Record<'error_code', unknown> | void> {
|
||||
if (!token) {
|
||||
console.error('token is undefined cannot call desktop getUser')
|
||||
return
|
||||
}
|
||||
|
||||
return window.electron.ipcRenderer.invoke>(
|
||||
'get_user',
|
||||
{
|
||||
token: token,
|
||||
hostname: host,
|
||||
}
|
||||
).catch((err) => console.error('error from Tauri getUser', err))
|
||||
}
|
||||
|
||||
export async function readDirRecursive(path: string): Promise<FileEntry[]> {
|
||||
return window.electron.ipcRenderer.invoke('read_dir_recursive', { path })
|
||||
}
|
||||
|
||||
// Read the contents of the app settings.
|
||||
export async function readAppSettingsFile(): Promise<Configuration> {
|
||||
return window.electron.ipcRenderer.invoke('read_app_settings_file')
|
||||
}
|
||||
|
||||
// Write the contents of the app settings.
|
||||
export async function writeAppSettingsFile(
|
||||
settings: Configuration
|
||||
): Promise<void> {
|
||||
return window.electron.ipcRenderer.invoke('write_app_settings_file', { configuration: settings })
|
||||
}
|
||||
|
||||
// Read project settings file.
|
||||
export async function readProjectSettingsFile(
|
||||
projectPath: string
|
||||
|
@ -1,19 +1,25 @@
|
||||
import { contextBridge } from 'electron'
|
||||
import { ipcRenderer, contextBridge } from 'electron'
|
||||
import path from 'path'
|
||||
import fs from 'node:fs'
|
||||
import fs from 'node:fs/promises'
|
||||
import packageJson from '../../package.json'
|
||||
|
||||
// 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.
|
||||
const readFile = (path: string) => fs.readFile(path, 'utf-8')
|
||||
const readdir = (path: string) => fs.readdir(path, 'utf-8')
|
||||
const exists = (path: string) =>
|
||||
new Promise((resolve, reject) =>
|
||||
fs.stat(path, (err, data) => {
|
||||
if (err) return reject(err.code)
|
||||
return resolve(data)
|
||||
})
|
||||
)
|
||||
const getPath = async (name: string) => ipcRenderer.invoke('app.getPath', name)
|
||||
|
||||
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"
|
||||
|
||||
contextBridge.exposeInMainWorld("fs", {
|
||||
readFile(p: string) { return fs.readFile(p, 'utf-8') },
|
||||
readdir(p: string) { return fs.readdir(p, 'utf-8') },
|
||||
join() { return path.join(...arguments) },
|
||||
exists(p: string) { fs.exists(p) },
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
readFile,
|
||||
readdir,
|
||||
path,
|
||||
exists,
|
||||
mkdir: fs.mkdir,
|
||||
getPath,
|
||||
packageJson,
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
// https://github.com/electron/electron/issues/2288#issuecomment-337858978
|
||||
// Thank you
|
||||
export function isDesktop(): boolean {
|
||||
return navigator.userAgent.toLowerCase().indexOf("electron") > -1;
|
||||
return navigator.userAgent.toLowerCase().indexOf('electron') > -1
|
||||
}
|
||||
|
@ -192,7 +192,8 @@ export function createSettings() {
|
||||
description: 'The directory to save and load projects from',
|
||||
hideOnLevel: 'project',
|
||||
hideOnPlatform: 'web',
|
||||
validate: (v) => typeof v === 'string' && (v.length > 0 || !isDesktop()),
|
||||
validate: (v) =>
|
||||
typeof v === 'string' && (v.length > 0 || !isDesktop()),
|
||||
Component: ({ value, updateValue }) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
return (
|
||||
|
@ -161,10 +161,8 @@ export async function loadAndValidateSettings(
|
||||
const settings = createSettings()
|
||||
const onDesktop = isDesktop()
|
||||
|
||||
if (!onDesktop) {
|
||||
// Make sure we have wasm initialized.
|
||||
await initPromise
|
||||
}
|
||||
|
||||
// Load the app settings from the file system or localStorage.
|
||||
const appSettings = onDesktop
|
||||
|
@ -1,4 +1,12 @@
|
||||
import toast from 'react-hot-toast'
|
||||
let toast = undefined
|
||||
|
||||
try {
|
||||
global
|
||||
} catch (e) {
|
||||
import('react-hot-toast').then((_toast) => {
|
||||
toast = _toast
|
||||
})
|
||||
}
|
||||
|
||||
type ExcludeErr<T> = Exclude<T, Error>
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { Models } from '@kittycad/lib'
|
||||
import withBaseURL from '../lib/withBaseURL'
|
||||
import { isDesktop } from 'lib/isDesktop'
|
||||
import { VITE_KC_API_BASE_URL, VITE_KC_DEV_TOKEN } from 'env'
|
||||
import { getUser as getUserTauri } from 'lib/desktop'
|
||||
import { getUser as getUserDesktop } from 'lib/desktop'
|
||||
|
||||
const SKIP_AUTH =
|
||||
import.meta.env.VITE_KC_SKIP_AUTH === 'true' && import.meta.env.DEV
|
||||
@ -146,7 +146,7 @@ async function getUser(context: UserContext) {
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.catch((err) => console.error('error from Browser getUser', err))
|
||||
: getUserTauri(context.token, VITE_KC_API_BASE_URL)
|
||||
: getUserDesktop(context.token, VITE_KC_API_BASE_URL)
|
||||
|
||||
const user = await userPromise
|
||||
|
||||
|
10
src/main.ts
10
src/main.ts
@ -1,7 +1,8 @@
|
||||
// Some of the following was taken from bits and pieces of the vite-typescript
|
||||
// template that ElectronJS provides.
|
||||
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import { Configuration } from 'wasm-lib/kcl/bindings/Configuration'
|
||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||
import path from 'path'
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
@ -17,8 +18,8 @@ const createWindow = () => {
|
||||
nodeIntegration: false, // do not give the application implicit system access
|
||||
contextIsolation: true, // expose system functions in preload
|
||||
sandbox: false, // expose nodejs in preload
|
||||
preload: path.join(__dirname, "./preload.js")
|
||||
}
|
||||
preload: path.join(__dirname, './preload.js'),
|
||||
},
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
@ -48,3 +49,6 @@ app.on('window-all-closed', () => {
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', createWindow)
|
||||
|
||||
ipcMain.handle('app.getPath', (event, data) => {
|
||||
return app.getPath(data)
|
||||
})
|
||||
|
13
src/wasm-lib/Cargo.lock
generated
13
src/wasm-lib/Cargo.lock
generated
@ -2589,6 +2589,17 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.14"
|
||||
@ -3625,6 +3636,8 @@ dependencies = [
|
||||
"kittycad",
|
||||
"pretty_assertions",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"toml",
|
||||
|
@ -16,6 +16,8 @@ gloo-utils = "0.2.0"
|
||||
kcl-lib = { path = "kcl" }
|
||||
kittycad.workspace = true
|
||||
serde_json = "1.0.122"
|
||||
serde_json = "1.0.122"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
tokio = { version = "1.39.2", features = ["sync"] }
|
||||
toml = "0.8.19"
|
||||
uuid = { version = "1.10.0", features = ["v4", "js", "serde"] }
|
||||
|
@ -19,7 +19,7 @@ const DEFAULT_PROJECT_NAME_TEMPLATE: &str = "project-$nnn";
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Configuration {
|
||||
/// The settings for the modeling app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub settings: Settings,
|
||||
}
|
||||
@ -183,23 +183,23 @@ impl Configuration {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Settings {
|
||||
/// The settings for the modeling app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub app: AppSettings,
|
||||
/// Settings that affect the behavior while modeling.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub modeling: ModelingSettings,
|
||||
/// Settings that affect the behavior of the KCL text editor.
|
||||
#[serde(default, alias = "textEditor", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "textEditor")]
|
||||
#[validate(nested)]
|
||||
pub text_editor: TextEditorSettings,
|
||||
/// Settings that affect the behavior of project management.
|
||||
#[serde(default, alias = "projects", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "projects")]
|
||||
#[validate(nested)]
|
||||
pub project: ProjectSettings,
|
||||
/// Settings that affect the behavior of the command bar.
|
||||
#[serde(default, alias = "commandBar", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "commandBar")]
|
||||
#[validate(nested)]
|
||||
pub command_bar: CommandBarSettings,
|
||||
}
|
||||
@ -212,11 +212,11 @@ pub struct Settings {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct AppSettings {
|
||||
/// The settings for the appearance of the app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub appearance: AppearanceSettings,
|
||||
/// The onboarding status of the app.
|
||||
#[serde(default, alias = "onboardingStatus", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "onboardingStatus")]
|
||||
pub onboarding_status: OnboardingStatus,
|
||||
/// Backwards compatible project directory setting.
|
||||
#[serde(default, alias = "projectDirectory", skip_serializing_if = "Option::is_none")]
|
||||
@ -232,10 +232,10 @@ pub struct AppSettings {
|
||||
pub enable_ssao: Option<bool>,
|
||||
/// Permanently dismiss the banner warning to download the desktop app.
|
||||
/// This setting only applies to the web app. And is temporary until we have Linux support.
|
||||
#[serde(default, alias = "dismissWebBanner", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "dismissWebBanner")]
|
||||
pub dismiss_web_banner: bool,
|
||||
/// When the user is idle, and this is true, the stream will be torn down.
|
||||
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "streamIdleMode")]
|
||||
stream_idle_mode: bool,
|
||||
}
|
||||
|
||||
@ -275,10 +275,10 @@ impl From<FloatOrInt> for AppColor {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct AppearanceSettings {
|
||||
/// The overall theme of the app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
pub theme: AppTheme,
|
||||
/// The hue of the primary theme color for the app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub color: AppColor,
|
||||
}
|
||||
@ -367,23 +367,23 @@ impl From<AppTheme> for kittycad::types::Color {
|
||||
#[ts(export)]
|
||||
pub struct ModelingSettings {
|
||||
/// The default unit to use in modeling dimensions.
|
||||
#[serde(default, alias = "defaultUnit", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "defaultUnit")]
|
||||
pub base_unit: UnitLength,
|
||||
/// The controls for how to navigate the 3D view.
|
||||
#[serde(default, alias = "mouseControls", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "mouseControls")]
|
||||
pub mouse_controls: MouseControlType,
|
||||
/// Highlight edges of 3D objects?
|
||||
#[serde(default, alias = "highlightEdges", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "highlightEdges")]
|
||||
pub highlight_edges: DefaultTrue,
|
||||
/// Whether to show the debug panel, which lets you see various states
|
||||
/// of the app to aid in development.
|
||||
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "showDebugPanel")]
|
||||
pub show_debug_panel: bool,
|
||||
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
pub enable_ssao: DefaultTrue,
|
||||
/// Whether or not to show a scale grid in the 3D modeling view
|
||||
#[serde(default, alias = "showScaleGrid", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "showScaleGrid")]
|
||||
pub show_scale_grid: bool,
|
||||
}
|
||||
|
||||
@ -492,10 +492,10 @@ pub enum MouseControlType {
|
||||
#[ts(export)]
|
||||
pub struct TextEditorSettings {
|
||||
/// Whether to wrap text in the editor or overflow with scroll.
|
||||
#[serde(default, alias = "textWrapping", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "textWrapping")]
|
||||
pub text_wrapping: DefaultTrue,
|
||||
/// Whether to make the cursor blink in the editor.
|
||||
#[serde(default, alias = "blinkingCursor", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "blinkingCursor")]
|
||||
pub blinking_cursor: DefaultTrue,
|
||||
}
|
||||
|
||||
@ -505,10 +505,10 @@ pub struct TextEditorSettings {
|
||||
#[ts(export)]
|
||||
pub struct ProjectSettings {
|
||||
/// The directory to save and load projects from.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[serde(default)]
|
||||
pub directory: std::path::PathBuf,
|
||||
/// The default project name to use when creating a new project.
|
||||
#[serde(default, alias = "defaultProjectName", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "defaultProjectName")]
|
||||
pub default_project_name: ProjectNameTemplate,
|
||||
}
|
||||
|
||||
@ -541,7 +541,7 @@ impl From<String> for ProjectNameTemplate {
|
||||
#[ts(export)]
|
||||
pub struct CommandBarSettings {
|
||||
/// Whether to include settings in the command bar.
|
||||
#[serde(default, alias = "includeSettings", skip_serializing_if = "is_default")]
|
||||
#[serde(default, alias = "includeSettings")]
|
||||
pub include_settings: DefaultTrue,
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,9 @@ use std::{
|
||||
};
|
||||
|
||||
use futures::stream::TryStreamExt;
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
use kcl_lib::{coredump::CoreDump, engine::EngineManager, executor::ExecutorSettings};
|
||||
use kcl_lib::{coredump::CoreDump, engine::EngineManager, executor::ExecutorSettings, lint::checks};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_wasm_bindgen;
|
||||
use tower_lsp::{LspService, Server};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@ -54,14 +55,13 @@ pub async fn execute_wasm(
|
||||
};
|
||||
|
||||
let memory = ctx.run(&program, Some(memory)).await.map_err(String::from)?;
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&memory).map_err(|e| e.to_string())
|
||||
|
||||
serde_wasm_bindgen::to_value(&memory).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
// wasm_bindgen wrapper for execute
|
||||
#[wasm_bindgen]
|
||||
pub async fn kcl_lint(program_str: &str) -> Result<JsValue, String> {
|
||||
pub async fn kcl_lint(program_str: &str) -> Result<JsValue, JsValue> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let program: kcl_lib::ast::types::Program = serde_json::from_str(program_str).map_err(|e| e.to_string())?;
|
||||
@ -70,7 +70,7 @@ pub async fn kcl_lint(program_str: &str) -> Result<JsValue, String> {
|
||||
findings.push(discovered_finding);
|
||||
}
|
||||
|
||||
Ok(JsValue::from_serde(&findings).map_err(|e| e.to_string())?)
|
||||
Ok(serde_wasm_bindgen::to_value(&findings)?)
|
||||
}
|
||||
|
||||
// wasm_bindgen wrapper for creating default planes
|
||||
@ -89,9 +89,7 @@ pub async fn make_default_planes(
|
||||
.await
|
||||
.map_err(String::from)?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&default_planes).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&default_planes).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
// wasm_bindgen wrapper for modifying the grid
|
||||
@ -143,9 +141,7 @@ pub async fn modify_ast_for_sketch_wasm(
|
||||
.await
|
||||
.map_err(String::from)?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&program).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&program).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -161,7 +157,7 @@ pub fn deserialize_files(data: &[u8]) -> Result<JsValue, JsError> {
|
||||
}
|
||||
|
||||
if let Some(kittycad::types::OkWebSocketResponseData::Export { files }) = ws_resp.resp {
|
||||
return Ok(JsValue::from_serde(&files)?);
|
||||
return Ok(serde_wasm_bindgen::to_value(&files)?);
|
||||
}
|
||||
|
||||
Err(JsError::new(&format!("Invalid response type, got: {:?}", ws_resp)))
|
||||
@ -174,7 +170,7 @@ pub fn lexer_wasm(js: &str) -> Result<JsValue, JsError> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let tokens = kcl_lib::token::lexer(js).map_err(JsError::from)?;
|
||||
Ok(JsValue::from_serde(&tokens)?)
|
||||
Ok(serde_wasm_bindgen::to_value(&tokens)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -184,9 +180,7 @@ pub fn parse_wasm(js: &str) -> Result<JsValue, String> {
|
||||
let tokens = kcl_lib::token::lexer(js).map_err(String::from)?;
|
||||
let parser = kcl_lib::parser::Parser::new(tokens);
|
||||
let program = parser.ast().map_err(String::from)?;
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&program).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&program).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
// wasm_bindgen wrapper for recast
|
||||
@ -200,7 +194,7 @@ pub fn recast_wasm(json_str: &str) -> Result<JsValue, JsError> {
|
||||
|
||||
// Use the default options until we integrate into the UI the ability to change them.
|
||||
let result = program.recast(&Default::default(), 0);
|
||||
Ok(JsValue::from_serde(&result)?)
|
||||
Ok(serde_wasm_bindgen::to_value(&result)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -481,9 +475,7 @@ pub fn program_memory_init() -> Result<JsValue, String> {
|
||||
|
||||
let memory = kcl_lib::executor::ProgramMemory::default();
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&memory).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&memory).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Get a coredump.
|
||||
@ -494,9 +486,7 @@ pub async fn coredump(core_dump_manager: kcl_lib::coredump::wasm::CoreDumpManage
|
||||
let core_dumper = kcl_lib::coredump::wasm::CoreDumper::new(core_dump_manager);
|
||||
let dump = core_dumper.dump().await.map_err(|e| e.to_string())?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&dump).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&dump).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Get the default app settings.
|
||||
@ -505,10 +495,9 @@ pub fn default_app_settings() -> Result<JsValue, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let settings = kcl_lib::settings::types::Configuration::default();
|
||||
web_sys::console::log(&js_sys::Array::of1(&JsValue::from_str(&format!("{:?}", settings))));
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&settings).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&settings).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Parse the app settings.
|
||||
@ -519,9 +508,7 @@ pub fn parse_app_settings(toml_str: &str) -> Result<JsValue, String> {
|
||||
let settings = kcl_lib::settings::types::Configuration::backwards_compatible_toml_parse(&toml_str)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&settings).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&settings).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Get the default project settings.
|
||||
@ -531,12 +518,10 @@ pub fn default_project_settings() -> Result<JsValue, String> {
|
||||
|
||||
let settings = kcl_lib::settings::types::project::ProjectConfiguration::default();
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&settings).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&settings).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Parse the project settings.
|
||||
/// Parse (deserialize) the project settings.
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_project_settings(toml_str: &str) -> Result<JsValue, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
@ -544,9 +529,17 @@ pub fn parse_project_settings(toml_str: &str) -> Result<JsValue, String> {
|
||||
let settings = kcl_lib::settings::types::project::ProjectConfiguration::backwards_compatible_toml_parse(&toml_str)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&settings).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&settings).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Serialize the project settings.
|
||||
#[wasm_bindgen]
|
||||
pub fn serialize_project_settings(val: JsValue) -> Result<JsValue, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let config: kcl_lib::settings::types::Configuration = serde_wasm_bindgen::from_value(val).map_err(|e| e.to_string())?;
|
||||
let toml_str = toml::to_string_pretty(&config).map_err(|e| e.to_string())?;
|
||||
serde_wasm_bindgen::to_value(&toml_str).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Parse the project route.
|
||||
@ -560,7 +553,5 @@ pub fn parse_project_route(configuration: &str, route: &str) -> Result<JsValue,
|
||||
let route =
|
||||
kcl_lib::settings::types::file::ProjectRoute::from_route(&configuration, route).map_err(|e| e.to_string())?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
JsValue::from_serde(&route).map_err(|e| e.to_string())
|
||||
serde_wasm_bindgen::to_value(&route).map_err(|e| e.to_string())
|
||||
}
|
||||
|
@ -1,29 +1,42 @@
|
||||
import type { ConfigEnv, UserConfig } from 'vite'
|
||||
import { defineConfig, mergeConfig } from 'vite'
|
||||
import { getBuildConfig, external, pluginHotRestart } from './vite.base.config'
|
||||
import { configDefaults } from 'vitest/config'
|
||||
import viteTsconfigPaths from 'vite-tsconfig-paths'
|
||||
import {
|
||||
getBuildConfig,
|
||||
getBuildDefine,
|
||||
external,
|
||||
pluginHotRestart,
|
||||
} from './vite.base.config'
|
||||
|
||||
// https://vitejs.dev/config
|
||||
export default defineConfig((env) => {
|
||||
const forgeEnv = env as ConfigEnv<'build'>
|
||||
const { forgeConfigSelf } = forgeEnv
|
||||
const define = getBuildDefine(forgeEnv)
|
||||
const { root, mode, forgeConfigSelf } = forgeEnv
|
||||
const config: UserConfig = {
|
||||
root,
|
||||
mode,
|
||||
base: './',
|
||||
build: {
|
||||
lib: {
|
||||
entry: forgeConfigSelf.entry!,
|
||||
fileName: () => '[name].js',
|
||||
formats: ['cjs'],
|
||||
},
|
||||
rollupOptions: {
|
||||
external,
|
||||
// Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`.
|
||||
input: forgeConfigSelf.entry!,
|
||||
output: {
|
||||
format: 'cjs',
|
||||
// It should not be split chunks.
|
||||
inlineDynamicImports: true,
|
||||
entryFileNames: '[name].js',
|
||||
chunkFileNames: '[name].js',
|
||||
assetFileNames: '[name].[ext]',
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
// Load the Node.js entry.
|
||||
mainFields: ['module', 'jsnext:main', 'jsnext'],
|
||||
},
|
||||
plugins: [pluginHotRestart('reload'), viteTsconfigPaths()],
|
||||
plugins: [pluginHotRestart('restart'), viteTsconfigPaths()],
|
||||
worker: {
|
||||
plugins: () => [viteTsconfigPaths()],
|
||||
},
|
||||
define,
|
||||
}
|
||||
|
||||
return mergeConfig(getBuildConfig(forgeEnv), config)
|
||||
|
Reference in New Issue
Block a user