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

Upgrade react admin to v5 #507

Merged
merged 5 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"mathjax-react": "^2.0.1",
"next": "15.0.3",
"react": "19.0.0-rc-66855b96-20241106",
"react-admin": "^4.16.20",
"react-admin": "^5.4.0",
"react-cookie": "^4.1.1",
"react-dom": "19.0.0-rc-66855b96-20241106",
"react-dropzone": "^14.3.5",
Expand Down
7 changes: 4 additions & 3 deletions src/components/Admin/AdminLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {Home, Logout} from '@mui/icons-material/'
import {Button, Stack, Typography} from '@mui/material'
import {useRouter} from 'next/router'
import {AppBar, Layout, LayoutProps, useLogout} from 'react-admin'
import {FC, PropsWithChildren} from 'react'
import {AppBar, Layout, useLogout} from 'react-admin'

const AppMenuBar = () => {
const router = useRouter()
Expand Down Expand Up @@ -32,10 +33,10 @@ const AppMenuBar = () => {
)
}

export const AdminLayout = (props: LayoutProps) => {
export const AdminLayout: FC<PropsWithChildren> = ({children}) => {
return (
<>
<Layout {...props} appBar={AppMenuBar} />
<Layout appBar={AppMenuBar}>{children}</Layout>
<Stack
style={{
position: 'fixed',
Expand Down
15 changes: 8 additions & 7 deletions src/components/Admin/custom/MyEditActions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {FC} from 'react'
import {ListButton, ShowButton, TopToolbar, useRecordContext, useResourceContext} from 'react-admin'
import {ListButton, ShowButton, TopToolbar, useCreatePath, useRecordContext, useResourceContext} from 'react-admin'
// eslint-disable-next-line node/no-extraneous-import
import {useLocation} from 'react-router-dom'

Expand All @@ -8,20 +8,21 @@

const resource = useResourceContext()
const record = useRecordContext()
const createPath = useCreatePath()

// needed, undefined on first load
if (!record) return null

const currentPathWithoutTab = `/${resource}/${record.id}` // '/cms/post/123'
let to = `${currentPathWithoutTab}/show` // '/cms/post/123/show'
const currentPathWithoutTab = createPath({type: 'edit', resource, id: record.id}) // '/cms/post/123'
const tabPart = pathname.slice(currentPathWithoutTab.length) // bud '' alebo '/1'
if (tabPart) to = `${to}${tabPart}` // '/cms/post/123/show' alebo '/cms/post/123/show/1'
const path = createPath({type: 'show', resource, id: record.id}) // '/cms/post/123/show'
const to = `${path}${tabPart}` // '/cms/post/123/show' alebo '/cms/post/123/show/1'

return (
<TopToolbar>
{/* the `to` prop was omitted from ShowButton in recent RA version, but it's still working
and RA doesn't provide better way to do this
TODO: try again after RA upgrade */}
{/* the `to` prop is omitted from ShowButtonProps, but it's still being spread to underlying button.
we want to link to the specific show tab, not just resource show */}
{/* @ts-ignore */}

Check warning on line 25 in src/components/Admin/custom/MyEditActions.tsx

View workflow job for this annotation

GitHub Actions / branch-test

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
<ShowButton to={to} />
<ListButton label="Back to list" />
</TopToolbar>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Admin/custom/MyFileField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const MyFileField: FC = () => {

return (
<RecordContextProvider value={myRecord}>
<FileField source="src" title={myRecord.title} />
<FileField source="src" title={myRecord?.title} />
</RecordContextProvider>
)
}
10 changes: 6 additions & 4 deletions src/components/Admin/custom/MyShowActions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {FC} from 'react'
import {EditButton, ListButton, TopToolbar, useRecordContext, useResourceContext} from 'react-admin'
import {EditButton, ListButton, TopToolbar, useCreatePath, useRecordContext, useResourceContext} from 'react-admin'
// eslint-disable-next-line node/no-extraneous-import
import {useLocation} from 'react-router-dom'

Expand All @@ -8,13 +8,15 @@ export const MyShowActions: FC = () => {

const resource = useResourceContext()
const record = useRecordContext()
const createPath = useCreatePath()

// needed, undefined on first load
if (!record) return null

const currentPathWithoutTab = `/${resource}/${record.id}/show` // '/cms/post/123/show'
let to = `/${resource}/${record.id}` // '/cms/post/123'
const currentPathWithoutTab = createPath({type: 'show', resource, id: record.id}) // '/cms/post/123/show'
const tabPart = pathname.slice(currentPathWithoutTab.length) // bud '' alebo '/1'
if (tabPart) to = `${to}${tabPart}` // '/cms/post/123' alebo '/cms/post/123/1'
const path = createPath({type: 'edit', resource, id: record.id}) // '/cms/post/123'
const to = `${path}${tabPart}` // '/cms/post/123' alebo '/cms/post/123/1'

return (
<TopToolbar>
Expand Down
54 changes: 34 additions & 20 deletions src/components/Admin/dataProvider.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import axios from 'axios'
import {stringify} from 'querystring'
import {DataProvider, RaRecord} from 'react-admin'

// potencialne TODO: ak BE bude mat pagination, filter alebo sort, upravime a pouzijeme tento kod.
// zatial je pagination aj sort rieseny client-side a len pre getList, filter/search nemame.

// TODO: BE chysta search, filter, pagination a sort. ked to bude ready,
// postupne odkomentujeme tento kod a zmazeme client-side handling nizsie
// import {FilterPayload, PaginationPayload, SortPayload} from 'react-admin'

// const getPaginationQuery = ({page, perPage}: PaginationPayload) => ({
// page,
// page_size: perPage,
// offset: page,
// limit: perPage,
// })
// const getFilterQuery = ({q, ...otherSearchParams}: FilterPayload) => ({
// ...otherSearchParams,
Expand Down Expand Up @@ -40,30 +38,46 @@
// ...getOrderingQuery(params.sort),
}
const stringifiedQuery = stringify(query)
const {data} = await axios.get(`${apiUrl}/${resource}${stringifiedQuery ? `/?${stringifiedQuery}` : ''}`)
const {data} = await axios.get<any[]>(`${apiUrl}/${resource}${stringifiedQuery ? `/?${stringifiedQuery}` : ''}`)

Check warning on line 41 in src/components/Admin/dataProvider.ts

View workflow job for this annotation

GitHub Actions / branch-test

Unexpected any. Specify a different type

// client-side filter
const filter = params.filter.q
let filteredData = data
if (filter) {
// v podstate vygenerovane Copilotom :D
// vyhladava to filter string vo vsetkych fieldoch kazdeho recordu
filteredData = data.filter((record: RaRecord) => {
return Object.keys(record).some((key) => {
const value = record[key]
return value && value.toString().toLowerCase().includes(filter.toLowerCase())
if (params.filter) {
const {q: search, ...rest} = params.filter
if (search) {
// vyhladava to filter string vo vsetkych fieldoch kazdeho recordu
// - bohuzial tie fieldy su casto len IDcka inych modelov, tak nic moc :D
filteredData = data.filter((record: RaRecord) => {
const matches = Object.values(record).some((value) => {
return value && JSON.stringify(value).toLowerCase().includes(search.toLowerCase())
})
return matches
})
}

if (rest) {
filteredData = filteredData.filter((record: RaRecord) => {
return Object.entries(rest).every(([key, value]) => {
if (!value) return true
return record[key] === value
})
})
})
}
}

// client-side sort
const {field, order} = params.sort
if (params.sort) {
const {field, order} = params.sort

filteredData.sort(dynamicSort(field, order))
filteredData.sort(dynamicSort(field, order))
}

// client-side pagination
const {page, perPage} = params.pagination
const pagedData = filteredData.slice((page - 1) * perPage, page * perPage)
let pagedData = filteredData
if (params.pagination) {
const {page, perPage} = params.pagination
pagedData = filteredData.slice((page - 1) * perPage, page * perPage)
}

return {
data: pagedData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TruncatedTextField} from '@/components/Admin/custom/TruncatedTextField'

export const FlatpageList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<NumberField source="id" />
<TextField source="url" />
<TextField source="title" />
Expand Down
2 changes: 1 addition & 1 deletion src/components/Admin/resources/cms/post/PostCreate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const PostCreate: FC = () => {
<TextInput source="caption" fullWidth validate={required()} />
<TextInput source="short_text" fullWidth validate={maxLength(200, 'Text musí mať najviac 200 znakov.')} />
<TextInput source="details" multiline fullWidth />
<MyDateTimeInput source="added_at" fullWidth disabled defaultValue={new Date().toISOString()} />
{/* <MyDateTimeInput source="added_at" fullWidth disabled /> */}
<MyDateTimeInput source="visible_after" fullWidth validate={required()} />
<MyDateTimeInput source="visible_until" fullWidth validate={required()} />
<SitesCheckboxInput source="sites" validate={required()} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/Admin/resources/cms/post/PostList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {TruncatedTextField} from '@/components/Admin/custom/TruncatedTextField'

export const PostList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<TextField source="caption" />
<TruncatedTextField source="short_text" maxTextWidth={50} />
<TruncatedTextField source="details" maxTextWidth={50} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/Admin/resources/cms/post/PostShow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const PostShow: FC = () => (
<Tab label="links">
<SimpleShowLayout>
<ArrayField source="links">
<Datagrid>
<Datagrid rowClick={false}>
<TextField source="caption" />
<TextField source="url" />
</Datagrid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TruncatedTextField} from '@/components/Admin/custom/TruncatedTextField'

export const CompetitionList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<TextField source="name" />
<TextField source="slug" />
<TextField source="start_year" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const UpcomingOrCurrentEvent: FC = () => {
const record = useRecordContext()
const redirect = useRedirect()

if (!record) return null

return (
<Labeled
label="Prebiehajúca alebo najbližšia akcia"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {EventRegistration} from '@/types/api/competition'

export const EventRegistrationList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<FunctionField
source="profile.last_name"
label="Meno a priezvisko"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {DateTimeField} from '@/components/Admin/custom/DateTimeField'

export const EventList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<ReferenceField source="competition" reference="competition/competition" link={false} />
<NumberField source="year" />
<NumberField source="season_code" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const EventShow: FC = () => (
<Tab label="publications">
<SimpleShowLayout>
<ArrayField source="publication_set">
<Datagrid>
<Datagrid rowClick={false}>
<TextField source="name" />
<TextField source="file" />
<ReferenceField source="publication_type" reference="competition/publication-type" link="show">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {LatexPreview} from '@/components/Admin/custom/LatexPreview'
import {MyCreate} from '@/components/Admin/custom/MyCreate'
import {MyFileField} from '@/components/Admin/custom/MyFileField'
import {MyImageField} from '@/components/Admin/custom/MyImageField'
import {Accept} from '@/utils/dropzone-accept'

import {createProblemFormData} from './createProblemFormData'

Expand All @@ -23,10 +24,10 @@ export const ProblemCreate: FC = () => (
<TextInput source="text" multiline fullWidth validate={required()} />
<LatexPreview source="text" />
<TextInput source="order" fullWidth validate={required()} />
<ImageInput source="image" accept="image/*">
<ImageInput source="image" accept={Accept.Image}>
<MyImageField />
</ImageInput>
<FileInput source="solution_pdf" accept="application/pdf">
<FileInput source="solution_pdf" accept={Accept.Pdf}>
<MyFileField />
</FileInput>
</FormTab>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {LatexPreview} from '@/components/Admin/custom/LatexPreview'
import {MyEdit} from '@/components/Admin/custom/MyEdit'
import {MyFileField} from '@/components/Admin/custom/MyFileField'
import {MyImageField} from '@/components/Admin/custom/MyImageField'
import {Accept} from '@/utils/dropzone-accept'

import {createProblemFormData} from './createProblemFormData'

Expand All @@ -23,10 +24,10 @@ export const ProblemEdit: FC = () => (
<TextInput source="text" multiline fullWidth validate={required()} />
<LatexPreview source="text" />
<TextInput source="order" fullWidth validate={required()} />
<ImageInput source="image" accept="image/*">
<ImageInput source="image" accept={Accept.Image}>
<MyImageField />
</ImageInput>
<FileInput source="solution_pdf" accept="application/pdf">
<FileInput source="solution_pdf" accept={Accept.Pdf}>
<MyFileField />
</FileInput>
</FormTab>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {TruncatedTextField} from '@/components/Admin/custom/TruncatedTextField'

export const ProblemList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<ReferenceField source="series" reference="competition/series" link={false} />
<NumberField source="order" />
<TruncatedTextField source="text" maxTextWidth={50} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {seasonCodeStrings} from './seasonCodeStrings'

export const SemesterList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<ReferenceField source="competition" reference="competition/competition" link={false} />
<NumberField source="year" />
<FunctionField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const SemesterShow: FC = () => (
<DateTimeField source="deadline" />
<TextField source="order" />
<ArrayField source="problems">
<Datagrid>
<Datagrid rowClick={false}>
<TruncatedTextField source="text" maxTextWidth={50} />
</Datagrid>
</ArrayField>
Expand All @@ -58,10 +58,10 @@ export const SemesterShow: FC = () => (
<Tab label="publications">
<SimpleShowLayout>
<ArrayField source="publication_set">
<Datagrid>
<Datagrid rowClick={false}>
<TextField source="name" />
<TextField source="file" />
<ReferenceField source="publication_type" reference="competition/publication-type" link="show">
<ReferenceField source="publication_type" reference="competition/publication-type">
<TextField source="name" />
</ReferenceField>
<NumberField source="event" />
Expand All @@ -73,7 +73,7 @@ export const SemesterShow: FC = () => (
<Tab label="late tags">
<SimpleShowLayout>
<ReferenceArrayField source="late_tags" reference="competition/late-tag">
<Datagrid>
<Datagrid rowClick={false}>
<TextField source="name" />
<TextField source="slug" />
<TextField source="upper_bound" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {DateTimeField} from '@/components/Admin/custom/DateTimeField'

export const SeriesList: FC = () => (
<List>
<Datagrid rowClick="show">
<Datagrid>
<ReferenceField source="semester" reference="competition/semester" link={false} />
<DateTimeField source="deadline" />
<TextField source="order" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {AutocompleteInput, BooleanInput, FileInput, ReferenceInput, required, Si

import {MyCreate} from '@/components/Admin/custom/MyCreate'
import {MyFileField} from '@/components/Admin/custom/MyFileField'
import {Accept} from '@/utils/dropzone-accept'

import {createSolutionFormData} from './createSolutionFormData'

Expand All @@ -20,7 +21,7 @@ export const SolutionCreate: FC = () => (
<ReferenceInput source="semester_registration" reference="competition/event-registration">
<AutocompleteInput optionText="verbose_name" fullWidth validate={required()} />
</ReferenceInput>
<FileInput source="solution" accept="application/pdf">
<FileInput source="solution" accept={Accept.Pdf}>
<MyFileField />
</FileInput>
<ReferenceInput source="late_tag" reference="competition/late-tag" label="Je riešenie po termíne?">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {AutocompleteInput, BooleanInput, FileInput, ReferenceInput, required, Si

import {MyEdit} from '@/components/Admin/custom/MyEdit'
import {MyFileField} from '@/components/Admin/custom/MyFileField'
import {Accept} from '@/utils/dropzone-accept'

import {createSolutionFormData} from './createSolutionFormData'

Expand All @@ -20,7 +21,7 @@ export const SolutionEdit: FC = () => (
<ReferenceInput source="semester_registration" reference="competition/event-registration">
<AutocompleteInput optionText="verbose_name" fullWidth validate={required()} />
</ReferenceInput>
<FileInput source="solution" accept="application/pdf">
<FileInput source="solution" accept={Accept.Pdf}>
<MyFileField />
</FileInput>
<ReferenceInput source="late_tag" reference="competition/late-tag" label="Je riešenie po termíne?">
Expand Down
Loading
Loading