Skip to content

Commit afe2eab

Browse files
authored
Revert "cleanup svg icon usage, types and href generation (#13746)" (#13751)
This reverts commit 5e7a2a1.
1 parent 91fe2f6 commit afe2eab

17 files changed

Lines changed: 269 additions & 58 deletions

File tree

app/gui/integration-test/dashboard/actions/index.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
type LocalTrackedCalls,
1515
} from './localApi'
1616
import LoginPageActions from './LoginPageActions'
17-
import { passAgreementsDialog, TEXT, type MockParams } from './utilities'
17+
import { passAgreementsDialog, TEXT, VALID_PASSWORD, type MockParams } from './utilities'
1818
export * from './utilities'
1919

2020
export const getText = (key: TextId, ...replacements: Replacements[TextId]) => {
@@ -28,23 +28,35 @@ export function getAuthFilePath() {
2828
}
2929

3030
/** Perform a successful login. */
31-
async function loginIfNeeded(page: Page, actions: LoginPageActions<Context>) {
31+
async function login({ page }: MockParams, email = 'email@example.com', password = VALID_PASSWORD) {
3232
const authFile = getAuthFilePath()
33+
34+
await waitForLoaded(page)
3335
const isLoggedIn = (await page.getByTestId('before-auth-layout').count()) === 0
36+
3437
if (isLoggedIn) {
3538
test.info().annotations.push({
3639
type: 'skip',
3740
description: 'Already logged in',
3841
})
39-
const agreementModalVisible = (await page.locator('#agreements-modal').count()) > 0
40-
if (agreementModalVisible) {
41-
await passAgreementsDialog({ page })
42-
await page.context().storageState({ path: authFile })
43-
}
44-
} else {
45-
await actions.login()
46-
await page.context().storageState({ path: authFile })
42+
return
4743
}
44+
45+
return test.step('Login', async () => {
46+
test.info().annotations.push({
47+
type: 'Login',
48+
description: 'Performing login',
49+
})
50+
await page.getByPlaceholder(TEXT.emailPlaceholder).fill(email)
51+
await page.getByPlaceholder(TEXT.passwordPlaceholder).fill(password)
52+
await page.getByRole('button', { name: TEXT.login, exact: true }).getByText(TEXT.login).click()
53+
54+
await expect(page.getByText(TEXT.loadingAppMessage)).not.toBeVisible()
55+
56+
await passAgreementsDialog({ page })
57+
58+
await page.context().storageState({ path: authFile })
59+
})
4860
}
4961

5062
/** Wait for the page to load. */
@@ -132,7 +144,7 @@ export function mockAllAndLogin({
132144
const actions = mockAll({ page, setupAPI, setupLocalAPI })
133145

134146
const driveActions = actions
135-
.step('Pass login screen', (page, _ctx, actions) => loginIfNeeded(page, actions))
147+
.step('Login', (page) => login({ page }))
136148
.step('Wait for dashboard to load', waitForDashboardToLoad)
137149
.into(DrivePageActions<Context>)
138150
return goToCloudFirst ? driveActions.goToCategory.cloud() : driveActions
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/** @file Mock for `@stripe/react-stripe-js` */
2+
3+
import type {
4+
CardElementProps,
5+
ElementsConsumer as StripeElementConsumer,
6+
Elements as StripeElements,
7+
} from '@stripe/react-stripe-js'
8+
import { createContext, useContext, useEffect, useState } from 'react'
9+
10+
/** */
11+
type ElementsContextValue = Parameters<Parameters<typeof StripeElementConsumer>[0]['children']>[0]
12+
13+
const ElementsContext = createContext<ElementsContextValue>(null!)
14+
15+
/** Elements provider for Stripe. */
16+
export function Elements(...[props]: Parameters<typeof StripeElements>) {
17+
const { stripe: stripeRaw, children } = props
18+
const [stripe, setStripe] = useState(stripeRaw && 'then' in stripeRaw ? null : stripeRaw)
19+
const [elements] = useState(() => {
20+
return {
21+
getElement: (type) => {
22+
switch (type) {
23+
case 'card': {
24+
return CardElement
25+
}
26+
default: {
27+
return (<></>) as any
28+
}
29+
}
30+
},
31+
} satisfies Partial<
32+
ElementsContextValue['elements']
33+
> as unknown as ElementsContextValue['elements']
34+
})
35+
36+
useEffect(() => {
37+
let canceled = false
38+
if (stripeRaw && 'then' in stripeRaw) {
39+
void stripeRaw.then((awaitedStripe) => {
40+
if (!canceled) {
41+
setStripe(awaitedStripe)
42+
}
43+
})
44+
}
45+
return () => {
46+
canceled = true
47+
}
48+
}, [stripeRaw])
49+
50+
return (
51+
stripe && (
52+
<ElementsContext.Provider
53+
value={{
54+
stripe,
55+
elements,
56+
}}
57+
>
58+
{children}
59+
</ElementsContext.Provider>
60+
)
61+
)
62+
}
63+
64+
/** Elements consumer for Stripe. */
65+
export function ElementsConsumer(...[props]: Parameters<typeof StripeElementConsumer>) {
66+
return props.children(useContext(ElementsContext))
67+
}
68+
69+
/** Card element for Stripe. */
70+
export function CardElement(props: CardElementProps) {
71+
const { onReady: onReadyRaw, onChange: onChangeRaw } = props
72+
const onReady = onReadyRaw ?? (() => {})
73+
const onChange = onChangeRaw ?? (() => {})
74+
75+
useEffect(() => {
76+
onReady({
77+
blur: () => {},
78+
clear: () => {},
79+
destroy: () => {},
80+
focus: () => {},
81+
mount: () => {},
82+
unmount: () => {},
83+
update: () => {},
84+
on: () => null!,
85+
off: () => null!,
86+
once: () => null!,
87+
})
88+
}, [onReady])
89+
90+
useEffect(() => {
91+
onChange({
92+
elementType: 'card',
93+
empty: false,
94+
complete: true,
95+
error: undefined,
96+
value: { postalCode: '40001' },
97+
brand: 'mastercard',
98+
})
99+
}, [onChange])
100+
101+
return <></>
102+
}
103+
104+
export const useStripe = () => ({
105+
confirmCardSetup: () => {},
106+
})
107+
108+
export const useElements = () => ({
109+
getElement: () => {},
110+
})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/** @file Mock for `@stripe/stripe-js` */
2+
import type { Stripe } from '@stripe/stripe-js'
3+
4+
export const loadStripe = (): Promise<Stripe> =>
5+
Promise.resolve({
6+
createPaymentMethod: () =>
7+
Promise.resolve({
8+
paymentMethod: {
9+
id: '',
10+
object: 'payment_method',
11+
// eslint-disable-next-line camelcase
12+
billing_details: {
13+
address: null,
14+
email: null,
15+
name: null,
16+
phone: null,
17+
},
18+
created: Number(new Date()) / 1_000,
19+
customer: null,
20+
livemode: true,
21+
metadata: {},
22+
type: '',
23+
},
24+
error: undefined,
25+
}),
26+
} satisfies Partial<Stripe> as Partial<Stripe> as Stripe)

app/gui/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
"@react-aria/interactions": "3.23.0",
6868
"@sentry/vite-plugin": "^2.22.7",
6969
"@sentry/vue": "^7.120.2",
70+
"@stripe/react-stripe-js": "^2.9.0",
71+
"@stripe/stripe-js": "^3.5.0",
7072
"@tanstack/react-query": "5.59.20",
7173
"@tanstack/vue-query": "5.59.20",
7274
"@vue/reactivity": "^3.5.13",

app/gui/playwright.config.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ export default defineConfig({
7878
fullyParallel: true,
7979
...(WORKERS ? { workers: WORKERS } : {}),
8080
forbidOnly: isCI,
81-
// Make test preview use the same port as test URL, so that svg icons are properly displayed.
82-
// Unfortunately we can't make it work for both dashboard and project-view at the same time.
83-
reporter: isCI ? [['list'], ['blob']] : [['html', { port: ports.projectView }]],
81+
reporter: isCI ? [['list'], ['blob']] : [['html']],
8482
retries: isCI ? 1 : 0,
8583
use: {
8684
actionTimeout: 5000,

app/gui/src/dashboard/components/Icon/Icon.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import type {
1212
TestIdProps,
1313
} from '#/components/types'
1414
import { tv, type VariantProps } from '#/utilities/tailwindVariants'
15+
import icons from '@/assets/icons.svg'
1516
import { isIconName, type Icon as PossibleIcon } from '@/util/iconMetadata/iconName'
16-
import { svgUseHref } from '@/util/icons'
1717
import { memo } from 'react'
1818
import SvgMask from '../SvgMask'
1919

@@ -171,7 +171,12 @@ export function SvgUse(props: SvgUseProps) {
171171
preserveAspectRatio="xMidYMid slice"
172172
aria-label={alt}
173173
>
174-
<use href={svgUseHref(icon)} className="h-full w-full" aria-hidden="true" data-icon={icon} />
174+
<use
175+
href={icon.includes(':') ? icon : `${icons}#${icon}`}
176+
className="h-full w-full"
177+
aria-hidden="true"
178+
data-icon={icon}
179+
/>
175180
</svg>
176181
)
177182
}

app/gui/src/project-view/assets/icon-missing.svg

Lines changed: 0 additions & 6 deletions
This file was deleted.

app/gui/src/project-view/components/GraphEditor/widgets/WidgetIcon.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import NodeWidget from '@/components/GraphEditor/NodeWidget.vue'
33
import GrowingSpinner from '@/components/shared/GrowingSpinner.vue'
44
import SvgIcon from '@/components/SvgIcon.vue'
55
import { Score, defineWidget, widgetProps } from '@/providers/widgetRegistry'
6-
import { type AnyWidgetIcon } from '@/util/icons'
6+
import { type URLString } from '@/util/data/urlString'
7+
import { type Icon } from '@/util/iconMetadata/iconName'
78
import { computed } from 'vue'
89
910
const props = defineProps(widgetProps(widgetDefinition))
@@ -16,7 +17,7 @@ export const DisplayIcon: unique symbol = Symbol.for('WidgetInput:DisplayIcon')
1617
declare module '@/providers/widgetRegistry' {
1718
export interface WidgetInput {
1819
[DisplayIcon]?: {
19-
icon: AnyWidgetIcon
20+
icon: Icon | URLString | '$evaluating'
2021
allowChoice?: boolean
2122
showContents?: boolean
2223
noGap?: boolean

app/gui/src/project-view/components/StandaloneButton.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<script setup lang="ts">
2-
import { type AnyIcon } from '@/util/icons'
2+
import type { URLString } from '@/util/data/urlString'
3+
import type { Icon } from '@/util/iconMetadata/iconName'
34
import SvgButton from './SvgButton.vue'
45
56
const props = defineProps<{
6-
icon?: AnyIcon | undefined
7+
icon?: Icon | URLString | undefined
78
label?: string | undefined
89
disabled?: boolean
910
title?: string | undefined

app/gui/src/project-view/components/SvgButton.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script setup lang="ts">
22
import MenuButton from '@/components/MenuButton.vue'
33
import SvgIcon from '@/components/SvgIcon.vue'
4-
import { AnyIcon } from '@/util/icons'
4+
import type { URLString } from '@/util/data/urlString'
5+
import type { Icon } from '@/util/iconMetadata/iconName'
56
67
const toggledOn = defineModel<boolean | undefined>()
78
defineProps<{
8-
name?: AnyIcon | undefined
9+
name?: Icon | URLString | undefined
910
label?: string | undefined
1011
disabled?: boolean | undefined
1112
title?: string | undefined

0 commit comments

Comments
 (0)