Merge branch 'main' into ok
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { MouseGuard } from 'lib/cameraControls'
|
||||
import { cameraMouseDragGuards, MouseGuard } from 'lib/cameraControls'
|
||||
import {
|
||||
Euler,
|
||||
MathUtils,
|
||||
@ -81,24 +81,7 @@ export class CameraControls {
|
||||
pendingZoom: number | null = null
|
||||
pendingRotation: Vector2 | null = null
|
||||
pendingPan: Vector2 | null = null
|
||||
interactionGuards: MouseGuard = {
|
||||
pan: {
|
||||
description: 'Right click + Shift + drag or middle click + drag',
|
||||
callback: (e) => !!(e.buttons & 4) && !e.ctrlKey,
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel or Right click + Ctrl + drag',
|
||||
dragCallback: (e) => e.button === 2 && e.ctrlKey,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Right click + drag',
|
||||
callback: (e) => {
|
||||
console.log('event', e)
|
||||
return !!(e.buttons & 2)
|
||||
},
|
||||
},
|
||||
}
|
||||
interactionGuards: MouseGuard = cameraMouseDragGuards.KittyCAD
|
||||
isFovAnimationInProgress = false
|
||||
fovBeforeOrtho = 45
|
||||
get isPerspective() {
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import { MouseControlType } from 'wasm-lib/kcl/bindings/MouseControlType'
|
||||
import { platform } from './utils'
|
||||
|
||||
const PLATFORM = platform()
|
||||
const META =
|
||||
PLATFORM === 'macos' ? 'Cmd' : PLATFORM === 'windows' ? 'Win' : 'Super'
|
||||
const ALT = PLATFORM === 'macos' ? 'Option' : 'Alt'
|
||||
|
||||
const noModifiersPressed = (e: React.MouseEvent) =>
|
||||
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
|
||||
@ -73,99 +79,99 @@ export const btnName = (e: React.MouseEvent) => ({
|
||||
export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
||||
KittyCAD: {
|
||||
pan: {
|
||||
description: 'Right click + Shift + drag or middle click + drag',
|
||||
description: 'Shift + Right click drag or middle click drag',
|
||||
callback: (e) =>
|
||||
(btnName(e).middle && noModifiersPressed(e)) ||
|
||||
(btnName(e).right && e.shiftKey),
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel or Right click + Ctrl + drag',
|
||||
description: 'Scroll or Ctrl + Right click drag',
|
||||
dragCallback: (e) => !!(e.buttons & 2) && e.ctrlKey,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Right click + drag',
|
||||
description: 'Right click drag',
|
||||
callback: (e) => btnName(e).right && noModifiersPressed(e),
|
||||
},
|
||||
},
|
||||
OnShape: {
|
||||
pan: {
|
||||
description: 'Right click + Ctrl + drag or middle click + drag',
|
||||
description: 'Ctrl + Right click drag or middle click drag',
|
||||
callback: (e) =>
|
||||
(btnName(e).right && e.ctrlKey) ||
|
||||
(btnName(e).middle && noModifiersPressed(e)),
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel',
|
||||
description: 'Scroll',
|
||||
dragCallback: () => false,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Right click + drag',
|
||||
description: 'Right click drag',
|
||||
callback: (e) => btnName(e).right && noModifiersPressed(e),
|
||||
},
|
||||
},
|
||||
'Trackpad Friendly': {
|
||||
pan: {
|
||||
description: 'Left click + Alt + Shift + drag or middle click + drag',
|
||||
description: `${ALT} + Shift + Left click drag or middle click drag`,
|
||||
callback: (e) =>
|
||||
(btnName(e).left && e.altKey && e.shiftKey && !e.metaKey) ||
|
||||
(btnName(e).middle && noModifiersPressed(e)),
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel or Left click + Alt + OS + drag',
|
||||
description: `Scroll or ${ALT} + ${META} + Left click drag`,
|
||||
dragCallback: (e) => btnName(e).left && e.altKey && e.metaKey,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Left click + Alt + drag',
|
||||
description: `${ALT} + Left click drag`,
|
||||
callback: (e) => btnName(e).left && e.altKey && !e.shiftKey && !e.metaKey,
|
||||
lenientDragStartButton: 0,
|
||||
},
|
||||
},
|
||||
Solidworks: {
|
||||
pan: {
|
||||
description: 'Right click + Ctrl + drag',
|
||||
description: 'Ctrl + Right click drag',
|
||||
callback: (e) => btnName(e).right && e.ctrlKey,
|
||||
lenientDragStartButton: 2,
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel or Middle click + Shift + drag',
|
||||
description: 'Scroll or Shift + Middle click drag',
|
||||
dragCallback: (e) => btnName(e).middle && e.shiftKey,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Middle click + drag',
|
||||
description: 'Middle click drag',
|
||||
callback: (e) => btnName(e).middle && noModifiersPressed(e),
|
||||
},
|
||||
},
|
||||
NX: {
|
||||
pan: {
|
||||
description: 'Middle click + Shift + drag',
|
||||
description: 'Shift + Middle click drag',
|
||||
callback: (e) => btnName(e).middle && e.shiftKey,
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel or Middle click + Ctrl + drag',
|
||||
description: 'Scroll or Ctrl + Middle click drag',
|
||||
dragCallback: (e) => btnName(e).middle && e.ctrlKey,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Middle click + drag',
|
||||
description: 'Middle click drag',
|
||||
callback: (e) => btnName(e).middle && noModifiersPressed(e),
|
||||
},
|
||||
},
|
||||
Creo: {
|
||||
pan: {
|
||||
description: 'Left click + Ctrl + drag',
|
||||
description: 'Ctrl + Left click drag',
|
||||
callback: (e) => btnName(e).left && !btnName(e).right && e.ctrlKey,
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel or Right click + Ctrl + drag',
|
||||
description: 'Scroll or Ctrl + Right click drag',
|
||||
dragCallback: (e) => btnName(e).right && !btnName(e).left && e.ctrlKey,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Middle (or Left + Right) click + Ctrl + drag',
|
||||
description: 'Ctrl + Middle (or Left + Right) click drag',
|
||||
callback: (e) => {
|
||||
const b = btnName(e)
|
||||
return (b.middle || (b.left && b.right)) && e.ctrlKey
|
||||
@ -174,16 +180,16 @@ export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
||||
},
|
||||
AutoCAD: {
|
||||
pan: {
|
||||
description: 'Middle click + drag',
|
||||
description: 'Middle click drag',
|
||||
callback: (e) => btnName(e).middle && noModifiersPressed(e),
|
||||
},
|
||||
zoom: {
|
||||
description: 'Scroll wheel',
|
||||
description: 'Scroll',
|
||||
dragCallback: () => false,
|
||||
scrollCallback: () => true,
|
||||
},
|
||||
rotate: {
|
||||
description: 'Middle click + Shift + drag',
|
||||
description: 'Shift + Middle click drag',
|
||||
callback: (e) => btnName(e).middle && e.shiftKey,
|
||||
},
|
||||
},
|
||||
|
||||
@ -61,6 +61,7 @@ export const TEST_SETTINGS_FILE_KEY = 'playwright-test-settings'
|
||||
|
||||
export const DEFAULT_HOST = 'https://api.zoo.dev'
|
||||
export const SETTINGS_FILE_NAME = 'settings.toml'
|
||||
export const TOKEN_FILE_NAME = 'token.txt'
|
||||
export const PROJECT_SETTINGS_FILE_NAME = 'project.toml'
|
||||
export const COOKIE_NAME = '__Secure-next-auth.session-token'
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
PROJECT_FOLDER,
|
||||
PROJECT_SETTINGS_FILE_NAME,
|
||||
SETTINGS_FILE_NAME,
|
||||
TOKEN_FILE_NAME,
|
||||
} from './constants'
|
||||
import { DeepPartial } from './types'
|
||||
import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration'
|
||||
@ -396,6 +397,23 @@ const getAppSettingsFilePath = async () => {
|
||||
}
|
||||
return window.electron.path.join(fullPath, SETTINGS_FILE_NAME)
|
||||
}
|
||||
const getTokenFilePath = async () => {
|
||||
const isTestEnv = window.electron.process.env.IS_PLAYWRIGHT === 'true'
|
||||
const testSettingsPath = window.electron.process.env.TEST_SETTINGS_FILE_KEY
|
||||
const appConfig = await window.electron.getPath('appData')
|
||||
const fullPath = isTestEnv
|
||||
? testSettingsPath
|
||||
: window.electron.path.join(appConfig, getAppFolderName())
|
||||
try {
|
||||
await window.electron.stat(fullPath)
|
||||
} catch (e) {
|
||||
// File/path doesn't exist
|
||||
if (e === 'ENOENT') {
|
||||
await window.electron.mkdir(fullPath, { recursive: true })
|
||||
}
|
||||
}
|
||||
return window.electron.path.join(fullPath, TOKEN_FILE_NAME)
|
||||
}
|
||||
|
||||
const getProjectSettingsFilePath = async (projectPath: string) => {
|
||||
try {
|
||||
@ -475,6 +493,34 @@ export const writeAppSettingsFile = async (tomlStr: string) => {
|
||||
return window.electron.writeFile(appSettingsFilePath, tomlStr)
|
||||
}
|
||||
|
||||
export const readTokenFile = async () => {
|
||||
let settingsPath = await getTokenFilePath()
|
||||
|
||||
if (window.electron.exists(settingsPath)) {
|
||||
const token: string = await window.electron.readFile(settingsPath)
|
||||
if (!token) return ''
|
||||
|
||||
return token
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export const writeTokenFile = async (token: string) => {
|
||||
const tokenFilePath = await getTokenFilePath()
|
||||
if (err(token)) return Promise.reject(token)
|
||||
return window.electron.writeFile(tokenFilePath, token)
|
||||
}
|
||||
|
||||
let appStateStore: Project | undefined = undefined
|
||||
|
||||
export const getState = async (): Promise<Project | undefined> => {
|
||||
return Promise.resolve(appStateStore)
|
||||
}
|
||||
|
||||
export const setState = async (state: Project | undefined): Promise<void> => {
|
||||
appStateStore = state
|
||||
}
|
||||
|
||||
export const getUser = async (
|
||||
token: string,
|
||||
hostname: string
|
||||
|
||||
@ -8,7 +8,11 @@ import {
|
||||
VITE_KC_SKIP_AUTH,
|
||||
DEV,
|
||||
} from 'env'
|
||||
import { getUser as getUserDesktop } from 'lib/desktop'
|
||||
import {
|
||||
getUser as getUserDesktop,
|
||||
readTokenFile,
|
||||
writeTokenFile,
|
||||
} from 'lib/desktop'
|
||||
import { COOKIE_NAME } from 'lib/constants'
|
||||
|
||||
const SKIP_AUTH = VITE_KC_SKIP_AUTH === 'true' && DEV
|
||||
@ -53,6 +57,7 @@ const persistedToken =
|
||||
|
||||
export const authMachine = createMachine<UserContext, Events>(
|
||||
{
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QEECuAXAFgOgMabFwGsBJAMwBkB7KGCEgOwGIIqGxsBLBgNyqI75CRALQAbGnRHcA2gAYAuolAAHKrE7pObZSAAeiAIwBmAEzYA7ABYAbAFZTcgBzGbN44adWANCACeiKbGdthypk4AnBFyVs6uQXYAvom+aFh4BMTk1LSQjExgAE6FVIXYKmIAhuhkpQC2GcLikpDSDPJKSCBqGlo6XQYIrk7YETYWctYRxmMWFk6+AUPj2I5OdjZyrnZOFmbJqRg4Ern0zDkABFQYHbo9mtoMuoOGFhHYxlZOhvbOsUGGRaIL4WbBONzWQxWYwWOx2H4HEBpY4tCAAeQwTEuskUd3UD36oEGIlMNlCuzk8Js0TcVisgP8iG2lmcGysb0mW3ByRSIAYVAgcF0yLxvUez0QIms5ImVJpNjpDKWxmw9PGdLh4Te00+iORjSylFRjFFBKeA0QThGQWcexMwWhniBCGiqrepisUVMdlszgieqO2BOdBNXXufXNRKMHtGVuphlJkXs4Wdriso2CCasdgipOidID6WDkAx6FNEYlCAT5jmcjrckMdj2b3GzpsjbBMVMWezDbGPMSQA */
|
||||
id: 'Auth',
|
||||
initial: 'checkIfLoggedIn',
|
||||
states: {
|
||||
@ -85,6 +90,9 @@ export const authMachine = createMachine<UserContext, Events>(
|
||||
on: {
|
||||
'Log out': {
|
||||
target: 'loggedOut',
|
||||
actions: () => {
|
||||
if (isDesktop()) writeTokenFile('')
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -96,7 +104,6 @@ export const authMachine = createMachine<UserContext, Events>(
|
||||
actions: assign({
|
||||
token: (_, event) => {
|
||||
const token = event.token || ''
|
||||
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
||||
return token
|
||||
},
|
||||
}),
|
||||
@ -120,11 +127,7 @@ export const authMachine = createMachine<UserContext, Events>(
|
||||
)
|
||||
|
||||
async function getUser(context: UserContext) {
|
||||
const token = VITE_KC_DEV_TOKEN
|
||||
? VITE_KC_DEV_TOKEN
|
||||
: context.token && context.token !== ''
|
||||
? context.token
|
||||
: getCookie(COOKIE_NAME) || localStorage?.getItem(TOKEN_PERSIST_KEY)
|
||||
const token = await getAndSyncStoredToken(context)
|
||||
const url = withBaseURL('/user')
|
||||
const headers: { [key: string]: string } = {
|
||||
'Content-Type': 'application/json',
|
||||
@ -189,3 +192,26 @@ function getCookie(cname: string): string | null {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function getAndSyncStoredToken(context: UserContext): Promise<string> {
|
||||
// dev mode
|
||||
if (VITE_KC_DEV_TOKEN) return VITE_KC_DEV_TOKEN
|
||||
|
||||
const token =
|
||||
context.token && context.token !== ''
|
||||
? context.token
|
||||
: getCookie(COOKIE_NAME) || localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
|
||||
if (token) {
|
||||
// has just logged in, update storage
|
||||
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
||||
isDesktop() && writeTokenFile(token)
|
||||
return token
|
||||
}
|
||||
if (!isDesktop()) return ''
|
||||
const fileToken = isDesktop() ? await readTokenFile() : ''
|
||||
// prefer other above, but file will ensure login persists after app updates
|
||||
if (!fileToken) return ''
|
||||
// has token in file, update localStorage
|
||||
localStorage.setItem(TOKEN_PERSIST_KEY, fileToken)
|
||||
return fileToken
|
||||
}
|
||||
|
||||
17
src/main.ts
17
src/main.ts
@ -2,7 +2,7 @@
|
||||
// template that ElectronJS provides.
|
||||
|
||||
import dotenv from 'dotenv'
|
||||
import { app, BrowserWindow, protocol, ipcMain, dialog, shell } from 'electron'
|
||||
import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron'
|
||||
import path from 'path'
|
||||
import { Issuer } from 'openid-client'
|
||||
import { Bonjour, Service } from 'bonjour-service'
|
||||
@ -42,21 +42,6 @@ if (process.defaultApp) {
|
||||
app.setAsDefaultProtocolClient(ZOO_STUDIO_PROTOCOL)
|
||||
}
|
||||
|
||||
// Register custom schemes with privileges.
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme: ZOO_STUDIO_PROTOCOL,
|
||||
privileges: {
|
||||
standard: true,
|
||||
secure: true,
|
||||
supportFetchAPI: true,
|
||||
corsEnabled: true,
|
||||
allowServiceWorkers: true,
|
||||
codeCache: true,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
// Global app listeners
|
||||
// Must be done before ready event.
|
||||
registerStartupListeners()
|
||||
|
||||
Reference in New Issue
Block a user