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

ui: migrate from react-router to wouter #2415

Merged
merged 49 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
032ab1d
wip: starting on refactoring breadcrumbs
Forfold May 16, 2022
bf73e52
fix typography color in appbar
Forfold May 16, 2022
70f653d
move avatar back to original position in toolbar
Forfold May 16, 2022
78f087e
address color issues in tootlbar title
Forfold May 16, 2022
b271637
skip query properly to load profile and admin pages
Forfold May 16, 2022
97aaa39
cleanup
Forfold May 17, 2022
40efc00
start on tests
Forfold May 17, 2022
45d5210
use better name
Forfold May 17, 2022
89db225
update test function
tony-tvu May 18, 2022
562f883
refine selector for failing shifts test
Forfold May 18, 2022
607904b
remove old toolbar component
Forfold May 18, 2022
b74abb1
fix admin pages
Forfold May 19, 2022
94dc551
add wouter, update esbuild
mastercactapus May 25, 2022
0946486
add top-level router with base path
mastercactapus May 25, 2022
b3c623b
convert hooks to wouter
mastercactapus May 25, 2022
d5f92e0
initial pass at AppLink
mastercactapus May 25, 2022
3c62f2a
add urlkey hook
mastercactapus May 26, 2022
884ed34
remove old routers
mastercactapus May 26, 2022
02aa892
refactor navbar
mastercactapus May 26, 2022
c1db5fa
use global routes
mastercactapus May 26, 2022
9e6d7e7
handle empty search
mastercactapus May 26, 2022
f2a29d1
fix requireconfig types
mastercactapus May 26, 2022
1d49f58
switch to wouter apis
mastercactapus May 26, 2022
b11fb56
add list pages
mastercactapus May 26, 2022
fdef5cb
convert ToolbarAction
mastercactapus May 26, 2022
a885db3
fix title handling
mastercactapus May 26, 2022
07908df
add remaining app pages
mastercactapus May 26, 2022
0d33521
add docs route
mastercactapus May 26, 2022
bd94612
remove react-router-dom
mastercactapus May 26, 2022
310d212
fix ref errors
mastercactapus May 26, 2022
b943052
fix profile redirect and spinner
mastercactapus May 26, 2022
a98b73a
fix calendar subscriptions
mastercactapus May 26, 2022
8bf44de
fix profile spinner
mastercactapus May 26, 2022
310470b
fix title replace
mastercactapus May 26, 2022
2bd9829
lint fixes
mastercactapus May 26, 2022
178655b
fix ts errors
mastercactapus May 26, 2022
a0142da
Merge remote-tracking branch 'origin/breadcrumbs' into wouter
mastercactapus May 26, 2022
5d7cee6
fix query
mastercactapus May 26, 2022
0c7568c
use full URLs in breadcrumb
mastercactapus May 26, 2022
8c74ff4
better alert title
mastercactapus May 26, 2022
7ffc419
link to service alert page
mastercactapus May 26, 2022
8c4e5cf
bring user to correct alert page
mastercactapus May 26, 2022
06fe8cd
fix route repair
mastercactapus May 26, 2022
ba8d242
fix lint errors
mastercactapus May 26, 2022
c1909ae
test fixes
mastercactapus May 26, 2022
24c9bff
collapse mobile
mastercactapus May 27, 2022
7a7225a
update navigation
mastercactapus May 27, 2022
8719eba
fix on-call format
mastercactapus May 27, 2022
6c30bd4
fix mobile nav to-from
mastercactapus May 27, 2022
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
11 changes: 2 additions & 9 deletions web/src/app/actions/hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,10 @@ interface GetParamTest {

describe('getParamValues', () => {
function check(x: GetParamTest): void {
const defaultSearch = 'a=str&b=3&c=1&d=0&e=e&e=e&e=ee&f=ok%2Cgo%21'
const mockLocationObject = {
key: '',
search: x.search ? x.search : defaultSearch,
pathname: '',
state: '',
hash: '',
}
const search = x.search || 'a=str&b=3&c=1&d=0&e=e&e=e&e=ee&f=ok%2Cgo%21'

it(x.desc, () => {
expect(getParamValues(mockLocationObject, x.params)).toEqual(x.expected)
expect(getParamValues(search, x.params)).toEqual(x.expected)
})
}

Expand Down
50 changes: 30 additions & 20 deletions web/src/app/actions/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Location } from 'history'
import { useNavigate, useLocation, NavigateFunction } from 'react-router-dom'
import { useLocation } from 'wouter'

export type Value = string | boolean | number | string[]

export function useURLKey(): string {
const [path] = useLocation()
return path + location.search
}

// sanitizeURLParam serializes a value to be ready to store in a URL.
// If a value cannot or should not be stored, an empty string is returned.
export function sanitizeURLParam(value: Value): string | string[] {
Expand All @@ -28,11 +32,11 @@ export function sanitizeURLParam(value: Value): string | string[] {
// getParamValues converts each URL search param into the
// desired type based on its respective default value.
export function getParamValues<T extends Record<string, Value>>(
location: Location,
search: string,
params: T, // <name, default> pairs
): T {
const result = {} as Record<string, Value>
const q = new URLSearchParams(location.search)
const q = new URLSearchParams(search)

for (const [name, defaultVal] of Object.entries(params)) {
if (!q.has(name)) {
Expand All @@ -52,21 +56,17 @@ export function getParamValues<T extends Record<string, Value>>(
return result as T
}

// setURLParams will replace the latest browser history entry with the provided params.
function setURLParams(
navigate: NavigateFunction,
location: Location,
params: URLSearchParams,
): void {
// newSearch will return a normalized URL search string if different from the current one.
function newSearch(params: URLSearchParams): [boolean, string] {
if (params.sort) params.sort()
let newSearch = params.toString()
newSearch = newSearch ? '?' + newSearch : ''

if (newSearch === location.search) {
// no action for no param change
return
return [false, '']
}
navigate(location.pathname + newSearch + location.hash, { replace: true })

return [true, newSearch]
}

// useURLParams returns the values for the given URL params if present, else the given defaults.
Expand All @@ -76,8 +76,7 @@ function setURLParams(
export function useURLParams<T extends Record<string, Value>>(
params: T, // <name, default> pairs
): [T, (newValues: Partial<T>) => void] {
const location = useLocation()
const navigate = useNavigate()
const [path, navigate] = useLocation()
const q = new URLSearchParams(location.search)
let called = false

Expand All @@ -102,10 +101,16 @@ export function useURLParams<T extends Record<string, Value>>(
}
}

setURLParams(navigate, location, q)
const [hasNew, search] = newSearch(q)
if (!hasNew) {
// nothing to do
return
}

navigate(path + search + location.hash, { replace: true })
}

const values = getParamValues<T>(location, params)
const values = getParamValues<T>(location.search, params)

return [values, setParams]
}
Expand All @@ -129,8 +134,7 @@ export function useURLParam<T extends Value>(
// The native history stack will not push a new entry; instead, its
// latest entry will be replaced.
export function useResetURLParams(...names: string[]): () => void {
const location = useLocation()
const navigate = useNavigate()
const [path, navigate] = useLocation()
let called = false

return function resetURLParams(): void {
Expand All @@ -150,6 +154,12 @@ export function useResetURLParams(...names: string[]): () => void {
const params = new URLSearchParams(location.search)
names.forEach((name) => params.delete(name))

setURLParams(navigate, location, params)
const [hasNew, search] = newSearch(params)
if (!hasNew) {
// nothing to do
return
}

navigate(path + search + location.hash, { replace: true })
}
}
32 changes: 0 additions & 32 deletions web/src/app/admin/AdminRouter.tsx

This file was deleted.

16 changes: 0 additions & 16 deletions web/src/app/alerts/AlertRouter.js

This file was deleted.

2 changes: 1 addition & 1 deletion web/src/app/alerts/AlertsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export default function AlertsList(props) {
}
/>
),
url: `/alerts/${a.id}`,
url: `/services/${a.service.id}/alerts/${a.id}`,
selectable: a.status !== 'StatusClosed',
})}
variables={variables}
Expand Down
4 changes: 1 addition & 3 deletions web/src/app/alerts/pages/AlertDetailPage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react'
import { gql, useQuery } from '@apollo/client'
import { useParams } from 'react-router-dom'
import { GenericError, ObjectNotFound } from '../../error-pages'
import Spinner from '../../loading/components/Spinner'
import AlertDetails from '../components/AlertDetails'
Expand Down Expand Up @@ -42,8 +41,7 @@ const query = gql`
}
`

function AlertDetailPage() {
const { alertID } = useParams()
function AlertDetailPage({ alertID }) {
const { loading, error, data } = useQuery(query, {
variables: { id: alertID },
})
Expand Down
2 changes: 1 addition & 1 deletion web/src/app/documentation/Documentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const useStyles = makeStyles({
},
})

export default function IntegrationKeyAPI(): JSX.Element {
export default function Documentation(): JSX.Element {
const [publicURL, webhookEnabled] = useConfigValue(
'General.PublicURL',
'Webhook.Enable',
Expand Down
4 changes: 2 additions & 2 deletions web/src/app/escalation-policies/PolicyCreateDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useState } from 'react'
import { gql, useMutation } from '@apollo/client'
import p from 'prop-types'
import { fieldErrors, nonFieldErrors } from '../util/errutil'
import { Navigate } from 'react-router-dom'
import FormDialog from '../dialogs/FormDialog'
import PolicyForm from './PolicyForm'
import { Redirect } from 'wouter'

const mutation = gql`
mutation ($input: CreateEscalationPolicyInput!) {
Expand Down Expand Up @@ -38,7 +38,7 @@ function PolicyCreateDialog(props) {

if (data && data.createEscalationPolicy) {
return (
<Navigate to={`/escalation-policies/${data.createEscalationPolicy.id}`} />
<Redirect to={`/escalation-policies/${data.createEscalationPolicy.id}`} />
)
}

Expand Down
4 changes: 2 additions & 2 deletions web/src/app/escalation-policies/PolicyDeleteDialog.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'
import { useMutation, gql } from '@apollo/client'
import p from 'prop-types'
import { useNavigate } from 'react-router-dom'
import FormDialog from '../dialogs/FormDialog'
import { useLocation } from 'wouter'

const mutation = gql`
mutation ($input: [TargetInput!]!) {
Expand All @@ -11,7 +11,7 @@ const mutation = gql`
`

export default function PolicyDeleteDialog(props) {
const navigate = useNavigate()
const [, navigate] = useLocation()
const [deletePolicy, deletePolicyStatus] = useMutation(mutation, {
variables: {
input: [
Expand Down
9 changes: 4 additions & 5 deletions web/src/app/escalation-policies/PolicyDetails.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useState } from 'react'
import { useQuery, gql } from '@apollo/client'
import { Navigate, useParams } from 'react-router-dom'
import _ from 'lodash'
import { Edit, Delete } from '@mui/icons-material'

Expand All @@ -15,6 +14,7 @@ import { useResetURLParams, useURLParam } from '../actions'
import { GenericError, ObjectNotFound } from '../error-pages'
import Spinner from '../loading/components/Spinner'
import { EPAvatar } from '../util/avatars'
import { Redirect } from 'wouter'

const query = gql`
query ($id: ID!) {
Expand All @@ -32,8 +32,7 @@ const query = gql`
}
`

export default function PolicyDetails() {
const { escalationPolicyID } = useParams()
export default function PolicyDetails({ policyID }) {
const stepNumParam = 'createStep'
const [createStep, setCreateStep] = useURLParam(stepNumParam, false)
const resetCreateStep = useResetURLParams(stepNumParam)
Expand All @@ -47,7 +46,7 @@ export default function PolicyDetails() {
data: _data,
} = useQuery(query, {
variables: {
id: escalationPolicyID,
id: policyID,
},
})

Expand All @@ -58,7 +57,7 @@ export default function PolicyDetails() {

if (!data) {
return showDeleteDialog ? (
<Navigate to='/escalation-policies' />
<Redirect to='/escalation-policies' />
) : (
<ObjectNotFound />
)
Expand Down
38 changes: 38 additions & 0 deletions web/src/app/escalation-policies/PolicyList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'
import { gql } from 'urql'
import SimpleListPage from '../lists/SimpleListPage'
import PolicyCreateDialog from './PolicyCreateDialog'

const query = gql`
query epsQuery($input: EscalationPolicySearchOptions) {
data: escalationPolicies(input: $input) {
nodes {
id
name
description
isFavorite
}
pageInfo {
hasNextPage
endCursor
}
}
}
`

export default function PolicyList(): JSX.Element {
return (
<SimpleListPage
query={query}
variables={{ input: { favoritesFirst: true } }}
mapDataNode={(n) => ({
title: n.name,
subText: n.description,
url: n.id,
isFavorite: n.isFavorite,
})}
createForm={<PolicyCreateDialog />}
createLabel='Escalation Policy'
/>
)
}
56 changes: 0 additions & 56 deletions web/src/app/escalation-policies/PolicyRouter.js

This file was deleted.

Loading