Skip to content

Commit 33e41fb

Browse files
chore: Allow multiple environment logins, new desktop authentication storage, pool configuration, swap environment support. (#7714)
* fix: logging information about the login * chore: improving the withBaseURL workflow * chore: moving VITE_KC_API_BASE_URL to the helper function * fix: env to helper function api base url * chore: fixing another api base url * chore: shortlinks with base api helper function * chore: prompt edit with base helper function * fix: auto fmt * fix: withAPIBaseURL for all urls * fix: AI caught my typo, RIP * fix: expected * chore: helper function and unit tests for a withSiteBaseURL * chore: migrating many urls to the helper function withSiteBaseURL * chore: updated all VITE_KC_SITE_BASE_URL locations, need to do raw urls next * fix: updating the signin page hard coded urls * chore: updated hard coded site urls in home.tsx * chore: updated all site base urls * chore: unit tests * chore: using the websocket url instead of the hard coded environment variable * chore: urls are using the global websocket url * fix: ope, this should be deleted * fix: huh? * chore: skeleton to get some environments going * chore: skeleton for ugly banner and chip, testing code * chore: more skeleton code * fix: auto fixes * fix: unit tests to make sure these values do not acciendentally change * fix: auto fmt * fix: removing this for now, not ready * fix: removing debugging comment * chore: trying to figure out how to get the custom url and pool, most likely window.localStorage * fix: auto fmt * fix: some clean up * chore: adding a status bar global * fix: auto fmt * fix: changing font color * fix: auto fmt * chore: trying to clean up the sign in page for multiple environments with a default environment as well * fix: linter, TS clean up * fix: fmt * fix: auto fixes * fix: auto fixes and testing each environment and scenario * fix: default value fix with empty string * fix: removing console logs * chore: adding where the envs are coming from * fix: adding comment gotcha * fix: swap environment command * fix: autofmt * fix: adding unit tests * fix: rename in unit test * chore: writing unit tests for deskopt functions * fix: writing some more unit tests * fix: adding a migration step for token.txt to production * fix: adding pool workflow * chore: getting pools configured * fix: trying to set default values for the new application commands * fix: default pool value * fix: sign out of all environments on desktop * chore: updating the advanced sign in page, dev mode to start, look at TODOs * chore: moving state up to have the sign in page know the new state for login * chore: updating memory, disk and reading from disk for the pool configuration when selecing the environments * chore: testing the prod binary logic with the correct NODE_ENV set * chore: trying to design the widget popover * fix: auto fmt * chore: formatting text for .env * fix: auto fmt * chore: trying to fix some display issues * fix: cleaning, the sign out all will be moved to the user menu * fix: adding more commands to the user menu, need to filter them now * chore: sign out of all envs instead of clearing cache * fix: adding more logic for localhost, need to clean up some of the logic to reuse functions easier * fix: moving specific logic to a helper function * fix: fmt? * chore: adding unit tetss for getEnvironmentNameDisplay * chore: cleaning up shorthand for environments, adding unit tests for it as well * fix: cleaning up PR * fix: trying to fix some bugs on the home page * fix: fmt * fix: hiding content if you are in production or web * fix: linter and fmt * fix: trying to solve tsc issues * fix: removing old function * fix: auto fmt * fix: fixing tsc errors by making another helper functiont to wrap my logic * Update snapshots * Update snapshots * fix: floating ' * fix: I think this correct? * chore: big brick, big refactor of base domain * fix: trying a massive clean up * fix: add builds from removal * fix: making some progress * fix: fixing some linter errors * fix: linters for time being, i have a lot of commented code * fix: more progress * fix: closer? * chore: looking good! * fix: large cleanup * fix: still need a few things * fix: fmt * fix: initializing the sign in page with desktop stuff since it isn't mapped to react easily * fix: fixing loading logic on the home page and passing during sign in * chore: adding comment for websocket ur override in .env.development * fix: removing NODE_ENV check, only hide on web * chore: remove debug copy, it is following the same flow for all ways of running the application * fix: cleanup * fix: should not be an env check, should be a desktop check * fix: typo on environment variable configuration for production * fix: display of the base domain was wrong, it needs to be based on the latest environment value * chore: implementing sign out all environments * fix: multiple sign out fix and showing and hiding it in the user menu * fix: hiding clear if pool is auto * chore: auto parse url, hide clear when needed, sign out of all * fix: file is empty now. * fix: fixing a bug! A unit test actually caught this * fix: fixing env.test.ts * fix: fixing src/lib/desktop.test.ts * fix: by default .env.development will not have this thus process.env won't. Only in .env.development.local * fix: vite will not have this either... * chore: cache wasm result for the collect recursive function, it does not need to compute it at recursive level * fix: can run isDesktop in electron now * chore: adding unit test for generating urls * fix: removing todo * fix: localhost debugging * fix: addressed duplicate id for status bar item * fix: leaving a TODO Reminder for the future * fix: updated confusing console log statements to say empty string instead of printing it. * fix: updating the unit test strings to match the subdomain * fix: updating old comment to provide a subdomain example * fix: improve comment to make it more clear * fix: cleaning up confusing variable names, removing everything related to token.txt * fix: two if statements into an if else, logic is the same * fix: if statement cruly braces for improved reading * fix: removing unused variable from previous advancedsigninoptions gui * fix: missing away on async function, ope * fix: fixing pool on localhost, allows web socket url to be overwritten locally * fix: fixing websocket .env.development.local override * fix: python codespell typo check * fix: improved substring logic since it could replace a valid string * fix: updated a console log to be more helpful when debugging --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 9931659 commit 33e41fb

22 files changed

+1089
-104
lines changed

.env.development

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
NODE_ENV=development
44

55
# App
6-
VITE_KITTYCAD_API_BASE_URL=https://api.dev.zoo.dev
7-
VITE_KITTYCAD_API_WEBSOCKET_URL=wss://api.dev.zoo.dev/ws/modeling/commands
6+
VITE_KITTYCAD_BASE_DOMAIN=dev.zoo.dev
87
#VITE_KITTYCAD_API_TOKEN="required for testing, optional to skip auth in the app"
9-
VITE_KITTYCAD_SITE_BASE_URL=https://dev.zoo.dev
10-
VITE_KITTYCAD_SITE_APP_URL=https://app.dev.zoo.dev
118
#VITE_WASM_BASE_URL="optional override of Wasm URL if not on default port 3000"
9+
#VITE_KITTYCAD_API_WEBSOCKET_URL="optional override for engine websocket url"
1210
FAIL_ON_CONSOLE_ERRORS=true
1311

1412
# KCL

.env.production

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
NODE_ENV=production
22

33
# App
4-
VITE_KITTYCAD_API_BASE_URL=https://api.zoo.dev
5-
VITE_KITTYCAD_API_WEBSOCKET_URL=wss://api.zoo.dev/ws/modeling/commands
6-
VITE_KITTYCAD_SITE_BASE_URL=https://zoo.dev
7-
VITE_KITTYCAD_SITE_APP_URL=https://app.zoo.dev
4+
VITE_KITTYCAD_BASE_DOMAIN=zoo.dev

interface.d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,9 @@ export interface IElectronAPI {
7373
process: {
7474
env: {
7575
NODE_ENV: string
76-
VITE_KITTYCAD_API_BASE_URL: string
76+
VITE_KITTYCAD_BASE_DOMAIN: string
7777
VITE_KITTYCAD_API_WEBSOCKET_URL: string
7878
VITE_KITTYCAD_API_TOKEN: string
79-
VITE_KITTYCAD_SITE_BASE_URL: string
80-
VITE_KITTYCAD_SITE_APP_URL: string
8179
}
8280
}
8381
kittycad: (access: string, args: any) => any

src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import type { StatusBarItemType } from '@src/components/StatusBar/statusBarTypes
6767
import { UndoRedoButtons } from '@src/components/UndoRedoButtons'
6868
import { Toolbar } from '@src/Toolbar'
6969
import { withSiteBaseURL } from '@src/lib/withBaseURL'
70+
import env from '@src/env'
7071

7172
// CYCLIC REF
7273
sceneInfra.camControls.engineStreamActor = engineStreamActor
@@ -92,7 +93,7 @@ export function App() {
9293

9394
// Stream related refs and data
9495
const [searchParams] = useSearchParams()
95-
const pool = searchParams.get('pool')
96+
const pool = searchParams.get('pool') || env().POOL || null
9697

9798
const projectName = project?.name || null
9899
const projectPath = project?.path || null

src/components/StatusBar/defaultStatusBarItems.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import { isDesktop } from '@src/lib/isDesktop'
1515
import { APP_DOWNLOAD_PATH } from '@src/lib/constants'
1616
import { desktopAppPitchMessage } from '@src/components/DownloadAppToast'
1717
import { withSiteBaseURL } from '@src/lib/withBaseURL'
18+
import {
19+
EnvironmentChip,
20+
EnvironmentDescription,
21+
} from '@src/components/environment/Environment'
1822

1923
export const defaultGlobalStatusBarItems = ({
2024
location,
@@ -43,6 +47,10 @@ export const defaultGlobalStatusBarItems = ({
4347
children: desktopAppPitchMessage,
4448
},
4549
},
50+
{
51+
id: 'environment',
52+
component: EnvironmentStatusBarItem,
53+
},
4654
{
4755
id: 'telemetry',
4856
element: 'link',
@@ -101,6 +109,24 @@ function BillingStatusBarItem() {
101109
)
102110
}
103111

112+
function EnvironmentStatusBarItem() {
113+
return isDesktop() ? (
114+
<Popover className="relative flex items-stretch">
115+
<Popover.Button
116+
className="m-0 p-0 border-0 flex items-stretch"
117+
data-testid="environment-subdomain-bar"
118+
>
119+
<EnvironmentChip />
120+
</Popover.Button>
121+
<Popover.Panel className="absolute left-0 bottom-full mb-1 w-64 flex flex-col gap-1 align-stretch rounded-lg shadow-lg text-sm">
122+
<EnvironmentDescription />
123+
</Popover.Panel>
124+
</Popover>
125+
) : (
126+
<></>
127+
)
128+
}
129+
104130
export const defaultLocalStatusBarItems: StatusBarItemType[] = [
105131
{
106132
id: 'help',

src/components/UserSidebarMenu.tsx

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Popover, Transition } from '@headlessui/react'
22
import type { Models } from '@kittycad/lib'
3-
import { Fragment, useMemo, useState } from 'react'
3+
import { Fragment, useEffect, useMemo, useState } from 'react'
44
import { useLocation, useNavigate } from 'react-router-dom'
55

66
import type { ActionButtonProps } from '@src/components/ActionButton'
@@ -14,9 +14,14 @@ import { PATHS } from '@src/lib/paths'
1414
import { authActor } from '@src/lib/singletons'
1515
import { reportRejection } from '@src/lib/trap'
1616
import { withSiteBaseURL } from '@src/lib/withBaseURL'
17+
import env from '@src/env'
18+
import { commandBarActor } from '@src/lib/singletons'
19+
import { listAllEnvironmentsWithTokens } from '@src/lib/desktop'
1720

1821
type User = Models['User_type']
1922

23+
let didListEnvironments = false
24+
2025
const UserSidebarMenu = ({ user }: { user?: User }) => {
2126
const platform = usePlatform()
2227
const location = useLocation()
@@ -25,6 +30,22 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
2530
const [imageLoadFailed, setImageLoadFailed] = useState(false)
2631
const navigate = useNavigate()
2732
const send = authActor.send
33+
const fullEnvironmentName = env().VITE_KITTYCAD_BASE_DOMAIN
34+
const [hasMultipleEnvironments, setHasMultipleEnvironments] = useState(false)
35+
36+
useEffect(() => {
37+
if (!didListEnvironments) {
38+
didListEnvironments = true
39+
listAllEnvironmentsWithTokens()
40+
.then((environmentsWithTokens) => {
41+
setHasMultipleEnvironments(environmentsWithTokens.length > 1)
42+
})
43+
.catch(reportRejection)
44+
}
45+
}, [])
46+
47+
// Do not show the environment items on web
48+
const hideEnvironmentItems = !isDesktop()
2849

2950
// We filter this memoized list so that no orphan "break" elements are rendered.
3051
const userMenuItems = useMemo<(ActionButtonProps | 'break')[]>(
@@ -141,20 +162,54 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
141162
children: <span className="flex-1">Check for updates</span>,
142163
},
143164
'break',
165+
{
166+
id: 'change-environment',
167+
Element: 'button',
168+
children: <span>Change environment</span>,
169+
onClick: () => {
170+
const environment = env().VITE_KITTYCAD_BASE_DOMAIN
171+
if (environment) {
172+
commandBarActor.send({
173+
type: 'Find and select command',
174+
data: {
175+
groupId: 'application',
176+
name: 'switch-environments',
177+
argDefaultValues: {
178+
environment,
179+
},
180+
},
181+
})
182+
}
183+
},
184+
className: hideEnvironmentItems ? 'hidden' : '',
185+
},
144186
{
145187
id: 'sign-out',
146188
Element: 'button',
147189
'data-testid': 'user-sidebar-sign-out',
148-
children: 'Sign out',
190+
children: (
191+
<span>
192+
Sign out{hideEnvironmentItems ? '' : ` of ${fullEnvironmentName}`}
193+
</span>
194+
),
149195
onClick: () => send({ type: 'Log out' }),
150196
className: '', // Just making TS's filter type coercion happy 😠
151197
},
198+
{
199+
id: 'sign-out-all',
200+
Element: 'button',
201+
'data-testid': 'user-sidebar-sign-out',
202+
children: <span>Sign out of all environments</span>,
203+
onClick: () => send({ type: 'Log out all' }),
204+
className:
205+
hideEnvironmentItems || !hasMultipleEnvironments ? 'hidden' : '',
206+
},
152207
].filter(
153208
(props) =>
154209
props === 'break' ||
155210
(typeof props !== 'string' && !props.className?.includes('hidden'))
156211
) as (ActionButtonProps | 'break')[],
157-
[platform, location, filePath, navigate, send]
212+
[platform, location, filePath, navigate, send, hasMultipleEnvironments]
158213
)
159214

160215
// This image host goes down sometimes. We will instead rewrite the
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { ActionButton } from '@src/components/ActionButton'
2+
import { commandBarActor } from '@src/lib/singletons'
3+
import env from '@src/env'
4+
import { writeEnvironmentConfigurationPool } from '@src/lib/desktop'
5+
import { reportRejection } from '@src/lib/trap'
6+
7+
export function EnvironmentChip() {
8+
const shorthand = env().VITE_KITTYCAD_BASE_DOMAIN
9+
const pool = env().POOL
10+
return (
11+
<div className="flex items-center px-2 py-1 text-xs text-chalkboard-80 dark:text-chalkboard-30 rounded-none border-none hover:bg-chalkboard-30 dark:hover:bg-chalkboard-80 focus:bg-chalkboard-30 dark:focus:bg-chalkboard-80 hover:text-chalkboard-100 dark:hover:text-chalkboard-10 focus:text-chalkboard-100 dark:focus:text-chalkboard-10 focus:outline-none focus-visible:ring-2 focus:ring-primary focus:ring-opacity-50">
12+
<span className="">
13+
{shorthand} {pool ? `+ Pool` : ''}
14+
</span>
15+
</div>
16+
)
17+
}
18+
19+
export function EnvironmentDescription() {
20+
const fullEnvironmentName = env().VITE_KITTYCAD_BASE_DOMAIN
21+
return (
22+
<div className="absolute left-2 bottom-full mb-1 flex-col gap-1 align-stretch bg-chalkboard-10 dark:bg-chalkboard-90 rounded shadow-lg border border-solid border-chalkboard-20/50 dark:border-chalkboard-80/50 text-sm">
23+
<div
24+
className={`flex flex-col p-2 mb-2 rounded-t-sm bg-chalkboard-20 text-chalkboard-100`}
25+
>
26+
<p className="flex flex-row justify-between">
27+
<h2 className="text-sm font-sans font-normal">Environment</h2>
28+
<p
29+
data-testid="environment"
30+
className="text-xs rounded-sm flex flex-row items-center"
31+
>
32+
<ActionButton
33+
Element="button"
34+
onClick={() => {
35+
const environment = env().VITE_KITTYCAD_BASE_DOMAIN
36+
if (environment) {
37+
commandBarActor.send({
38+
type: 'Find and select command',
39+
data: {
40+
groupId: 'application',
41+
name: 'switch-environments',
42+
argDefaultValues: {
43+
environment,
44+
},
45+
},
46+
})
47+
}
48+
}}
49+
iconEnd={{ icon: 'sketch', bgClassName: '!bg-transparent' }}
50+
className="ml-1 pr-0"
51+
>
52+
{fullEnvironmentName}
53+
</ActionButton>
54+
</p>
55+
</p>
56+
</div>
57+
<ul>
58+
<li className="flex flex-col px-2 py-2 gap-1 last:mb-0 ">
59+
<p className="text-chalkboard-100">API</p>{' '}
60+
<p className="text-chalkboard-60">
61+
{env().VITE_KITTYCAD_API_BASE_URL}
62+
</p>
63+
</li>
64+
<li className="flex flex-col px-2 py-2 gap-1 last:mb-0 ">
65+
<p className="text-chalkboard-100">Site</p>{' '}
66+
<p className="text-chalkboard-60">
67+
{env().VITE_KITTYCAD_SITE_BASE_URL}
68+
</p>
69+
</li>
70+
<li className="flex flex-col px-2 py-2 gap-1 last:mb-0 ">
71+
<p className="text-chalkboard-100">WebSocket (real-time-data)</p>{' '}
72+
<p className="text-chalkboard-60">
73+
{env().VITE_KITTYCAD_API_WEBSOCKET_URL}
74+
</p>
75+
</li>
76+
<li className="flex flex-col px-2 py-2 gap-1 last:mb-0 ">
77+
<p className="text-chalkboard-100">Connection Pool</p>{' '}
78+
<p className="text-chalkboard-60 flex flex-row justify-between">
79+
<span>{env().POOL || 'Auto'}</span>
80+
<div className="flex flex-row gap-1">
81+
<ActionButton
82+
Element="button"
83+
onClick={() => {
84+
commandBarActor.send({
85+
type: 'Find and select command',
86+
data: {
87+
groupId: 'application',
88+
name: 'choose-pool',
89+
argDefaultValues: {
90+
pool: env().POOL,
91+
},
92+
},
93+
})
94+
}}
95+
>
96+
<span className="py-2 lg:py-0">Edit</span>
97+
</ActionButton>
98+
{env().POOL !== '' && (
99+
<ActionButton
100+
onClick={() => {
101+
const environment = env().VITE_KITTYCAD_BASE_DOMAIN
102+
if (environment) {
103+
writeEnvironmentConfigurationPool(environment, '')
104+
.then(() => {
105+
window.location.reload()
106+
})
107+
.catch(reportRejection)
108+
}
109+
}}
110+
Element="button"
111+
>
112+
<span className="py-2 lg:py-0">Clear</span>
113+
</ActionButton>
114+
)}
115+
</div>
116+
</p>
117+
</li>
118+
</ul>
119+
</div>
120+
)
121+
}

0 commit comments

Comments
 (0)