Add (broken) event logic and command triggering logic
This commit is contained in:
@ -22,9 +22,11 @@ import Gizmo from 'components/Gizmo'
|
|||||||
import { CoreDumpManager } from 'lib/coredump'
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
import { UnitsMenu } from 'components/UnitsMenu'
|
import { UnitsMenu } from 'components/UnitsMenu'
|
||||||
import { CameraProjectionToggle } from 'components/CameraProjectionToggle'
|
import { CameraProjectionToggle } from 'components/CameraProjectionToggle'
|
||||||
|
import { useCreateFileLinkQuery } from 'hooks/useCreateFileLinkQueryWatcher'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const { project, file } = useLoaderData() as IndexLoaderData
|
const { project, file } = useLoaderData() as IndexLoaderData
|
||||||
|
useCreateFileLinkQuery()
|
||||||
useRefreshSettings(PATHS.FILE + 'SETTINGS')
|
useRefreshSettings(PATHS.FILE + 'SETTINGS')
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const filePath = useAbsoluteFilePath()
|
const filePath = useAbsoluteFilePath()
|
||||||
|
78
src/hooks/useCreateFileLinkQueryWatcher.ts
Normal file
78
src/hooks/useCreateFileLinkQueryWatcher.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { base64ToString } from 'lib/base64'
|
||||||
|
import { CREATE_FILE_URL_PARAM, DEFAULT_FILE_NAME } from 'lib/constants'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { useCommandsContext } from './useCommandsContext'
|
||||||
|
import { useSettingsAuthContext } from './useSettingsAuthContext'
|
||||||
|
import { isDesktop } from 'lib/isDesktop'
|
||||||
|
import { FileLinkParams } from 'lib/createFileLink'
|
||||||
|
import { ProjectsCommandSchema } from 'lib/commandBarConfigs/projectsCommandConfig'
|
||||||
|
import { baseUnitsUnion } from 'lib/settings/settingsTypes'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* companion to createFileLink. This hook runs an effect on mount that
|
||||||
|
* checks the URL for the CREATE_FILE_URL_PARAM and triggers the "Create file"
|
||||||
|
* command if it is present, loading the command's default values from the other
|
||||||
|
* URL parameters.
|
||||||
|
*/
|
||||||
|
export function useCreateFileLinkQuery() {
|
||||||
|
const location = useLocation()
|
||||||
|
const { commandBarSend } = useCommandsContext()
|
||||||
|
const { settings } = useSettingsAuthContext()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const urlParams = new URLSearchParams(location.search)
|
||||||
|
const createFileParam = urlParams.has(CREATE_FILE_URL_PARAM)
|
||||||
|
|
||||||
|
console.log('checking for createFileParam', {
|
||||||
|
createFileParam,
|
||||||
|
urlParams: [...urlParams.entries()],
|
||||||
|
location,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (createFileParam) {
|
||||||
|
const params: FileLinkParams = {
|
||||||
|
code: base64ToString(decodeURIComponent(urlParams.get('code') ?? '')),
|
||||||
|
|
||||||
|
name: urlParams.get('name') ?? DEFAULT_FILE_NAME,
|
||||||
|
|
||||||
|
units:
|
||||||
|
(baseUnitsUnion.find((unit) => urlParams.get('units') === unit) ||
|
||||||
|
settings.context.modeling.defaultUnit.default) ??
|
||||||
|
settings.context.modeling.defaultUnit.current,
|
||||||
|
}
|
||||||
|
console.log('createFileParam', params)
|
||||||
|
|
||||||
|
// For initializing the command arguments, we actually want `method` to be undefined
|
||||||
|
// so that we don't skip it in the command palette.
|
||||||
|
type CreateFileSchemaMethodOptional = Omit<
|
||||||
|
ProjectsCommandSchema['Import file from URL'],
|
||||||
|
'method'
|
||||||
|
> & {
|
||||||
|
method?: 'newProject' | 'existingProject'
|
||||||
|
}
|
||||||
|
|
||||||
|
const argDefaultValues: CreateFileSchemaMethodOptional = {
|
||||||
|
name: params.name
|
||||||
|
? isDesktop()
|
||||||
|
? params.name.replace('.kcl', '')
|
||||||
|
: params.name
|
||||||
|
: isDesktop()
|
||||||
|
? settings.context.projects.defaultProjectName.current
|
||||||
|
: DEFAULT_FILE_NAME,
|
||||||
|
code: params.code || '',
|
||||||
|
units: params.units,
|
||||||
|
method: isDesktop() ? undefined : 'existingProject',
|
||||||
|
}
|
||||||
|
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: {
|
||||||
|
groupId: 'projects',
|
||||||
|
name: 'Import file from URL',
|
||||||
|
argDefaultValues,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [location.search])
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
|
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
|
||||||
import { CommandBarOverwriteWarning } from 'components/CommandBarOverwriteWarning'
|
import { CommandBarOverwriteWarning } from 'components/CommandBarOverwriteWarning'
|
||||||
import { StateMachineCommandSetConfig } from 'lib/commandTypes'
|
import { StateMachineCommandSetConfig } from 'lib/commandTypes'
|
||||||
|
import { baseUnitLabels, baseUnitsUnion } from 'lib/settings/settingsTypes'
|
||||||
import { projectsMachine } from 'machines/projectsMachine'
|
import { projectsMachine } from 'machines/projectsMachine'
|
||||||
|
|
||||||
export type ProjectsCommandSchema = {
|
export type ProjectsCommandSchema = {
|
||||||
@ -17,6 +19,13 @@ export type ProjectsCommandSchema = {
|
|||||||
oldName: string
|
oldName: string
|
||||||
newName: string
|
newName: string
|
||||||
}
|
}
|
||||||
|
'Import file from URL': {
|
||||||
|
name: string
|
||||||
|
code?: string
|
||||||
|
units: UnitLength_type
|
||||||
|
method: 'newProject' | 'existingProject'
|
||||||
|
projectName?: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const projectsCommandBarConfig: StateMachineCommandSetConfig<
|
export const projectsCommandBarConfig: StateMachineCommandSetConfig<
|
||||||
@ -94,4 +103,55 @@ export const projectsCommandBarConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'Import file from URL': {
|
||||||
|
icon: 'file',
|
||||||
|
description: 'Create a file',
|
||||||
|
needsReview: true,
|
||||||
|
args: {
|
||||||
|
method: {
|
||||||
|
inputType: 'options',
|
||||||
|
required: true,
|
||||||
|
skip: true,
|
||||||
|
options: [
|
||||||
|
{ name: 'New Project', value: 'newProject' },
|
||||||
|
{ name: 'Existing Project', value: 'existingProject' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// TODO: We can't get the currently-opened project to auto-populate here because
|
||||||
|
// it's not available on projectMachine, but lower in fileMachine. Unify these.
|
||||||
|
projectName: {
|
||||||
|
inputType: 'options',
|
||||||
|
required: (commandsContext) => commandsContext.argumentsToSubmit.method === 'existingProject',
|
||||||
|
skip: true,
|
||||||
|
options: [],
|
||||||
|
optionsFromContext: (context) =>
|
||||||
|
context.projects.map((p) => ({
|
||||||
|
name: p.name!,
|
||||||
|
value: p.name!,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
inputType: 'string',
|
||||||
|
required: true,
|
||||||
|
skip: true,
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
inputType: 'text',
|
||||||
|
required: false,
|
||||||
|
skip: true,
|
||||||
|
},
|
||||||
|
units: {
|
||||||
|
inputType: 'options',
|
||||||
|
required: false,
|
||||||
|
skip: true,
|
||||||
|
options: baseUnitsUnion.map((unit) => ({
|
||||||
|
name: baseUnitLabels[unit],
|
||||||
|
value: unit,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reviewMessage(commandBarContext) {
|
||||||
|
return `Will add the contents from URL to a new ${commandBarContext.argumentsToSubmit.method === 'newProject' ? 'project with file main.kcl' : `file within the project "${commandBarContext.argumentsToSubmit.projectName}"`} named "${commandBarContext.argumentsToSubmit.name}", and set default units to "${commandBarContext.argumentsToSubmit.units}".`
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,12 @@ import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
|
|||||||
import { CREATE_FILE_URL_PARAM, PROD_APP_URL } from './constants'
|
import { CREATE_FILE_URL_PARAM, PROD_APP_URL } from './constants'
|
||||||
import { stringToBase64 } from './base64'
|
import { stringToBase64 } from './base64'
|
||||||
|
|
||||||
|
export interface FileLinkParams {
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
units: UnitLength_type
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a file's code, name, and units, creates shareable link
|
* Given a file's code, name, and units, creates shareable link
|
||||||
* TODO: make the app respect this link
|
* TODO: make the app respect this link
|
||||||
@ -10,11 +16,7 @@ export function createFileLink({
|
|||||||
code,
|
code,
|
||||||
name,
|
name,
|
||||||
units,
|
units,
|
||||||
}: {
|
}: FileLinkParams) {
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
units: UnitLength_type
|
|
||||||
}) {
|
|
||||||
return new URL(
|
return new URL(
|
||||||
`/?${CREATE_FILE_URL_PARAM}&name=${encodeURIComponent(
|
`/?${CREATE_FILE_URL_PARAM}&name=${encodeURIComponent(
|
||||||
name
|
name
|
||||||
|
@ -25,6 +25,7 @@ export const projectsMachine = setup({
|
|||||||
type: 'Delete project'
|
type: 'Delete project'
|
||||||
data: ProjectsCommandSchema['Delete project']
|
data: ProjectsCommandSchema['Delete project']
|
||||||
}
|
}
|
||||||
|
| { type: 'Import file from URL'; data: ProjectsCommandSchema['Import file from URL'] }
|
||||||
| { type: 'navigate'; data: { name: string } }
|
| { type: 'navigate'; data: { name: string } }
|
||||||
| {
|
| {
|
||||||
type: 'xstate.done.actor.read-projects'
|
type: 'xstate.done.actor.read-projects'
|
||||||
@ -93,9 +94,10 @@ export const projectsMachine = setup({
|
|||||||
},
|
},
|
||||||
guards: {
|
guards: {
|
||||||
'Has at least 1 project': () => false,
|
'Has at least 1 project': () => false,
|
||||||
|
'New project method is used': () => false,
|
||||||
},
|
},
|
||||||
}).createMachine({
|
}).createMachine({
|
||||||
/** @xstate-layout N4IgpgJg5mDOIC5QAkD2BbMACdBDAxgBYCWAdmAMS6yzFSkDaADALqKgAOqtALsaqXYgAHogAsAJgA0IAJ6IAjBIkA2AHQAOCUw0qNkjQE4xYjQF8zMtJhwES5NcmpZSqLBwBOqAFZh8PWAoAJTBcCHcvX39YZjYkEC5efkF40QQFFQBmAHY1Qwz9QwBWU0NMrRl5BGyxBTUVJlVM01rtBXNLEGtsPCIyMEdnVwifPwCKAGEPUJ5sT1H-WKFE4j4BITSMzMzNIsyJDSZMhSYmFWzKxAkTNSYxIuU9zOKT7IsrDB67fsHYEajxiEwv8xjFWMtuKtkhsrpJboZsioincFMdTIjLggVGJ1GImMVMg0JISjEV3l1PrY+g4nH95gDAiFSLgbPSxkt4is1ilQGlrhJ4YjkbU0RoMXJEIYkWoikV8hJinjdOdyd0qfYBrSQdFJtNcLNtTwOZxIdyYQh+YKkSjReKqqYBQoEQpsgiSi9MqrKb0Nb9DYEACJgAA2YANbMW4M5puhqVhAvxQptCnRKkxCleuw0Gm2+2aRVRXpsPp+Woj4wA8hwwKRDcaEjH1nGLXDE9aRSmxWmJVipWocmdsbL8kxC501SWHFMZmQoIaKBABAMyAA3VAAawG+D1swAtOX61zY7zENlEWoMkoatcdPoipjCWIZRIirozsPiYYi19qQNp-rZ3nMAPC8Dw1A4YN9QAM1QDx0DUbcZjAfdInZKMTSSJsT2qc9Lwka8lTvTFTB2WUMiyQwc3yPRv3VH4mRZQDywXJc1FXDcBmmZlMBQhYjXQhtMJ5ERT1wlQr0kQj7kxKiZTxM5s2zbQEVoycBgY9AmNQ-wKGA0DwMgngYLgtQuJZZCDwEo8sJEnD1Dwgjb2kntig0GUkWVfZDEMfFVO+Bwg1DPhSDnZjFwcdjNzUCAQzDCztP4uIMKhGy0jPezxPwySnPvHsTjlPIhyOHRsnwlM-N-NRArDLS+N0kDYIM6DYPgmKgvivjD0bYS+VbBF21RTs7UUUcimfRpXyYRF8LFCrfSBCBaoZFiItINcor1CBeIZLqhPNdKL0yxzs2cqoNDqdpSo0EoSoLOb6NCRaQv9FblzWjjTMe7bQQYBQksElKesUMRjFubRMllCHsm2a5MVldRDBfFpmj0IpxPuhwFqW0F6v0iDmpMzbvuiXbAfNFNQcaI5IaKaH9jETFsUMNRVDxOU5TxBULE6VwYvgeIJ38sAIT25td27KpdzG7yZeho5slHVmMc1IY3HLfnkrNZt2hOW5smRCQM2uhQHkZ6VtkRBFnmu0qFGVv11ZFsnm0kdN8QFJVjlUPZ9co+3-2C0KEqdrXsJMJ8ryc86iUyYiCvxFNzldb3jHtjTsf8EPj1ssQchZlR8jR5EmDRrIGZcuF7maF1aZtslx29IWqtiwPDSz1LxDxepnlOfYDghp03eyOpngzXuYdHNPHozgJ26B9IXR2cTvP0BVkSRXKqgLtyq8OfQcXOwlubMIA */
|
/** @xstate-layout N4IgpgJg5mDOIC5QAkD2BbMACdBDAxgBYCWAdmAMS6yzFSkDaADALqKgAOqtALsaqXYgAHogAsAJgA0IAJ6IAjBIkA2AHQAOCUw0qNkjQE4xYjQF8zMtJhwES5NcmpZSqLBwBOqAFZh8PWAoAJTBcCHcvX39YZjYkEC5efkF40QQFFQBmAHY1Qwz9QwBWU0NMrRl5BGyxBTUVJlVM01rtBXNLEGtsPCIyMEdnVwifPwCKAGEPUJ5sT1H-WKFE4j4BITSMzMzNIsyJDSZMhSYmFWzKxAkTNSYxIuU9zOKT7IsrDB67fsHYEajxiEwv8xjFWMtuKtkhsrpJboZsioincFMdTIjLggVGJ1GImMVMg0JISjEV3l1PrY+g4nH95gDAiFSLgbPSxkt4is1ilQGlrhJ4YjkbU0RoMXJEIYkWoikV8hJinjdOdyd0qfYBrSQdFJtNcLNtTwOZxIdyYQh+YKkSjReKqqYBQoEQpsgiSi9MqrKb0Nb9DYEACJgAA2YANbMW4M5puhqVhAvxQptCnRKkxCleuw0Gm2+2aRVRXpsPp+Woj4wA8hwwKRDcaEjH1nGLXDE9aRSmxWmJVipWocmdsbL8kxC501SWHFMZmQoIaKBABAMyAA3VAAawG+D1swAtOX61zY7zENlEWoMkoatcdPoipjCWIZRIirozsPiYYi19qQNp-rZ3nMAPC8Dw1A4YN9QAM1QDx0DUbcZjAfdInZKMTSSJsT2qc9Lwka8lTvTFTB2WUMiyQwc3yPRv3VH4mRZQDywXJc1FXDcBmmZlMBQhYjXQhtMJ5ERT1wlQr0kQj7kxKiZTxM5s2zbQEVoycBgY9AmNQ-wKGA0DwMgngYLgtQuJZZCDwEo8sJEnD1Dwgjb2kntig0GUkWVfZDEMfFVO+Bwg1DPhSDnZjFwcdjNzUCAQzDCztP4uIMKhGy0jPezxPwySnPvHsTjlPIhyOHRsnwlM-N-NRArDLS+N0kDYIM6DYPgmKgvivjD0bYS+VbBF21RTs7UUUcimfRpXyYRF8LFCrfSBCBaoZFiItINcor1CBeIZLqhPNdKL0yxzs2cqoNDqdpSo0EoSoLOb6NCRaQv9FblzWjjTMe7bQQYBQksElKesUMRjFubRMllCHsm2a5MVldRDBfFpmj0IpxPuhwFqW0F6v0iDmpMzbvuiXbAfNFNQcaI5IaKaH9jETFsUMNRVDxOU5TxBUMcof8DSg4hQ1Js1mwyfCL2JYlakkA4GZcp16jEaGzylfMsm53UkKwfnBb+iE9pFlQDjUM8HiYV99At2WqhOO5+zPLQqbRyiyXJVwYvgeIJ38sA9bJ5td27KpdzG7zQ70VFslOBVim5v1hnLD3kuF7D2hOW5smRCQM2uhQHkZ6VtkRBFnmu0qFFjssEsTgHk9syR03xAUlWOVQ9gzyjY957H-F92u0hMJ8ryc86iUyYiCvxFNzldVvjFjjTu54XvjzrnIWZUfI0eRM2VCyK3JThe5mhdWnS5dj5i29qrYuC0KEuX1LxDxepnlOfYDghp0G+yOpngzN+Yajnno9Re1drJA3SC6HY4lvL6AVMiJEuUqgbzckfQ4+gcTnUJBYCwQA */
|
||||||
id: 'Home machine',
|
id: 'Home machine',
|
||||||
|
|
||||||
initial: 'Reading projects',
|
initial: 'Reading projects',
|
||||||
@ -111,6 +113,14 @@ export const projectsMachine = setup({
|
|||||||
})),
|
})),
|
||||||
target: '.Reading projects',
|
target: '.Reading projects',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"Import file from URL": [{
|
||||||
|
target: ".Creating project",
|
||||||
|
guard: "New project method is used"
|
||||||
|
}, {
|
||||||
|
target: ".Reading projects",
|
||||||
|
actions: "navigateToProject"
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
states: {
|
states: {
|
||||||
'Has no projects': {
|
'Has no projects': {
|
||||||
@ -155,7 +165,7 @@ export const projectsMachine = setup({
|
|||||||
id: 'create-project',
|
id: 'create-project',
|
||||||
src: 'createProject',
|
src: 'createProject',
|
||||||
input: ({ event, context }) => {
|
input: ({ event, context }) => {
|
||||||
if (event.type !== 'Create project') {
|
if (event.type !== 'Create project' && event.type !== 'Import file from URL') {
|
||||||
return {
|
return {
|
||||||
name: '',
|
name: '',
|
||||||
projects: context.projects,
|
projects: context.projects,
|
||||||
@ -270,7 +280,7 @@ export const projectsMachine = setup({
|
|||||||
actions: ['toastError'],
|
actions: ['toastError'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -23,10 +23,12 @@ import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
|
|||||||
import { useProjectsLoader } from 'hooks/useProjectsLoader'
|
import { useProjectsLoader } from 'hooks/useProjectsLoader'
|
||||||
import { useProjectsContext } from 'hooks/useProjectsContext'
|
import { useProjectsContext } from 'hooks/useProjectsContext'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
|
import { useCreateFileLinkQuery } from 'hooks/useCreateFileLinkQueryWatcher'
|
||||||
|
|
||||||
// This route only opens in the desktop context for now,
|
// This route only opens in the desktop context for now,
|
||||||
// as defined in Router.tsx, so we can use the desktop APIs and types.
|
// as defined in Router.tsx, so we can use the desktop APIs and types.
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
|
useCreateFileLinkQuery()
|
||||||
const { state, send } = useProjectsContext()
|
const { state, send } = useProjectsContext()
|
||||||
const { commandBarSend } = useCommandsContext()
|
const { commandBarSend } = useCommandsContext()
|
||||||
const [projectsLoaderTrigger, setProjectsLoaderTrigger] = useState(0)
|
const [projectsLoaderTrigger, setProjectsLoaderTrigger] = useState(0)
|
||||||
@ -203,6 +205,14 @@ const Home = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<Link
|
||||||
|
to="/?create-file&name=Untitled-1.kcl&units=mm&code=c2tldGNoMDAxID0gc3RhcnRTa2V0Y2hPbignWFknKQogIHw%2BIGNpcmNsZSh7CiAgICAgICBjZW50ZXI6IFstMTUuNTEsIDE1LjMzXSwKICAgICAgIHJhZGl1czogMTIuMTkKICAgICB9LCAlKQpleHRydXNpb25EaXN0YW5jZSA9IDEyCmV4dHJ1ZGUwMDEgPSBleHRydWRlKGV4dHJ1c2lvbkRpc3RhbmNlLCBza2V0Y2gwMDEpCnNrZXRjaDAwMiA9IHN0YXJ0U2tldGNoT24oZXh0cnVkZTAwMSwgJ0VORCcpCiAgfD4gY2lyY2xlKHsKICAgICAgIGNlbnRlcjogWy0xOC42OSwgMjAuMjNdLAogICAgICAgcmFkaXVzOiA0LjgzCiAgICAgfSwgJSkKZXh0cnVkZTAwMiA9IGV4dHJ1ZGUoLWV4dHJ1c2lvbkRpc3RhbmNlLCBza2V0Y2gwMDIpCgo%3D"
|
||||||
|
className="text-primary underline underline-offset-2"
|
||||||
|
>
|
||||||
|
Go to a test create-file link
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
data-testid="home-section"
|
data-testid="home-section"
|
||||||
|
Reference in New Issue
Block a user