Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make toast copy more consistent #2504

Merged
merged 22 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c86cc22
Make toast copy more consistent
charliepark Oct 14, 2024
a55c4e7
Add confirmation for disk deletion
charliepark Oct 14, 2024
29fe8a5
Add highlighting to toast contents
charliepark Oct 16, 2024
d8ea07a
keep str test
charliepark Oct 16, 2024
72f7540
Fix tests; a few more ToastContents, but will hold here
charliepark Oct 16, 2024
d284ad5
Move away from ToastContent
charliepark Oct 16, 2024
bc37a3d
Migrate other addToasts to new approach
charliepark Oct 16, 2024
6f0cfa6
Add toast on a couple of onSuccess functions missing them
charliepark Oct 16, 2024
eacc792
Fix a few tests
charliepark Oct 16, 2024
0beea3d
Missed a couple
charliepark Oct 16, 2024
874c49b
Formatting
charliepark Oct 16, 2024
8852827
surely saying this was the last test to fix won't jinx it
charliepark Oct 16, 2024
92d024b
nope; it was not fully reading the previous CI report
charliepark Oct 16, 2024
983b791
Add expectToast helper
charliepark Oct 17, 2024
749a32b
use a lighter weight font
charliepark Oct 17, 2024
868aa24
Close toasts at end of expectToast
charliepark Oct 17, 2024
3da00b3
Merge branch 'main' into align_toast_copy
charliepark Oct 29, 2024
dbe02c4
let addToast take the content directly, fix type errors, change one case
david-crespo Oct 29, 2024
d90b1c7
a billion one-liner toasts with the magic of prettier-ignore
charliepark Oct 29, 2024
a3d736b
eliminate HLs by using CSS instead
charliepark Oct 29, 2024
4ecef06
actually..... do it in tailwind with group. yowza
david-crespo Oct 29, 2024
69940ce
undo spurious changes to checksums in package-lock.json
david-crespo Oct 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lintBuildTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: 'npm'
- name: Cache node_modules
uses: actions/cache@v4
Expand Down
5 changes: 3 additions & 2 deletions app/components/AttachEphemeralIpModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useForm } from 'react-hook-form'

import { useApiMutation, useApiQueryClient, usePrefetchedApiQuery } from '~/api'
import { ListboxField } from '~/components/form/fields/ListboxField'
import { HL } from '~/components/HL'
import { useInstanceSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { Modal } from '~/ui/lib/Modal'
Expand All @@ -29,9 +30,9 @@ export const AttachEphemeralIpModal = ({ onDismiss }: { onDismiss: () => void })
[siloPools]
)
const instanceEphemeralIpAttach = useApiMutation('instanceEphemeralIpAttach', {
onSuccess() {
onSuccess(ephemeralIp) {
queryClient.invalidateQueries('instanceExternalIpList')
addToast({ content: 'Your ephemeral IP has been attached' })
addToast(<>IP <HL>{ephemeralIp.ip}</HL> attached</>) // prettier-ignore
onDismiss()
},
onError: (err) => {
Expand Down
5 changes: 3 additions & 2 deletions app/components/AttachFloatingIpModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useForm } from 'react-hook-form'

import { useApiMutation, useApiQueryClient, type FloatingIp, type Instance } from '~/api'
import { ListboxField } from '~/components/form/fields/ListboxField'
import { HL } from '~/components/HL'
import { addToast } from '~/stores/toast'
import { Message } from '~/ui/lib/Message'
import { Modal } from '~/ui/lib/Modal'
Expand Down Expand Up @@ -45,10 +46,10 @@ export const AttachFloatingIpModal = ({
}) => {
const queryClient = useApiQueryClient()
const floatingIpAttach = useApiMutation('floatingIpAttach', {
onSuccess() {
onSuccess(floatingIp) {
queryClient.invalidateQueries('floatingIpList')
queryClient.invalidateQueries('instanceExternalIpList')
addToast({ content: 'Your floating IP has been attached' })
addToast(<>IP <HL>{floatingIp.name}</HL> attached</>) // prettier-ignore
onDismiss()
},
onError: (err) => {
Expand Down
9 changes: 8 additions & 1 deletion app/components/HL.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,11 @@
*/
import { classed } from '~/util/classed'

export const HL = classed.span`text-sans-semi-md text-default`
// note parent with secondary text color must have 'group' on it for
// this to work. see Toast for an example
export const HL = classed.span`
text-sans-md text-default
group-[.text-accent-secondary]:text-accent
group-[.text-error-secondary]:text-error
group-[.text-info-secondary]:text-info
`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mad scientist stuff. This is the CSS selector it generates.

.group.text-accent-secondary .group-\[\.text-accent-secondary\]\:text-accent {
  // ...
}

5 changes: 4 additions & 1 deletion app/components/ToastStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ export function ToastStack() {
})

return (
<div className="pointer-events-auto fixed bottom-4 left-4 z-toast flex flex-col items-end space-y-2">
<div
className="pointer-events-auto fixed bottom-4 left-4 z-toast flex flex-col items-end space-y-2"
data-testid="Toasts"
>
{transition((style, item) => (
<animated.div
style={{
Expand Down
3 changes: 2 additions & 1 deletion app/forms/disk-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { ListboxField } from '~/components/form/fields/ListboxField'
import { NameField } from '~/components/form/fields/NameField'
import { RadioField } from '~/components/form/fields/RadioField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { useProjectSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { FormDivider } from '~/ui/lib/Divider'
Expand Down Expand Up @@ -76,7 +77,7 @@ export function CreateDiskSideModalForm({
const createDisk = useApiMutation('diskCreate', {
onSuccess(data) {
queryClient.invalidateQueries('diskList')
addToast({ content: 'Your disk has been created' })
addToast(<>Disk <HL>{data.name}</HL> created</>) // prettier-ignore
onSuccess?.(data)
onDismiss(navigate)
},
Expand Down
6 changes: 4 additions & 2 deletions app/forms/firewall-rules-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '@oxide/api'

import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { getVpcSelector, useVpcSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { ALL_ISH } from '~/util/consts'
Expand Down Expand Up @@ -74,9 +75,10 @@ export function CreateFirewallRuleForm() {
const onDismiss = () => navigate(pb.vpcFirewallRules(vpcSelector))

const updateRules = useApiMutation('vpcFirewallRulesUpdate', {
onSuccess() {
onSuccess(updatedRules) {
const newRule = updatedRules.rules[updatedRules.rules.length - 1]
queryClient.invalidateQueries('vpcFirewallRulesView')
addToast({ content: 'Your firewall rule has been created' })
addToast(<>Firewall rule <HL>{newRule.name}</HL> created</>) // prettier-ignore
navigate(pb.vpcFirewallRules(vpcSelector))
},
})
Expand Down
6 changes: 5 additions & 1 deletion app/forms/firewall-rules-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import {

import { trigger404 } from '~/components/ErrorBoundary'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import {
getFirewallRuleSelector,
useFirewallRuleSelector,
useVpcSelector,
} from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { ALL_ISH } from '~/util/consts'
import { invariant } from '~/util/invariant'
import { pb } from '~/util/path-builder'
Expand Down Expand Up @@ -64,13 +66,15 @@ export function EditFirewallRuleForm() {
const onDismiss = () => navigate(pb.vpcFirewallRules(vpcSelector))

const updateRules = useApiMutation('vpcFirewallRulesUpdate', {
onSuccess() {
onSuccess(updatedRules, { body }) {
// Nav before the invalidate because I once saw the above invariant fail
// briefly after successful edit (error page flashed but then we land
// on the rules list ok) and I think it was a race condition where the
// invalidate managed to complete while the modal was still open.
onDismiss()
queryClient.invalidateQueries('vpcFirewallRulesView')
const updatedRule = body.rules[body.rules.length - 1]
addToast(<>Firewall rule <HL>{updatedRule.name}</HL> updated</>) // prettier-ignore
},
})

Expand Down
5 changes: 3 additions & 2 deletions app/forms/floating-ip-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { toIpPoolItem } from '~/components/form/fields/ip-pool-item'
import { ListboxField } from '~/components/form/fields/ListboxField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { useProjectSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { Message } from '~/ui/lib/Message'
Expand All @@ -45,10 +46,10 @@ export function CreateFloatingIpSideModalForm() {
const navigate = useNavigate()

const createFloatingIp = useApiMutation('floatingIpCreate', {
onSuccess() {
onSuccess(floatingIp) {
queryClient.invalidateQueries('floatingIpList')
queryClient.invalidateQueries('ipPoolUtilizationView')
addToast({ content: 'Your Floating IP has been created' })
addToast(<>Floating IP <HL>{floatingIp.name}</HL> created</>) // prettier-ignore
navigate(pb.floatingIps(projectSelector))
},
})
Expand Down
3 changes: 2 additions & 1 deletion app/forms/floating-ip-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { getFloatingIpSelector, useFloatingIpSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { pb } from 'app/util/path-builder'
Expand Down Expand Up @@ -47,7 +48,7 @@ export function EditFloatingIpSideModalForm() {
const editFloatingIp = useApiMutation('floatingIpUpdate', {
onSuccess(_floatingIp) {
queryClient.invalidateQueries('floatingIpList')
addToast({ content: 'Your floating IP has been updated' })
addToast(<>Floating IP <HL>{_floatingIp.name}</HL> updated</>) // prettier-ignore
onDismiss()
},
})
Expand Down
5 changes: 3 additions & 2 deletions app/forms/idp/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FileField } from '~/components/form/fields/FileField'
import { NameField } from '~/components/form/fields/NameField'
import { TextField } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { useSiloSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { readBlobAsBase64 } from '~/util/file'
Expand Down Expand Up @@ -51,9 +52,9 @@ export function CreateIdpSideModalForm() {
const onDismiss = () => navigate(pb.silo({ silo }))

const createIdp = useApiMutation('samlIdentityProviderCreate', {
onSuccess() {
onSuccess(idp) {
queryClient.invalidateQueries('siloIdentityProviderList')
addToast({ content: 'Your identity provider has been created' })
addToast(<>IdP <HL>{idp.name}</HL> created</>) // prettier-ignore
onDismiss()
},
})
Expand Down
5 changes: 3 additions & 2 deletions app/forms/image-from-snapshot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { TextField } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { getProjectSnapshotSelector, useProjectSnapshotSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { PropertiesTable } from '~/ui/lib/PropertiesTable'
Expand Down Expand Up @@ -54,9 +55,9 @@ export function CreateImageFromSnapshotSideModalForm() {
const onDismiss = () => navigate(pb.snapshots({ project }))

const createImage = useApiMutation('imageCreate', {
onSuccess() {
onSuccess(image) {
queryClient.invalidateQueries('imageList')
addToast({ content: 'Your image has been created' })
addToast(<>Image <HL>{image.name}</HL> created</>) // prettier-ignore
onDismiss()
},
})
Expand Down
2 changes: 1 addition & 1 deletion app/forms/instance-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export function CreateInstanceForm() {
{ path: { instance: instance.name }, query: { project } },
instance
)
addToast({ content: 'Your instance has been created' })
addToast(<>Instance <HL>{instance.name}</HL> created</>) // prettier-ignore
navigate(pb.instance({ project, instance: instance.name }))
},
})
Expand Down
3 changes: 2 additions & 1 deletion app/forms/ip-pool-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useApiMutation, useApiQueryClient, type IpPoolCreate } from '@oxide/api
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { addToast } from '~/stores/toast'
import { Message } from '~/ui/lib/Message'
import { pb } from '~/util/path-builder'
Expand All @@ -31,7 +32,7 @@ export function CreateIpPoolSideModalForm() {
const createPool = useApiMutation('ipPoolCreate', {
onSuccess(_pool) {
queryClient.invalidateQueries('ipPoolList')
addToast({ content: 'Your IP pool has been created' })
addToast(<>IP pool <HL>{_pool.name}</HL> created</>) // prettier-ignore
navigate(pb.ipPools())
},
})
Expand Down
3 changes: 2 additions & 1 deletion app/forms/ip-pool-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { getIpPoolSelector, useIpPoolSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
Expand All @@ -43,7 +44,7 @@ export function EditIpPoolSideModalForm() {
onSuccess(updatedPool) {
queryClient.invalidateQueries('ipPoolList')
navigate(pb.ipPool({ pool: updatedPool.name }))
addToast({ content: 'Your IP pool has been updated' })
addToast(<>IP pool <HL>{updatedPool.name}</HL> updated</>) // prettier-ignore

// Only invalidate if we're staying on the same page. If the name
// _has_ changed, invalidating ipPoolView causes an error page to flash
Expand Down
5 changes: 4 additions & 1 deletion app/forms/network-interface-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { TextFieldInner } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { useInstanceSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { FormDivider } from '~/ui/lib/Divider'
import { FieldLabel } from '~/ui/lib/FieldLabel'
import * as MiniTable from '~/ui/lib/MiniTable'
Expand All @@ -42,8 +44,9 @@ export function EditNetworkInterfaceForm({
const instanceSelector = useInstanceSelector()

const editNetworkInterface = useApiMutation('instanceNetworkInterfaceUpdate', {
onSuccess() {
onSuccess(nic) {
queryClient.invalidateQueries('instanceNetworkInterfaceList')
addToast(<>Network interface <HL>{nic.name}</HL> updated</>) // prettier-ignore
onDismiss()
},
})
Expand Down
4 changes: 4 additions & 0 deletions app/forms/project-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import { ListboxField } from '~/components/form/fields/ListboxField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { useProjectSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'

import {
actorToItem,
Expand All @@ -35,6 +36,8 @@ export function ProjectAccessAddUserSideModal({ onDismiss, policy }: AddRoleModa
const updatePolicy = useApiMutation('projectPolicyUpdate', {
onSuccess: () => {
queryClient.invalidateQueries('projectPolicyView')
// We don't have the name of the user or group, so we'll just have a generic message
addToast({ content: 'Role assigned' })
onDismiss()
},
})
Expand Down Expand Up @@ -97,6 +100,7 @@ export function ProjectAccessEditUserSideModal({
const updatePolicy = useApiMutation('projectPolicyUpdate', {
onSuccess: () => {
queryClient.invalidateQueries('projectPolicyView')
addToast({ content: 'Role updated' })
onDismiss()
},
})
Expand Down
3 changes: 2 additions & 1 deletion app/forms/project-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useApiMutation, useApiQueryClient, type ProjectCreate } from '@oxide/ap
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'

Expand All @@ -33,7 +34,7 @@ export function CreateProjectSideModalForm() {
queryClient.invalidateQueries('projectList')
// avoid the project fetch when the project page loads since we have the data
queryClient.setQueryData('projectView', { path: { project: project.name } }, project)
addToast({ content: 'Your project has been created' })
addToast(<>Project <HL>{project.name}</HL> created</>) // prettier-ignore
navigate(pb.project({ project: project.name }))
},
})
Expand Down
3 changes: 2 additions & 1 deletion app/forms/project-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { getProjectSelector, useProjectSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
Expand Down Expand Up @@ -45,7 +46,7 @@ export function EditProjectSideModalForm() {
queryClient.invalidateQueries('projectList')
// avoid the project fetch when the project page loads since we have the data
queryClient.setQueryData('projectView', { path: { project: project.name } }, project)
addToast({ content: 'Your project has been updated' })
addToast(<>Project <HL>{project.name}</HL> updated</>) // prettier-ignore
onDismiss()
},
})
Expand Down
3 changes: 2 additions & 1 deletion app/forms/silo-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { RadioField } from '~/components/form/fields/RadioField'
import { TextField } from '~/components/form/fields/TextField'
import { TlsCertsField } from '~/components/form/fields/TlsCertsField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { addToast } from '~/stores/toast'
import { FormDivider } from '~/ui/lib/Divider'
import { FieldLabel } from '~/ui/lib/FieldLabel'
Expand Down Expand Up @@ -57,7 +58,7 @@ export function CreateSiloSideModalForm() {
onSuccess(silo) {
queryClient.invalidateQueries('siloList')
queryClient.setQueryData('siloView', { path: { silo: silo.name } }, silo)
addToast({ content: 'Your silo has been created' })
addToast(<>Silo <HL>{silo.name}</HL> created</>) // prettier-ignore
onDismiss()
},
})
Expand Down
5 changes: 3 additions & 2 deletions app/forms/snapshot-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ComboboxField } from '~/components/form/fields/ComboboxField'
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { useProjectSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { toComboboxItems } from '~/ui/lib/Combobox'
Expand Down Expand Up @@ -52,9 +53,9 @@ export function CreateSnapshotSideModalForm() {
const onDismiss = () => navigate(pb.snapshots(projectSelector))

const createSnapshot = useApiMutation('snapshotCreate', {
onSuccess() {
onSuccess(snapshot) {
queryClient.invalidateQueries('snapshotList')
addToast({ content: 'Your snapshot has been created' })
addToast(<>Snapshot <HL>{snapshot.name}</HL> created</>) // prettier-ignore
onDismiss()
},
})
Expand Down
Loading
Loading