Skip to content

Commit

Permalink
feat: store params in url with qs (#1475)
Browse files Browse the repository at this point in the history
* chore: moved toggle filter drawer to redux store

* chore: unified stored list params in url

* chore: pre-fill new item with params from url

* chore: add redirectUrl to query params

* chore: removed filter button from resource action

---------

Co-authored-by: Rafal Dziegielewski <rafal.dzieg@gmail.com>
  • Loading branch information
ariansobczak-rst and dziraf committed Oct 17, 2023
1 parent 9af7a77 commit 54f218f
Show file tree
Hide file tree
Showing 24 changed files with 442 additions and 238 deletions.
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.0",
"@types/babel-core": "^6.25.7",
"@types/react": "^18.0.28",
"axios": "^1.3.4",
"commander": "^10.0.0",
"flat": "^5.0.2",
Expand All @@ -116,6 +114,7 @@
"ora": "^6.2.0",
"prop-types": "^15.8.1",
"punycode": "^2.3.0",
"qs": "^6.11.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-feather": "^2.0.10",
Expand All @@ -137,13 +136,16 @@
"@commitlint/config-conventional": "^17.4.4",
"@semantic-release/git": "^10.0.1",
"@testing-library/react": "^14.0.0",
"@types/babel-core": "^6.25.7",
"@types/chai": "^4.3.4",
"@types/chai-as-promised": "^7.1.5",
"@types/factory-girl": "^5.0.8",
"@types/flat": "^5.0.2",
"@types/lodash": "^4.14.191",
"@types/lodash": "^4.14.194",
"@types/mocha": "^10.0.1",
"@types/node": "^18.15.11",
"@types/qs": "^6.9.7",
"@types/react": "^18.0.35",
"@types/react-dom": "^18.0.11",
"@types/sinon": "^10.0.13",
"@types/sinon-chai": "^3.2.9",
Expand Down
9 changes: 4 additions & 5 deletions src/frontend/components/actions/list.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Box, Pagination, Text } from '@adminjs/design-system'
import React, { useEffect } from 'react'
import { useLocation, useNavigate } from 'react-router'
import { useLocation } from 'react-router'

import allowOverride from '../../hoc/allow-override.js'
import { useQueryParams } from '../../hooks/use-query-params.js'
import useRecords from '../../hooks/use-records/use-records.js'
import useSelectedRecords from '../../hooks/use-selected-records/use-selected-records.js'
import { getActionElementCss } from '../../utils/index.js'
Expand All @@ -28,7 +29,7 @@ const List: React.FC<ActionProps> = ({ resource, setTag }) => {
setSelectedRecords,
} = useSelectedRecords(records)
const location = useLocation()
const navigate = useNavigate()
const { storeParams } = useQueryParams()

useEffect(() => {
if (setTag) {
Expand All @@ -50,9 +51,7 @@ const List: React.FC<ActionProps> = ({ resource, setTag }) => {
const handleActionPerformed = (): any => fetchData()

const handlePaginationChange = (pageNumber: number): void => {
const search = new URLSearchParams(location.search)
search.set('page', pageNumber.toString())
navigate({ search: search.toString() })
storeParams({ page: pageNumber.toString() })
}

const contentTag = getActionElementCss(resource.id, 'list', 'table-wrapper')
Expand Down
105 changes: 70 additions & 35 deletions src/frontend/components/actions/new.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Box, Button, DrawerContent, DrawerFooter, Icon } from '@adminjs/design-system'
import pick from 'lodash/pick.js'
import React, { FC, useEffect } from 'react'
import { useNavigate } from 'react-router'

import allowOverride from '../../hoc/allow-override.js'
import { useQueryParams } from '../../hooks/use-query-params.js'
import useRecord from '../../hooks/use-record/use-record.js'
import { useTranslation } from '../../hooks/use-translation.js'
import { RecordJSON } from '../../interfaces/index.js'
Expand All @@ -15,25 +17,30 @@ import LayoutElementRenderer from './utils/layout-element-renderer.js'

const New: FC<ActionProps> = (props) => {
const { record: initialRecord, resource, action } = props
const {
record,
handleChange,
submit: handleSubmit,
loading,
setRecord,
} = useRecord(initialRecord, resource.id)
const { record, handleChange, submit, loading, setRecord } = useRecord(initialRecord, resource.id)
const { translateButton } = useTranslation()
const navigate = useNavigate()
const { parsedQuery, redirectUrl } = useQueryParams()

useEffect(() => {
if (initialRecord) {
setRecord(initialRecord)
}
}, [initialRecord])
}, [initialRecord, parsedQuery])

const submit = (event: React.FormEvent<HTMLFormElement>): boolean => {
useEffect(() => {
if (parsedQuery) {
const resourceProperties = pick(parsedQuery, Object.keys(resource.properties))
if (Object.keys(resourceProperties).length) {
setRecord({ ...record, params: { ...record.params, ...resourceProperties } })
}
}
}, [parsedQuery])

const handleSubmit = (event): boolean => {
event.preventDefault()
handleSubmit().then((response) => {
if (!event.currentTarget) return false
submit().then((response) => {
if (response.data.redirectUrl) {
navigate(appendForceRefresh(response.data.redirectUrl))
}
Expand All @@ -45,48 +52,76 @@ const New: FC<ActionProps> = (props) => {
return false
}

const handleCancel = () => {
if (redirectUrl) {
window.location.href = redirectUrl
}
}

const contentTag = getActionElementCss(resource.id, action.name, 'drawer-content')
const formTag = getActionElementCss(resource.id, action.name, 'form')
const footerTag = getActionElementCss(resource.id, action.name, 'drawer-footer')
const buttonTag = getActionElementCss(resource.id, action.name, 'drawer-submit')
const cancelButtonTag = getActionElementCss(resource.id, action.name, 'drawer-cancel')

return (
<Box
as="form"
onSubmit={submit}
flex
flexGrow={1}
onSubmit={handleSubmit}
flexDirection="column"
data-css={formTag}
>
<DrawerContent data-css={contentTag}>
{action?.showInDrawer ? <ActionHeader {...props} /> : null}
{action.layout ? action.layout.map((layoutElement, i) => (
<LayoutElementRenderer
// eslint-disable-next-line react/no-array-index-key
key={i}
layoutElement={layoutElement}
{...props}
where="edit"
onChange={handleChange}
record={record as RecordJSON}
/>
)) : resource.editProperties.map((property) => (
<BasePropertyComponent
key={property.propertyPath}
where="edit"
onChange={handleChange}
property={property}
resource={resource}
record={record as RecordJSON}
/>
))}
{action.layout
? action.layout.map((layoutElement, i) => (
<LayoutElementRenderer
// eslint-disable-next-line react/no-array-index-key
key={i}
layoutElement={layoutElement}
{...props}
where="edit"
onChange={handleChange}
record={record as RecordJSON}
/>
))
: resource.editProperties.map((property) => (
<BasePropertyComponent
key={property.propertyPath}
where="edit"
onChange={handleChange}
property={property}
resource={resource}
record={record as RecordJSON}
/>
))}
</DrawerContent>
<DrawerFooter data-css={footerTag}>
<Button variant="contained" type="submit" data-css={buttonTag} data-testid="button-save" disabled={loading}>
{loading ? (<Icon icon="Loader" spin />) : null}
{translateButton('save', resource.id)}
</Button>
<Box flex style={{ gap: 16 }}>
{redirectUrl && (
<Button
variant="light"
type="button"
onClick={handleCancel}
data-css={cancelButtonTag}
data-testid="button-cancel"
>
{translateButton('cancel', resource.id)}
</Button>
)}
<Button
variant="contained"
type="submit"
data-css={buttonTag}
data-testid="button-save"
disabled={loading}
>
{loading ? <Icon icon="Loader" spin /> : null}
{translateButton('save', resource.id)}
</Button>
</Box>
</DrawerFooter>
</Box>
)
Expand Down
49 changes: 33 additions & 16 deletions src/frontend/components/app/action-button/action-button.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/* eslint-disable no-undef */
/* eslint-disable no-alert */
/* eslint-disable no-restricted-globals */

import React, { ReactElement } from 'react'
import { stringify } from 'qs'

import { ActionResponse } from '../../../../backend/actions/action.interface.js'
import allowOverride from '../../../hoc/allow-override.js'
Expand All @@ -16,16 +13,18 @@ import { getActionElementCss } from '../../../utils/index.js'
*/
export type ActionButtonProps = {
/** Action to which button should redirect */
action: ActionJSON;
action: ActionJSON
/** Id of a resource of an action */
resourceId: string;
resourceId: string
/** Optional recordId for _record_ action */
recordId?: string;
recordId?: string
/** Optional recordIds for _bulk_ action */
recordIds?: Array<string>;
recordIds?: Array<string>
/** optional callback function which will be triggered when action is performed */
actionPerformed?: (action: ActionResponse) => any;
children?: React.ReactNode;
actionPerformed?: (action: ActionResponse) => any
children?: React.ReactNode
search?: string
queryParams?: Record<string, unknown>
}

/**
Expand All @@ -41,22 +40,40 @@ export type ActionButtonProps = {
* @subcategory Application
*/
const ActionButton: React.FC<ActionButtonProps> = (props) => {
const { children, action, actionPerformed, resourceId, recordId, recordIds } = props
const {
children,
action,
actionPerformed,
resourceId,
recordId,
recordIds,
search,
queryParams,
} = props

const { href, handleClick } = useAction(action, {
resourceId, recordId, recordIds,
}, actionPerformed)
const { href, handleClick } = useAction(
action,
{
resourceId,
recordId,
recordIds,
search: stringify(queryParams, { addQueryPrefix: true }) || search,
},
actionPerformed,
)

if (!action) {
return null
}

const firstChild = React.Children.toArray(children)[0]

if (!firstChild
if (
!firstChild
|| typeof firstChild === 'string'
|| typeof firstChild === 'number'
|| typeof firstChild === 'boolean') {
|| typeof firstChild === 'boolean'
) {
throw new Error('ActionButton has to have one child')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type ActionHeaderProps = {
/** Optional record - for _record_ actions */
record?: RecordJSON;
/** If given, action header will render Filter button */
toggleFilter?: () => any;
toggleFilter?: (() => any) | boolean;
/**
* It indicates if action without a component was performed.
*/
Expand Down

0 comments on commit 54f218f

Please sign in to comment.