Separate creating createFileUrl
and shortlink so it is unit testable
This commit is contained in:
@ -15,7 +15,7 @@ import { MachineManagerContext } from 'components/MachineManagerProvider'
|
||||
import usePlatform from 'hooks/usePlatform'
|
||||
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
||||
import Tooltip from './Tooltip'
|
||||
import { createFileLink } from 'lib/createFileLink'
|
||||
import { createCreateFileUrl, createShortlink } from 'lib/links'
|
||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||
import toast from 'react-hot-toast'
|
||||
import { DEV, VITE_KC_PROD_TOKEN } from 'env'
|
||||
@ -212,20 +212,21 @@ function ProjectMenuPopover({
|
||||
})
|
||||
return
|
||||
}
|
||||
const shareUrl = await createFileLink(token, {
|
||||
const shareUrl = createCreateFileUrl({
|
||||
code: codeManager.code,
|
||||
name: project?.name || '',
|
||||
units: settings.context.modeling.defaultUnit.current,
|
||||
})
|
||||
const shortlink = await createShortlink(token, shareUrl.toString())
|
||||
|
||||
if (err(shareUrl)) {
|
||||
toast.error(shareUrl.message, {
|
||||
if (err(shortlink)) {
|
||||
toast.error(shortlink.message, {
|
||||
duration: 5000,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
await globalThis.navigator.clipboard.writeText(shareUrl.url)
|
||||
await globalThis.navigator.clipboard.writeText(shortlink.url)
|
||||
toast.success(
|
||||
'Link copied to clipboard. Anyone who clicks this link will get a copy of this file. Share carefully!',
|
||||
{
|
||||
|
@ -4,7 +4,7 @@ import { useEffect } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { useSettingsAuthContext } from './useSettingsAuthContext'
|
||||
import { isDesktop } from 'lib/isDesktop'
|
||||
import { FileLinkParams } from 'lib/createFileLink'
|
||||
import { FileLinkParams } from 'lib/links'
|
||||
import { ProjectsCommandSchema } from 'lib/commandBarConfigs/projectsCommandConfig'
|
||||
import { baseUnitsUnion } from 'lib/settings/settingsTypes'
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { CREATE_FILE_URL_PARAM } from './constants'
|
||||
import { createFileLink } from './createFileLink'
|
||||
|
||||
describe(`createFileLink`, () => {
|
||||
test(`with simple code`, async () => {
|
||||
const code = `extrusionDistance = 12`
|
||||
const name = `test`
|
||||
const units = `mm`
|
||||
|
||||
// Converted with external online tools
|
||||
const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D`
|
||||
const expectedLink = `http:/localhost:3000/?${CREATE_FILE_URL_PARAM}&name=test&units=mm&code=${expectedEncodedCode}`
|
||||
|
||||
const result = createFileLink({ code, name, units })
|
||||
expect(result).toBe(expectedLink)
|
||||
})
|
||||
})
|
17
src/lib/links.test.ts
Normal file
17
src/lib/links.test.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { ASK_TO_OPEN_QUERY_PARAM, CREATE_FILE_URL_PARAM } from './constants'
|
||||
import { createCreateFileUrl } from './links'
|
||||
|
||||
describe(`link creation tests`, () => {
|
||||
test(`createCreateFileUrl happy path`, async () => {
|
||||
const code = `extrusionDistance = 12`
|
||||
const name = `test`
|
||||
const units = `mm`
|
||||
|
||||
// Converted with external online tools
|
||||
const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D`
|
||||
const expectedLink = `http:/localhost:3000/?${CREATE_FILE_URL_PARAM}&name=test&units=mm&code=${expectedEncodedCode}&${ASK_TO_OPEN_QUERY_PARAM}`
|
||||
|
||||
const result = createCreateFileUrl({ code, name, units })
|
||||
expect(result.toString()).toBe(expectedLink)
|
||||
})
|
||||
})
|
@ -1,7 +1,6 @@
|
||||
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
|
||||
import { ASK_TO_OPEN_QUERY_PARAM, CREATE_FILE_URL_PARAM, PROD_APP_URL } from './constants'
|
||||
import { stringToBase64 } from './base64'
|
||||
import { ZOO_STUDIO_PROTOCOL } from './links'
|
||||
import { DEV } from 'env'
|
||||
export interface FileLinkParams {
|
||||
code: string
|
||||
@ -9,26 +8,38 @@ export interface FileLinkParams {
|
||||
units: UnitLength_type
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a URL with the necessary query parameters to trigger
|
||||
* the "Import file from URL" command in the app.
|
||||
*
|
||||
* With the additional step of asking the user if they want to
|
||||
* open the URL in the desktop app.
|
||||
*/
|
||||
export function createCreateFileUrl({ code, name, units }: FileLinkParams) {
|
||||
// Use the dev server if we are in development mode
|
||||
let origin = DEV ? 'http://localhost:3000' : PROD_APP_URL
|
||||
const searchParams = new URLSearchParams({
|
||||
[CREATE_FILE_URL_PARAM]: '',
|
||||
name,
|
||||
units,
|
||||
code: stringToBase64(code),
|
||||
[ASK_TO_OPEN_QUERY_PARAM]: '',
|
||||
})
|
||||
const createFileUrl = new URL(`?${searchParams.toString()}`, origin)
|
||||
|
||||
return createFileUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a file's code, name, and units, creates shareable link to the
|
||||
* web app with a query parameter that triggers a modal to "open in desktop app".
|
||||
* That modal is defined in the `OpenInDesktopAppHandler` component.
|
||||
* TODO: update the return type to use TS library after its updated
|
||||
*/
|
||||
export async function createFileLink(
|
||||
export async function createShortlink(
|
||||
token: string,
|
||||
{ code, name, units }: FileLinkParams
|
||||
url: string
|
||||
): Promise<Error | { key: string; url: string }> {
|
||||
// Use the dev server if we are in development mode
|
||||
let origin = DEV ? 'http://localhost:3000' : PROD_APP_URL
|
||||
|
||||
let urlFileToShare = new URL(
|
||||
`?${CREATE_FILE_URL_PARAM}&name=${encodeURIComponent(
|
||||
name
|
||||
)}&units=${units}&code=${encodeURIComponent(stringToBase64(code))}&${ASK_TO_OPEN_QUERY_PARAM}`,
|
||||
origin
|
||||
).toString()
|
||||
|
||||
/**
|
||||
* We don't use our `withBaseURL` function here because
|
||||
* there is no URL shortener service in the dev API.
|
||||
@ -40,12 +51,11 @@ export async function createFileLink(
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
url: urlFileToShare,
|
||||
url,
|
||||
// In future we can support org-scoped and password-protected shortlinks here
|
||||
// https://zoo.dev/docs/api/shortlinks/create-a-shortlink-for-a-user?lang=typescript
|
||||
}),
|
||||
})
|
||||
console.log('response', response)
|
||||
if (!response.ok) {
|
||||
const error = await response.json()
|
||||
return new Error(`Failed to create shortlink: ${error.message}`)
|
Reference in New Issue
Block a user