Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to create and open URLs to create files #4166

Open
wants to merge 70 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
401dcf8
Rename `homeMachine` and accessories to `projectsMachine`
franknoirot Oct 4, 2024
5822321
Separate out `/home` route from `projectsMachine`
franknoirot Oct 4, 2024
5bd8904
Add logic to navigate out from deleted or renamed project
franknoirot Oct 4, 2024
049e487
Show a warning in the command palette for deleting a project
franknoirot Oct 4, 2024
d7fe827
Make it navigate when you create a project
franknoirot Oct 4, 2024
4f06524
Update "New project" button to use command bar flow
franknoirot Oct 4, 2024
5d8f3f9
More explicit warning message text
franknoirot Oct 4, 2024
f496d94
Merge branch 'main' into franknoirot/4088/decouple-homeMachine
franknoirot Oct 7, 2024
fe6d1f8
Make projects watching code not run in web
franknoirot Oct 7, 2024
bfccb79
Tests first version: nested loops
franknoirot Oct 7, 2024
238163d
Tests second version: flattened
franknoirot Oct 7, 2024
3fc707a
Remove console logs
franknoirot Oct 7, 2024
f163870
Fix tsc
franknoirot Oct 7, 2024
8ab24ce
@jtran feedback, use the type guard util
franknoirot Oct 7, 2024
d1be6d7
A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)
github-actions[bot] Oct 7, 2024
7545b61
A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)
github-actions[bot] Oct 7, 2024
3d2e487
A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)
github-actions[bot] Oct 7, 2024
f0136a5
Fix tests that relied on one-click, no-navigation project creation
franknoirot Oct 8, 2024
75e3f84
Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"
franknoirot Oct 8, 2024
e22a9ed
Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"
franknoirot Oct 8, 2024
372f2ee
Add a mask to the state indicator to client-side scale test
franknoirot Oct 8, 2024
1f515b7
A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)
github-actions[bot] Oct 8, 2024
9378d98
A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)
github-actions[bot] Oct 8, 2024
80e32b3
Merge branch 'main' into franknoirot/4088/decouple-homeMachine
franknoirot Oct 8, 2024
48380be
A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)
github-actions[bot] Oct 8, 2024
f4ecd16
Merge branch 'main' into franknoirot/4088/decouple-homeMachine
franknoirot Oct 8, 2024
14eeafb
Fix lint
franknoirot Oct 8, 2024
403cee5
Fix tsc
franknoirot Oct 8, 2024
30a24c8
Add menu item to share link to file
franknoirot Oct 8, 2024
8141103
Forward query params while redirecting to /home or /file
franknoirot Oct 8, 2024
5dc983a
Add (broken) event logic and command triggering logic
franknoirot Oct 8, 2024
3a9e0c7
Fix a couple stray tests that still relied on the old way of creating…
franknoirot Oct 8, 2024
524fcb0
Merge branch 'franknoirot/4088/decouple-homeMachine' into franknoirot…
franknoirot Oct 8, 2024
02b249b
Merge branch 'main' into franknoirot/update-download-progress
franknoirot Oct 10, 2024
746ebf8
De-flake another text that could be thrown off by toast-based selectors
franknoirot Oct 10, 2024
15bedd5
FMT
franknoirot Oct 10, 2024
1ce3d8c
Dumb test error because I was rushing
franknoirot Oct 10, 2024
c882e34
Merge branch 'franknoirot/4088/decouple-homeMachine' into franknoirot…
franknoirot Oct 10, 2024
a2330a0
A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)
github-actions[bot] Oct 10, 2024
698ce67
Merge branch 'main' into franknoirot/4088/decouple-homeMachine
franknoirot Oct 10, 2024
4748c2d
Ahhh more flaky toasts, they're everywhere!
franknoirot Oct 10, 2024
36d49b1
A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)
github-actions[bot] Oct 10, 2024
96b0624
Side quest: Only register commands once, power their disabled status …
franknoirot Oct 10, 2024
d58a147
Get query-triggered command working in browser too
franknoirot Oct 10, 2024
1e5954e
Merge branch 'main' into franknoirot/4088/decouple-homeMachine
franknoirot Oct 11, 2024
b84d595
Merge branch 'main' into franknoirot/4088/decouple-homeMachine
franknoirot Oct 15, 2024
bb67a9e
Merge branch 'franknoirot/4088/decouple-homeMachine' into franknoirot…
franknoirot Oct 15, 2024
cbb8df5
A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)
github-actions[bot] Oct 15, 2024
2048c26
Tests always run on localhost, don't expect the prod origin
franknoirot Oct 16, 2024
2aa4a01
Merge branch 'franknoirot/4088/decouple-homeMachine' into franknoirot…
franknoirot Oct 16, 2024
713886b
rerun CI
franknoirot Oct 17, 2024
570d159
wip
lf94 Oct 17, 2024
2193d56
wip
lf94 Oct 17, 2024
c29be6e
Everything's pretty much done but url.zoo.dev has been broken and we …
lf94 Oct 19, 2024
28eb99f
Merge branch 'main' into franknoirot/4088/create-file-url
franknoirot Jan 8, 2025
5cbd11c
Add useCreateFileLinkQuery on Home page
franknoirot Jan 8, 2025
ca09224
Get primary user flow working on desktop
franknoirot Jan 8, 2025
670faac
Rework to open browser app first, then send along to the desktop app …
franknoirot Jan 9, 2025
f05acf9
Styling updates to OpenInDesktopAppHandler
franknoirot Jan 10, 2025
a2ff0ae
Clean up unecessary file
franknoirot Jan 10, 2025
91f0cfe
Merge branch 'main' into franknoirot/4088/create-file-url
franknoirot Jan 10, 2025
ebc6b64
Separate creating `createFileUrl` and shortlink so it is unit testable
franknoirot Jan 10, 2025
e417e60
Add E2E test for importing file from URL
franknoirot Jan 10, 2025
83e72da
Add a couple component tests for OpenInDesktopAppHandler
franknoirot Jan 10, 2025
af702ae
Fix the "existing project" user flow
franknoirot Jan 10, 2025
8b8a2bc
Add E2E test for "add to existing project" user flow
franknoirot Jan 10, 2025
c06b2b4
Merge branch 'main' into franknoirot/4088/create-file-url
franknoirot Jan 10, 2025
d64270d
Undo mistaken or unecessary changes
franknoirot Jan 10, 2025
679b65f
Lints, fmt, tsc
franknoirot Jan 10, 2025
82aefec
Fix unit test
franknoirot Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=5000
# ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!
#VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local"
# Add a prod token if you want to use the share URL feature in local dev
#VITE_KC_PROD_TOKEN="your token from prod.zoo.dev should go in .env.development.local"
133 changes: 131 additions & 2 deletions e2e/playwright/command-bar-tests.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { test, expect } from './zoo-test'

import { getUtils } from './test-utils'
import * as fsp from 'fs/promises'
import { executorInputPath, getUtils } from './test-utils'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import path from 'path'

test.describe('Command bar tests', () => {
test('Extrude from command bar selects extrude line after', async ({
Expand Down Expand Up @@ -345,4 +346,132 @@ test.describe('Command bar tests', () => {
await arcToolCommand.click()
await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
})

test(`Reacts to query param to open "import from URL" command`, async ({
page,
cmdBar,
editor,
homePage,
}) => {
await test.step(`Prepare and navigate to home page with query params`, async () => {
const targetURL = `?create-file&name=test&units=mm&code=ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D&askToOpenInDesktop`
await homePage.expectState({
projectCards: [],
sortBy: 'last-modified-desc',
})
await page.goto(page.url() + targetURL)
expect(page.url()).toContain(targetURL)
})

await test.step(`Submit the command`, async () => {
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Import file from URL',
currentArgKey: 'method',
currentArgValue: '',
headerArguments: {
Method: '',
Name: 'test',
Code: '1 line',
},
highlightedHeaderArg: 'method',
})
await cmdBar.selectOption({ name: 'New Project' }).click()
await cmdBar.expectState({
stage: 'review',
commandName: 'Import file from URL',
headerArguments: {
Method: 'New project',
Name: 'test',
Code: '1 line',
},
})
await cmdBar.progressCmdBar()
})

await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
await editor.expectEditor.toContain('extrusionDistance = 12')
})
})

test(`"import from URL" can add to existing project`, async ({
page,
cmdBar,
editor,
homePage,
toolbar,
context,
}) => {
await context.folderSetupFn(async (dir) => {
const testProjectDir = path.join(dir, 'testProjectDir')
await Promise.all([fsp.mkdir(testProjectDir, { recursive: true })])
await Promise.all([
fsp.copyFile(
executorInputPath('cylinder.kcl'),
path.join(testProjectDir, 'main.kcl')
),
])
})
await test.step(`Prepare and navigate to home page with query params`, async () => {
const targetURL = `?create-file&name=test&units=mm&code=ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D&askToOpenInDesktop`
await homePage.expectState({
projectCards: [
{
fileCount: 1,
title: 'testProjectDir',
},
],
sortBy: 'last-modified-desc',
})
await page.goto(page.url() + targetURL)
expect(page.url()).toContain(targetURL)
})

await test.step(`Submit the command`, async () => {
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Import file from URL',
currentArgKey: 'method',
currentArgValue: '',
headerArguments: {
Method: '',
Name: 'test',
Code: '1 line',
},
highlightedHeaderArg: 'method',
})
await cmdBar.selectOption({ name: 'Existing Project' }).click()
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Import file from URL',
currentArgKey: 'projectName',
currentArgValue: '',
headerArguments: {
Method: 'Existing project',
Name: 'test',
ProjectName: '',
Code: '1 line',
},
highlightedHeaderArg: 'projectName',
})
await cmdBar.selectOption({ name: 'testProjectDir' }).click()
await cmdBar.expectState({
stage: 'review',
commandName: 'Import file from URL',
headerArguments: {
Method: 'Existing project',
ProjectName: 'testProjectDir',
Name: 'test',
Code: '1 line',
},
})
await cmdBar.progressCmdBar()
})

await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
await editor.expectEditor.toContain('extrusionDistance = 12')
await toolbar.openPane('files')
await toolbar.expectFileTreeState(['main.kcl', 'test.kcl'])
})
})
})
7 changes: 7 additions & 0 deletions e2e/playwright/fixtures/cmdBarFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,11 @@ export class CmdBarFixture {
await promptEditCommand.first().click()
}
}

/**
* Select an option from the command bar
*/
selectOption = (options: Parameters<typeof this.page.getByRole>[1]) => {
return this.page.getByRole('option', options)
}
}
1 change: 1 addition & 0 deletions interface.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface IElectronAPI {
TEST_SETTINGS_FILE_KEY: string
IS_PLAYWRIGHT: string
VITE_KC_DEV_TOKEN: string
VITE_KC_PROD_TOKEN: string
VITE_KC_API_WS_MODELING_URL: string
VITE_KC_API_BASE_URL: string
VITE_KC_SITE_BASE_URL: string
Expand Down
16 changes: 16 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,29 @@ import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump'
import { UnitsMenu } from 'components/UnitsMenu'
import { CameraProjectionToggle } from 'components/CameraProjectionToggle'
import { useCreateFileLinkQuery } from 'hooks/useCreateFileLinkQueryWatcher'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { maybeWriteToDisk } from 'lib/telemetry'
maybeWriteToDisk()
.then(() => {})
.catch(() => {})

export function App() {
const { project, file } = useLoaderData() as IndexLoaderData
const { commandBarSend } = useCommandsContext()

// Keep a lookout for a URL query string that invokes the 'import file from URL' command
useCreateFileLinkQuery((argDefaultValues) => {
commandBarSend({
type: 'Find and select command',
data: {
groupId: 'projects',
name: 'Import file from URL',
argDefaultValues,
},
})
})

useRefreshSettings(PATHS.FILE + 'SETTINGS')
const navigate = useNavigate()
const filePath = useAbsoluteFilePath()
Expand Down
56 changes: 34 additions & 22 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { CommandBarProvider } from 'components/CommandBar/CommandBarProvider'
import SettingsAuthProvider from 'components/SettingsAuthProvider'
import LspProvider from 'components/LspProvider'
import { KclContextProvider } from 'lang/KclProvider'
import { BROWSER_PROJECT_NAME } from 'lib/constants'
import { ASK_TO_OPEN_QUERY_PARAM, BROWSER_PROJECT_NAME } from 'lib/constants'
import { CoreDumpManager } from 'lib/coredump'
import { codeManager, engineCommandManager } from 'lib/singletons'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
Expand All @@ -47,6 +47,7 @@ import { AppStateProvider } from 'AppState'
import { reportRejection } from 'lib/trap'
import { RouteProvider } from 'components/RouteProvider'
import { ProjectsContextProvider } from 'components/ProjectsContextProvider'
import { OpenInDesktopAppHandler } from 'components/OpenInDesktopAppHandler'

const createRouter = isDesktop() ? createHashRouter : createBrowserRouter

Expand All @@ -58,33 +59,44 @@ const router = createRouter([
/* Make sure auth is the outermost provider or else we will have
* inefficient re-renders, use the react profiler to see. */
element: (
<CommandBarProvider>
<RouteProvider>
<SettingsAuthProvider>
<LspProvider>
<ProjectsContextProvider>
<KclContextProvider>
<AppStateProvider>
<MachineManagerProvider>
<Outlet />
</MachineManagerProvider>
</AppStateProvider>
</KclContextProvider>
</ProjectsContextProvider>
</LspProvider>
</SettingsAuthProvider>
</RouteProvider>
</CommandBarProvider>
<OpenInDesktopAppHandler>
<CommandBarProvider>
<RouteProvider>
<SettingsAuthProvider>
<LspProvider>
<ProjectsContextProvider>
<KclContextProvider>
<AppStateProvider>
<MachineManagerProvider>
<Outlet />
</MachineManagerProvider>
</AppStateProvider>
</KclContextProvider>
</ProjectsContextProvider>
</LspProvider>
</SettingsAuthProvider>
</RouteProvider>
</CommandBarProvider>
</OpenInDesktopAppHandler>
),
errorElement: <ErrorPage />,
children: [
{
path: PATHS.INDEX,
loader: async () => {
loader: async ({ request }) => {
const onDesktop = isDesktop()
return onDesktop
? redirect(PATHS.HOME)
: redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME)
const url = new URL(request.url)
if (onDesktop) {
return redirect(PATHS.HOME + (url.search || ''))
} else {
const searchParams = new URLSearchParams(url.search)
if (!searchParams.has(ASK_TO_OPEN_QUERY_PARAM)) {
return redirect(
PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME + (url.search || '')
)
}
}
return null
},
},
{
Expand Down
2 changes: 2 additions & 0 deletions src/components/CommandBar/CommandArgOptionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,13 @@ function CommandArgOptionInput({
<label
htmlFor="option-input"
className="capitalize px-2 py-1 rounded-l bg-chalkboard-100 dark:bg-chalkboard-80 text-chalkboard-10 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80"
data-testid="cmd-bar-arg-name"
>
{argName}
</label>
<Combobox.Input
id="option-input"
data-testid="cmd-bar-arg-value"
ref={inputRef}
onChange={(event) =>
!event.target.disabled && setQuery(event.target.value)
Expand Down
1 change: 1 addition & 0 deletions src/components/CommandBar/CommandBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const CommandBar = () => {

// Close the command bar when navigating
useEffect(() => {
if (commandBarState.matches('Closed')) return
commandBarSend({ type: 'Close' })
}, [pathname])

Expand Down
12 changes: 11 additions & 1 deletion src/components/CommandComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
import { Command } from 'lib/commandTypes'
import { useEffect, useState } from 'react'
import { CustomIcon } from './CustomIcon'
import { getActorNextEvents } from 'lib/utils'

function CommandComboBox({
options,
Expand Down Expand Up @@ -73,7 +74,8 @@ function CommandComboBox({
<Combobox.Option
key={option.groupId + option.name + (option.displayName || '')}
value={option}
className="flex items-center gap-4 px-4 py-1.5 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90"
className="flex items-center gap-4 px-4 py-1.5 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90 ui-disabled:!text-chalkboard-50"
disabled={optionIsDisabled(option)}
>
{'icon' in option && option.icon && (
<CustomIcon name={option.icon} className="w-5 h-5" />
Expand All @@ -96,3 +98,11 @@ function CommandComboBox({
}

export default CommandComboBox

function optionIsDisabled(option: Command): boolean {
return (
'machineActor' in option &&
option.machineActor !== undefined &&
!getActorNextEvents(option.machineActor.getSnapshot()).includes(option.name)
)
}
Loading
Loading