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:
@ -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 (
|
||||||
|
@ -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`}
|
||||||
>
|
>
|
||||||
|
@ -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
|
||||||
|
@ -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',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -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),
|
||||||
})
|
})
|
||||||
|
@ -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,
|
||||||
|
@ -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/${
|
||||||
|
Reference in New Issue
Block a user