Remove units from share link flow, enable it on nightly (#5304)

* Remove units from the share link flow

They should rely on inline settings annotations

* @pierremtb's fix to turn on the menu item in nightly

* fmt

* Don't show web banner if the create file query param is present

* Change copy to 'Share current part (via Zoo link)'

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
This commit is contained in:
Frank Noirot
2025-02-07 13:19:56 -05:00
committed by GitHub
parent 1bfc3a0a3c
commit f20fc5b467
10 changed files with 20 additions and 86 deletions

View File

@ -2,11 +2,15 @@ import { Dialog } from '@headlessui/react'
import { ActionButton } from './ActionButton' import { ActionButton } from './ActionButton'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useState } from 'react' import { useState } from 'react'
import { useSearchParams } from 'react-router-dom'
import { CREATE_FILE_URL_PARAM } from 'lib/constants'
const DownloadAppBanner = () => { const DownloadAppBanner = () => {
const [searchParams] = useSearchParams()
const hasCreateFileParam = searchParams.has(CREATE_FILE_URL_PARAM)
const { settings } = useSettingsAuthContext() const { settings } = useSettingsAuthContext()
const [isBannerDismissed, setIsBannerDismissed] = useState( const [isBannerDismissed, setIsBannerDismissed] = useState(
settings.context.app.dismissWebBanner.current settings.context.app.dismissWebBanner.current || hasCreateFileParam
) )
return ( return (

View File

@ -104,7 +104,7 @@ function ProjectMenuPopover({
const location = useLocation() const location = useLocation()
const navigate = useNavigate() const navigate = useNavigate()
const filePath = useAbsoluteFilePath() const filePath = useAbsoluteFilePath()
const { settings } = useSettingsAuthContext() useSettingsAuthContext()
const token = useToken() const token = useToken()
const machineManager = useContext(MachineManagerContext) const machineManager = useContext(MachineManagerContext)
const commands = useSelector(commandBarActor, commandsSelector) const commands = useSelector(commandBarActor, commandsSelector)
@ -193,14 +193,13 @@ function ProjectMenuPopover({
{ {
id: 'share-link', id: 'share-link',
Element: 'button', Element: 'button',
children: 'Share link to file', children: 'Share current part (via Zoo link)',
disabled: IS_NIGHTLY_OR_DEBUG || !findCommand(shareCommandInfo), disabled: !(IS_NIGHTLY_OR_DEBUG && findCommand(shareCommandInfo)),
onClick: async () => { onClick: async () => {
await copyFileShareLink({ await copyFileShareLink({
token: token ?? '', token: token ?? '',
code: codeManager.code, code: codeManager.code,
name: project?.name || '', name: project?.name || '',
units: settings.context.modeling.defaultUnit.current,
}) })
}, },
}, },
@ -263,7 +262,7 @@ function ProjectMenuPopover({
as={Fragment} as={Fragment}
> >
<Popover.Panel <Popover.Panel
className={`z-10 absolute top-full left-0 mt-1 pb-1 w-48 bg-chalkboard-10 dark:bg-chalkboard-90 className={`z-10 absolute top-full left-0 mt-1 pb-1 w-52 bg-chalkboard-10 dark:bg-chalkboard-90
border border-solid border-chalkboard-20 dark:border-chalkboard-90 rounded border border-solid border-chalkboard-20 dark:border-chalkboard-90 rounded
shadow-lg`} shadow-lg`}
> >

View File

@ -30,15 +30,7 @@ import {
FILE_EXT, FILE_EXT,
PROJECT_ENTRYPOINT, PROJECT_ENTRYPOINT,
} from 'lib/constants' } from 'lib/constants'
import { DeepPartial } from 'lib/types' import { codeManager, kclManager } from 'lib/singletons'
import { Configuration } from 'wasm-lib/kcl/bindings/Configuration'
import { codeManager } from 'lib/singletons'
import {
loadAndValidateSettings,
projectConfigurationToSettingsPayload,
saveSettings,
setSettingsAtLevel,
} from 'lib/settings/settingsUtils'
import { Project } from 'lib/project' import { Project } from 'lib/project'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
@ -86,7 +78,7 @@ const ProjectsContextWeb = ({ children }: { children: React.ReactNode }) => {
setSearchParams(searchParams) setSearchParams(searchParams)
}, [searchParams, setSearchParams]) }, [searchParams, setSearchParams])
const { const {
settings: { context: settings, send: settingsSend }, settings: { context: settings },
} = useSettingsAuthContext() } = useSettingsAuthContext()
const [state, send, actor] = useMachine( const [state, send, actor] = useMachine(
@ -132,17 +124,10 @@ const ProjectsContextWeb = ({ children }: { children: React.ReactNode }) => {
clearImportSearchParams() clearImportSearchParams()
codeManager.updateCodeStateEditor(input.code || '') codeManager.updateCodeStateEditor(input.code || '')
await codeManager.writeToFile() await codeManager.writeToFile()
await kclManager.executeCode(true)
settingsSend({
type: 'set.modeling.defaultUnit',
data: {
level: 'project',
value: input.units,
},
})
return { return {
message: 'File and units overwritten successfully', message: 'File overwritten successfully',
fileName: input.name, fileName: input.name,
projectName: '', projectName: '',
} }
@ -392,16 +377,6 @@ const ProjectsContextDesktop = ({
? input.name ? input.name
: input.name + FILE_EXT : input.name + FILE_EXT
let message = 'File created successfully' let message = 'File created successfully'
const unitsConfiguration: DeepPartial<Configuration> = {
settings: {
project: {
directory: settings.app.projectDirectory.current,
},
modeling: {
base_unit: input.units,
},
},
}
const needsInterpolated = doesProjectNameNeedInterpolated(projectName) const needsInterpolated = doesProjectNameNeedInterpolated(projectName)
if (needsInterpolated) { if (needsInterpolated) {
@ -414,28 +389,10 @@ const ProjectsContextDesktop = ({
// Create the project around the file if newProject // Create the project around the file if newProject
if (input.method === 'newProject') { if (input.method === 'newProject') {
await createNewProjectDirectory( await createNewProjectDirectory(projectName, input.code)
projectName,
input.code,
unitsConfiguration
)
message = `Project "${projectName}" created successfully with link contents` message = `Project "${projectName}" created successfully with link contents`
} else { } else {
let projectPath = window.electron.join(
settings.app.projectDirectory.current,
projectName
)
message = `File "${fileName}" created successfully` message = `File "${fileName}" created successfully`
const existingConfiguration = await loadAndValidateSettings(
projectPath
)
const settingsToSave = setSettingsAtLevel(
existingConfiguration.settings,
'project',
projectConfigurationToSettingsPayload(unitsConfiguration)
)
await saveSettings(settingsToSave, projectPath)
} }
// Create the file // Create the file

View File

@ -6,7 +6,6 @@ import { useSettingsAuthContext } from './useSettingsAuthContext'
import { isDesktop } from 'lib/isDesktop' import { isDesktop } from 'lib/isDesktop'
import { FileLinkParams } from 'lib/links' import { FileLinkParams } from 'lib/links'
import { ProjectsCommandSchema } from 'lib/commandBarConfigs/projectsCommandConfig' import { ProjectsCommandSchema } from 'lib/commandBarConfigs/projectsCommandConfig'
import { baseUnitsUnion } from 'lib/settings/settingsTypes'
// For initializing the command arguments, we actually want `method` to be undefined // For initializing the command arguments, we actually want `method` to be undefined
// so that we don't skip it in the command palette. // so that we don't skip it in the command palette.
@ -37,13 +36,7 @@ export function useCreateFileLinkQuery(
code: base64ToString( code: base64ToString(
decodeURIComponent(searchParams.get('code') ?? '') decodeURIComponent(searchParams.get('code') ?? '')
), ),
name: searchParams.get('name') ?? DEFAULT_FILE_NAME, name: searchParams.get('name') ?? DEFAULT_FILE_NAME,
units:
(baseUnitsUnion.find((unit) => searchParams.get('units') === unit) ||
settings.context.modeling.defaultUnit.default) ??
settings.context.modeling.defaultUnit.current,
} }
const argDefaultValues: CreateFileSchemaMethodOptional = { const argDefaultValues: CreateFileSchemaMethodOptional = {
@ -55,7 +48,6 @@ export function useCreateFileLinkQuery(
? settings.context.projects.defaultProjectName.current ? settings.context.projects.defaultProjectName.current
: DEFAULT_FILE_NAME, : DEFAULT_FILE_NAME,
code: params.code || '', code: params.code || '',
units: params.units,
method: isDesktop() ? undefined : 'existingProject', method: isDesktop() ? undefined : 'existingProject',
} }

View File

@ -1,8 +1,6 @@
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 { isDesktop } from 'lib/isDesktop' import { isDesktop } from 'lib/isDesktop'
import { baseUnitLabels, baseUnitsUnion } from 'lib/settings/settingsTypes'
import { projectsMachine } from 'machines/projectsMachine' import { projectsMachine } from 'machines/projectsMachine'
export type ProjectsCommandSchema = { export type ProjectsCommandSchema = {
@ -23,7 +21,6 @@ export type ProjectsCommandSchema = {
'Import file from URL': { 'Import file from URL': {
name: string name: string
code?: string code?: string
units: UnitLength_type
method: 'newProject' | 'existingProject' method: 'newProject' | 'existingProject'
projectName?: string projectName?: string
} }
@ -157,15 +154,6 @@ export const projectsCommandBarConfig: StateMachineCommandSetConfig<
return `${lineCount} line${lineCount === 1 ? '' : 's'}` return `${lineCount} line${lineCount === 1 ? '' : 's'}`
}, },
}, },
units: {
inputType: 'options',
required: false,
skip: true,
options: baseUnitsUnion.map((unit) => ({
name: baseUnitLabels[unit],
value: unit,
})),
},
}, },
reviewMessage(commandBarContext) { reviewMessage(commandBarContext) {
return isDesktop() return isDesktop()

View File

@ -136,7 +136,7 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
}, },
{ {
name: 'share-file-link', name: 'share-file-link',
displayName: 'Share file', displayName: 'Share current part (via Zoo link)',
hide: IS_NIGHTLY_OR_DEBUG ? undefined : 'desktop', hide: IS_NIGHTLY_OR_DEBUG ? undefined : 'desktop',
description: 'Create a link that contains a copy of the current file.', description: 'Create a link that contains a copy of the current file.',
groupId: 'code', groupId: 'code',
@ -147,7 +147,6 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
token: commandProps.authToken, token: commandProps.authToken,
code: codeManager.code, code: codeManager.code,
name: commandProps.projectData.project?.name || '', name: commandProps.projectData.project?.name || '',
units: commandProps.settings.defaultUnit,
}).catch(reportRejection) }).catch(reportRejection)
}, },
}, },

View File

@ -5,13 +5,12 @@ describe(`link creation tests`, () => {
test(`createCreateFileUrl happy path`, async () => { test(`createCreateFileUrl happy path`, async () => {
const code = `extrusionDistance = 12` const code = `extrusionDistance = 12`
const name = `test` const name = `test`
const units = `mm`
// Converted with external online tools // Converted with external online tools
const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D` const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D`
const expectedLink = `${VITE_KC_SITE_APP_URL}/?create-file=true&name=test&units=mm&code=${expectedEncodedCode}&ask-open-desktop=true` const expectedLink = `${VITE_KC_SITE_APP_URL}/?create-file=true&name=test&code=${expectedEncodedCode}&ask-open-desktop=true`
const result = createCreateFileUrl({ code, name, units }) const result = createCreateFileUrl({ code, name })
expect(result.toString()).toBe(expectedLink) expect(result.toString()).toBe(expectedLink)
}) })
}) })

View File

@ -1,4 +1,3 @@
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
import { ASK_TO_OPEN_QUERY_PARAM, CREATE_FILE_URL_PARAM } from './constants' import { ASK_TO_OPEN_QUERY_PARAM, CREATE_FILE_URL_PARAM } from './constants'
import { stringToBase64 } from './base64' import { stringToBase64 } from './base64'
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_APP_URL } from 'env' import { VITE_KC_API_BASE_URL, VITE_KC_SITE_APP_URL } from 'env'
@ -7,7 +6,6 @@ import { err } from './trap'
export interface FileLinkParams { export interface FileLinkParams {
code: string code: string
name: string name: string
units: UnitLength_type
} }
export async function copyFileShareLink( export async function copyFileShareLink(
@ -46,12 +44,11 @@ export async function copyFileShareLink(
* With the additional step of asking the user if they want to * With the additional step of asking the user if they want to
* open the URL in the desktop app. * open the URL in the desktop app.
*/ */
export function createCreateFileUrl({ code, name, units }: FileLinkParams) { export function createCreateFileUrl({ code, name }: FileLinkParams) {
let origin = VITE_KC_SITE_APP_URL let origin = VITE_KC_SITE_APP_URL
const searchParams = new URLSearchParams({ const searchParams = new URLSearchParams({
[CREATE_FILE_URL_PARAM]: String(true), [CREATE_FILE_URL_PARAM]: String(true),
name, name,
units,
code: stringToBase64(code), code: stringToBase64(code),
[ASK_TO_OPEN_QUERY_PARAM]: String(true), [ASK_TO_OPEN_QUERY_PARAM]: String(true),
}) })

View File

@ -306,7 +306,6 @@ export const projectsMachine = setup({
return { return {
code: '', code: '',
name: '', name: '',
units: 'mm',
method: 'existingProject', method: 'existingProject',
projects: context.projects, projects: context.projects,
} }
@ -314,7 +313,6 @@ export const projectsMachine = setup({
return { return {
code: event.data.code || '', code: event.data.code || '',
name: event.data.name, name: event.data.name,
units: event.data.units,
method: event.data.method, method: event.data.method,
projectName: event.data.projectName, projectName: event.data.projectName,
projects: context.projects, projects: context.projects,

View File

@ -32,7 +32,8 @@ export const PACKAGE_NAME = isDesktop()
export const IS_NIGHTLY = PACKAGE_NAME.indexOf('-nightly') > -1 export const IS_NIGHTLY = PACKAGE_NAME.indexOf('-nightly') > -1
export const IS_NIGHTLY_OR_DEBUG = IS_NIGHTLY || APP_VERSION === '0.0.0' export const IS_NIGHTLY_OR_DEBUG =
IS_NIGHTLY || APP_VERSION === '0.0.0' || APP_VERSION === '11.22.33'
export function getReleaseUrl(version: string = APP_VERSION) { export function getReleaseUrl(version: string = APP_VERSION) {
return `https://github.com/KittyCAD/modeling-app/releases/tag/${ return `https://github.com/KittyCAD/modeling-app/releases/tag/${