Skip to content
Snippets Groups Projects
Commit a80629d9 authored by borzechof99's avatar borzechof99 :whale2:
Browse files

Reformatted existing Code, added Question Order View

parent 6c7521bf
Branches
No related tags found
No related merge requests found
import * as React from 'react';
import { Admin, Resource } from 'react-admin';
import { Admin, EditGuesser, ListGuesser, Resource } from 'react-admin';
import dataProviderMapper from './dataProviderMapper';
import { SportList, SportEdit, SportCreate } from './sportList';
import { IncompleteList, IncompleteEdit } from './incompleteList';
import { QuestionList, QuestionEdit, QuestionCreate } from './questionList';
import { ScraperList } from './scraperList';
import { orderList, orderEdit } from './questionOrderList';
import QuestionAnswerIcon from '@material-ui/icons/QuestionAnswer';
import SportsFootballIcon from '@material-ui/icons/SportsFootball';
......@@ -52,6 +53,11 @@ const App = () => (
options={{ label: 'Sportarten auslesen' }}
list={ScraperList}
/>
<Resource
name='question-order'
list={orderList}
/>
</Admin>
);
......
import drfProvider from 'ra-data-django-rest-framework';
import sportIncompleteProvider from './sportIncompleteProvider.js';
import scraperDataProvider from './scraperDataProvider.js';
import questionOrderProvider from './questionOrderProvider.js';
import {
GET_LIST,
GET_ONE,
......@@ -28,6 +29,10 @@ const dataProviders = [
{
dataProvider: scraperDataProvider('http://localhost:8000/api/admin'),
resources: ['sport-scraper'],
},
{
dataProvider: questionOrderProvider('http://localhost:8000/api/admin'),
resources: ['question-order'],
}
];
......@@ -50,6 +55,10 @@ export default (type, resource, params) => {
[DELETE]: 'delete',
[DELETE_MANY]: 'deleteMany',
["post_scraper"]: 'post_scraper',
["add_entry"]: 'add_entry',
["move_entry"]: 'move_entry',
["save_order"]: 'save_order',
["empty_cache"]: 'empty_cache',
};
......
import { Pagination } from 'react-admin';
// Removes the pagination field at the bottom of the page
// Used whenever flipping pages on a view might crash things
export default (props => <Pagination rowsPerPageOptions={[]} {...props} />)
\ No newline at end of file
......@@ -24,15 +24,19 @@ import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
const AsideIncompleteList = () => (
<div style={{ width: 400, margin: '1em' }}>
<div style={{
width: 400,
margin: '1em'
}}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Klicke auf die ID von dem Sport, um den gesamten Sport zu bearbeiten.</li>
......@@ -63,21 +67,34 @@ const IncompleteEditToolbar = props => (
export const IncompleteList = props => (
<List {...props} aside={<AsideIncompleteList />} bulkActionButtons={false}>
<List
{...props}
aside={<AsideIncompleteList />}
bulkActionButtons={false}>
{/* rowClick expand means that no edit page is opened, but instead shown below the data row itself without reloading */}
<Datagrid rowClick="expand" expand={IncompleteEdit} style={{ tableLayout: "fixed", }} >
<Datagrid
rowClick="expand"
expand={IncompleteEdit}
style={{ tableLayout: "fixed", }} >
{/* Reference Field fetches every Sport object if a reference field to it exists.
This means that n GETs are made for one load of the incomplete-list.
Could probably be improved in the future.
*/}
<ReferenceField label="ID" source="id" reference="sport" >
<ReferenceField
label="ID"
source="id"
reference="sport"
sortable={false}>
<ChipField source="id" />
</ReferenceField>
<TextField source="name" />
<TextField
source="name"
sortable={false}
/>
</Datagrid>
</List >
</List>
);
......@@ -96,17 +113,32 @@ export const IncompleteEdit = props => {
// mutationMode pessimistic deactivates the optimistic rendering
// Now the request will be sent first and rendered after getting the return code
return (
<Edit {...props} mutationMode="pessimistic" onSuccess={onSuccess}>
<Edit
{...props}
mutationMode="pessimistic"
onSuccess={onSuccess}
>
<SimpleForm toolbar={<IncompleteEditToolbar />}>
<Typography variant="h5" fullWidth>Fehlende Kriterien ausfüllen</Typography>
<Typography
variant="h5"
fullWidth
>
Fehlende Kriterien ausfüllen
</Typography>
{/* Documentation for formatting https://marmelab.com/react-admin/CreateEdit.html#custom-row-container */}
<TextField source="id" />
<TextField source="name" />
<ArrayInput source="criteria" label="">
<SimpleFormIterator disableAdd disableRemove>
<ArrayInput
source="criteria"
label=""
>
<SimpleFormIterator
disableAdd
disableRemove
>
{/* Documentation is wrong, look here! https://github.com/marmelab/react-admin/issues/2500
getSource() needs to get called without arguments before the return,
......@@ -131,6 +163,6 @@ export const IncompleteEdit = props => {
</SimpleFormIterator>
</ArrayInput>
</SimpleForm>
</Edit >
</Edit>
);
};
import { Pagination } from 'react-admin';
const PostPagination = props => <Pagination rowsPerPageOptions={[100, 500, 1000]} {...props} />;
\ No newline at end of file
import * as React from 'react';
import { useDataProvider, useNotify, useRedirect, Button } from 'react-admin';
import { useDataProvider, useNotify, useRedirect, Button, useUnselectAll } from 'react-admin';
export const PostScraperButton = ({ selectedIds }) => {
const notify = useNotify();
......
......@@ -18,7 +18,12 @@ const AsideQuestionList = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Klicke auf eine Datenreihe, um sie zu bearbeiten.</li>
......@@ -37,7 +42,12 @@ const AsideQuestionEdit = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Pflichtangaben sind:
......@@ -60,10 +70,18 @@ const AsideQuestionEdit = () => (
);
const AsideQuestionCreate = () => (
<div style={{ width: 400, margin: '1em' }}>
<div style={{
width: 400,
margin: '1em'
}}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Pflichtangaben sind:
......@@ -86,11 +104,28 @@ const AsideQuestionCreate = () => (
export const QuestionList = props => (
<List {...props} aside={<AsideQuestionList />}>
<Datagrid rowClick="edit" style={{ tableLayout: "fixed", }}>
<TextField source="text_de" label="Deutscher Fragetext" />
<TextField source="text_en" label="Englischer Fragetext" />
<TextField source="criterion" label="Name des Kriteriums" />
<List
{...props}
aside={<AsideQuestionList />}
>
<Datagrid
rowClick="edit"
style={{ tableLayout: "fixed", }}>
<TextField
source="text_de"
label="Deutscher Fragetext"
sortable={false}
/>
<TextField
source="text_en"
label="Englischer Fragetext"
sortable={false}
/>
<TextField
source="criterion"
label="Name des Kriteriums"
sortable={false}
/>
</Datagrid>
</List>
);
......@@ -98,12 +133,34 @@ export const QuestionList = props => (
// mutationMode pessimistic deactivates the optimistic rendering
// Now the request will be sent first and rendered after getting the return code
export const QuestionEdit = props => (
<Edit {...props} mutationMode="pessimistic" aside={<AsideQuestionEdit />}>
<Edit
{...props}
mutationMode="pessimistic"
aside={<AsideQuestionEdit />}
>
<SimpleForm>
<Typography variant="h5" fullWidth >Frage bearbeiten</Typography>
<TextInput source="text_de" label="Deutscher Fragetext" fullWidth required />
<TextInput source="text_en" label="Englischer Fragetext" fullWidth />
<TextInput source="criterion" label="Name des Kriteriums" required />
<Typography
ariant="h5"
fullWidth
>
Frage bearbeiten
</Typography>
<TextInput
source="text_de"
label="Deutscher Fragetext"
fullWidth
required
/>
<TextInput
source="text_en"
label="Englischer Fragetext"
fullWidth
/>
<TextInput
source="criterion"
label="Name des Kriteriums"
required
/>
</SimpleForm>
</Edit>
);
......@@ -112,11 +169,29 @@ export const QuestionCreate = props => (
<Create {...props} aside={<AsideQuestionCreate />}>
<SimpleForm redirect="list">
<Typography variant="h5" fullWidth >Frage erstellen</Typography>
<TextInput source="text_de" label="Deutscher Fragetext" fullWidth required />
<TextInput source="text_en" label="Englischer Fragetext" fullWidth />
<TextInput source="criterion" label="Name des Kriteriums" required />
<Typography
variant="h5"
fullWidth
>
Frage erstellen
</Typography>
<TextInput
source="text_de"
label="Deutscher Fragetext"
fullWidth
required
/>
<TextInput
source="text_en"
label="Englischer Fragetext"
fullWidth
/>
<TextInput
source="criterion"
label="Name des Kriteriums"
required
/>
</SimpleForm>
</Create>
);
\ No newline at end of file
import {
List,
Datagrid,
TextField,
NumberField,
DateField,
TopToolbar,
EditButton,
Button,
useNotify,
Edit,
SimpleForm,
ArrayInput,
SimpleFormIterator,
TextInput,
Show,
ReferenceInput,
SelectInput,
AutocompleteInput,
Toolbar,
SaveButton,
DeleteButton,
ReferenceField,
useDataProvider,
RadioButtonGroupInput,
useRefresh,
useRedirect,
useListContext,
useListParams,
} from 'react-admin';
import Typography from '@material-ui/core/Typography';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { useReducer } from 'react';
const PostShowActions = ({ basePath, data, resource }) => {
const notify = useNotify();
const refresh = useRefresh();
const dataProvider = useDataProvider();
const action = () => {
notify("Trööt");
};
const addOrderEntry = () => {
dataProvider.add_entry("question-order", {}).then(
response => {
notify("Neuen Entry Hinzugefügt!");
refresh();
}).catch(error => {
notify("Etwas ist schief gelaufen!", "warning");
});
}
const save_order = () => {
dataProvider.save_order("question-order", {}).then(
response => {
notify("Veräenderungen gespeichert!");
refresh();
}).catch(error => {
notify("Etwas ist schief gelaufen!", "warning");
});
}
const empty_cache = () => {
dataProvider.empty_cache("question-order", {}).then(
response => {
notify("Veränderungen auf Serverzustand zurückgesetzt!");
refresh();
}).catch(error => {
notify("Etwas ist schief gelaufen!", "warning");
});
}
return (
<TopToolbar>
<Button
color="primary"
onClick={addOrderEntry}
label="Eintrag Hinzufügen"
/>
<Button
color="primary"
onClick={save_order}
label="Veränderungen Speichern"
/>
<Button
color="primary"
onClick={empty_cache}
label="Veränderungen Verwerfen"
/>
</TopToolbar>
)
};
const AsideQuestionOrder = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
</CardContent>
</Card>
</div>
);
const DirEditButton = props => {
const notify = useNotify();
const refresh = useRefresh();
const dataProvider = useDataProvider();
const listContext = useListContext();
if (props.record === undefined) {
return null;
};
if (props.record.id + props.direction > listContext.total || props.record.id + props.direction < 1) {
return null;
};
const id = props.record.id;
const dir = props.direction;
const action = (props) => {
dataProvider.move_entry('question-order', { id: id, move: dir }).then(
response => {
notify("Entry Verschoben!");
refresh();
}).catch(error => {
notify("Etwas ist schief gelaufen!", "warning");
});
};
return <Button label={props.custom_label} onClick={action} />
}
export const orderList = props => {
return (
<List
{...props}
actions={<PostShowActions />}
aside={<AsideQuestionOrder />}
bulkActionButtons={false}
>
<Datagrid
rowClick="expand"
expand={orderShow}
>
<TextField
source="id"
sortable={false}
/>
<TextField
source="type"
sortable={false}
/>
<TextField
source="question_id"
sortable={false}
/>
<ReferenceField
reference="question"
source="question_id"
sortable={false}
>
<TextField source="text_de" />
</ReferenceField>
<DirEditButton direction={-1} custom_label="Hoch" sortable={false} />
<DirEditButton direction={+1} custom_label="Runter" sortable={false} />
</Datagrid>
</List>
);
};
const QuestionSensitiveField = (props) => {
console.log(props);
if (props.record.type === "question") {
return (
<Typography >
props.record.type
</Typography>
)
} else {
return (
<Typography>
"None Here!"
</Typography>
)
}
}
const OrderEditToolbar = props => {
const notify = useNotify();
const refresh = useRefresh();
const dataProvider = useDataProvider();
const deleteEntry = () => {
dataProvider.delete("question-order", { id: props.record.id }).then(
response => {
notify("Eintrag erfolgreich gelöscht!");
refresh();
}).catch(error => {
notify("Etwas ist schief gelaufen!", "warning");
});
};
return (
<Toolbar {...props} >
<SaveButton />
<Button
color="primary"
onClick={deleteEntry}
label="Eintrag Löschen"
/>
</Toolbar>
)
};
const CategoryQuestionField = (props) => {
if (props.record.type === "question") {
return (
<ReferenceInput
label="Frage"
reference="question"
source="question_id"
fullWidth
>
<SelectInput
optionText="text_de"
fullWidth
/>
</ReferenceInput>
)
} else {
return null
}
}
export const orderShow = props => (
<Edit {...props} mutationMode={"optimistic"}>
<SimpleForm toolbar={<OrderEditToolbar />}>
<RadioButtonGroupInput
source="type"
label="Eintragsart"
choices={[
{ id: "snack", name: "Wissenssnack" },
{ id: "activity", name: "Aktivität" },
{ id: "question", name: "Frage" }]}
/>
<CategoryQuestionField />
</SimpleForm>
</Edit>
);
\ No newline at end of file
import { stringify } from 'query-string';
import {
fetchUtils,
} from 'ra-core';
import { useNotify } from 'react-admin';
/*
DEFAULT DATA PROVIDER TEMPLATE
Just for copy and pasting when other data providers are needed.
*/
// export {
// default as tokenAuthProvider,
// fetchJsonWithAuthToken,
// } from './tokenAuthProvider';
// export {
// default as jwtTokenAuthProvider,
// fetchJsonWithAuthJWTToken,
// } from './jwtTokenAuthProvider';
const getPaginationQuery = (pagination) => {
return {
page: pagination.page,
page_size: pagination.perPage,
};
};
const getFilterQuery = (filter) => {
const { q: search, ...otherSearchParams } = filter;
return {
...otherSearchParams,
search,
};
};
export const getOrderingQuery = (sort) => {
const { field, order } = sort;
return {
ordering: `${order === 'ASC' ? '' : '-'}${field}`,
};
};
let cached_order = undefined;
export default (
apiUrl,
httpClient = fetchUtils.fetchJson
) => {
const getOneJson = (resource, id) =>
httpClient(`${apiUrl}/${resource}/${id}/`).then(
(response) => response.json
);
return {
getList: async (resource, params) => {
const query = {
...getFilterQuery(params.filter),
...getPaginationQuery(params.pagination),
...getOrderingQuery(params.sort),
};
console.log("cached_order in getList is: ", cached_order)
if (cached_order == undefined) {
const url = `${apiUrl}/${resource}/?${stringify(query)}`;
const { json } = await httpClient(url);
cached_order = {
data: json.results,
total: json.count,
}
return {
data: json.results,
total: json.count,
};
} else {
// Cache Already exist, so continue working on that
return cached_order;
}
},
getOne: async (resource, params) => {
const data = cached_order.data[params.id - 1];
return {
data,
};
},
getMany: (resource, params) => {
return Promise.all(
params.ids.map(id => getOneJson(resource, id))
).then(data => ({ data }));
},
getManyReference: async (resource, params) => {
const query = {
...getFilterQuery(params.filter),
...getPaginationQuery(params.pagination),
...getOrderingQuery(params.sort),
[params.target]: params.id,
};
const url = `${apiUrl}/${resource}/?${stringify(query)}`;
const { json } = await httpClient(url);
return {
data: json.results,
total: json.count,
};
},
update: async (resource, params) => {
let data = cached_order.data[params.id - 1];
data.type = params.data.type;
if (data.type !== "question") {
data.question_id = null;
} else {
data.question_id = params.data.question_id;
}
cached_order.data[params.id - 1] = data;
return { data: data };
},
updateMany: (resource, params) =>
Promise.all(
params.ids.map(id =>
httpClient(`${apiUrl}/${resource}/${id}/`, {
method: 'PATCH',
body: JSON.stringify(params.data),
})
)
).then(responses => ({ data: responses.map(({ json }) => json.id) })),
create: async (resource, params) => {
const { json } = await httpClient(`${apiUrl}/${resource}/`, {
method: 'POST',
body: JSON.stringify(params.data),
});
return {
data: { ...json },
};
},
delete: async (resource, params) => {
cached_order.data.splice(params.id - 1, 1);
cached_order.total -= 1;
for (let index = 0; index < cached_order.data.length; index++) {
cached_order.data[index].id = index + 1;
}
console.log(cached_order);
return { data: {} };
},
deleteMany: (resource, params) =>
Promise.all(
params.ids.map(id =>
httpClient(`${apiUrl}/${resource}/${id}/`, {
method: 'DELETE',
})
)
).then(responses => ({ data: responses.map(({ json }) => json.id) })),
add_entry: async (resource, params) => {
cached_order.data.push({
id: cached_order.data.length + 1,
type: "snack",
question_id: null,
});
cached_order.total += 1;
console.log(cached_order);
return { data: cached_order.data[cached_order.data.length] };
},
move_entry: async (resource, params) => {
let old_id = params.id - 1;
let new_id = params.id - 1 + params.move;
let obj = cached_order.data[old_id];
let overwritten_obj = cached_order.data[new_id];
let tmp = obj.id;
obj.id = overwritten_obj.id;
overwritten_obj.id = tmp;
cached_order.data[new_id] = obj;
cached_order.data[old_id] = overwritten_obj;
console.log(cached_order)
return { data: {} }
},
empty_cache: async (resource, params) => {
// Call Fresh Data again to Overwrite Changes
const url = `${apiUrl}/${resource}/`;
const { json } = await httpClient(url);
cached_order = {
data: json.results,
total: json.count,
}
return { data: {} };
},
save_order: async (resource, params) => {
const { json } = await httpClient(`${apiUrl}/${resource}/`, {
method: 'POST',
body: JSON.stringify(cached_order.data),
});
return { data: {} }
},
};
};
......@@ -4,6 +4,7 @@ import {
TextField,
NumberField,
DateField,
Pagination,
} from 'react-admin';
import Typography from '@material-ui/core/Typography';
......@@ -16,7 +17,12 @@ const AsideSportScrape = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>
......@@ -40,20 +46,51 @@ const AsideSportScrape = () => (
</div>
);
const ScraperPagination = props => <Pagination rowsPerPageOptions={[]} {...props} />;
{/* bulkActionButtons should theoretically be able to take a whole Fragment worth of buttons, but React hates us and we return the feeling*/ }
// perPage is set to 1000
// It is important that the page shows all entries, so that there are no issues while scrolling through the pages and sending the data afterwards
// So, all Diffs should be displayed on the same page
export const ScraperList = props => (
<List {...props} perPage={1000} bulkActionButtons={<PostScraperButton {...props} />} aside={<AsideSportScrape />}>
<List
{...props}
perPage={1000}
pagination={<ScraperPagination />}
bulkActionButtons={<PostScraperButton {...props} />}
aside={<AsideSportScrape />}
>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="kind_of_diff" label="Art der Differenz" />
<NumberField source="old_sport.id" label="Alte ID" />
<DateField source="old_sport.last_used" label="Zuletzt aktiviert" />
<TextField source="old_sport.name" label="Alter Sport" />
<TextField source="new_sport.name" label="Neuer Sport" />
<TextField
source="id"
sortable={false}
/>
<TextField
source="kind_of_diff"
label="Art der Differenz"
sortable={false}
/>
<NumberField
source="old_sport.id"
label="Alte ID"
sortable={false}
/>
<DateField
source="old_sport.last_used"
label="Zuletzt aktiviert"
sortable={false}
/>
<TextField
source="old_sport.name"
label="Alter Sport"
sortable={false}
/>
<TextField
source="new_sport.name"
label="Neuer Sport"
sortable={false}
/>
</Datagrid>
</List>
);
\ No newline at end of file
......@@ -20,13 +20,23 @@ import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import { criterionEditValidator } from './criterionEditValidator.js';
const AsideSportList = () => (
<div style={{ width: 400, margin: '1em' }}>
<div style={{
width: 400,
margin: '1em'
}}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Klicke auf eine Datenreihe, um den Eintrag zu bearbeiten.</li>
......@@ -42,10 +52,18 @@ const AsideSportList = () => (
);
const AsideSportEdit = () => (
<div style={{ width: 400, margin: '1em' }}>
<div style={{
width: 400,
margin: '1em'
}}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Der Slider "Wird aktuell angeboten" entscheidet, ob der Sport beim Quiz als Ergebnis auftreten kann.</li>
......@@ -69,15 +87,20 @@ const AsideSportEdit = () => (
</ul>
</CardContent>
</Card >
</div >
</Card>
</div>
);
const AsideSportCreate = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<Typography
variant="h4"
align="center"
>
Tipps&Tricks
</Typography>
<br />
<ul>
<li>Die Kriterien können ausgefüllt werden, nachdem der Sport erstellt wurde.
......@@ -91,14 +114,21 @@ const AsideSportCreate = () => (
export const SportList = props => (
<List {...props} aside={<AsideSportList />}>
<Datagrid rowClick="edit" style={{ tableLayout: "fixed", }}>
<Datagrid
rowClick="edit"
style={{
tableLayout: "fixed",
}}>
<TextField source="id" />
<TextField source="name" />
<UrlField source="url" />
<BooleanField source="is_filled" label="Kriterien ausgefüllt?" />
<BooleanField
source="is_filled"
label="Kriterien ausgefüllt?"
/>
</Datagrid>
</List >
</List>
);
......@@ -107,18 +137,52 @@ export const SportEdit = props => (
<Edit {...props} aside={<AsideSportEdit />}>
<SimpleForm>
<Typography variant="h4" fullWidth>Sport bearbeiten</Typography>
<TextInput disabled source="id" label="ID" />
<TextInput source="name" fullWidth required />
<TextInput source="url" label="URL" fullWidth required />
<BooleanInput source="currently_active" label="Wird aktuell angeboten" />
<DateInput disabled source="last_used" label="Zuletzt genutzt" />
<Typography variant="h5" align="left">Kriterien</Typography>
<ArrayInput source="criteria" label="">
<SimpleFormIterator disableAdd disableRemove> {/* Used because you cannot know how many objects will be sent */}
<Typography
variant="h4"
fullWidth
>
Sport bearbeiten
</Typography>
<TextInput
disabled source="id"
label="ID"
/>
<TextInput
source="name"
fullWidth
required
/>
<TextInput
source="url"
label="URL"
fullWidth
required
/>
<BooleanInput
source="currently_active"
label="Wird aktuell angeboten"
/>
<DateInput
disabled
source="last_used"
label="Zuletzt genutzt"
/>
<Typography
variant="h5"
align="left"
>
Kriterien
</Typography>
<ArrayInput
source="criteria"
label=""
>
<SimpleFormIterator
disableAdd
disableRemove
> {/* Used because you cannot know how many objects will be sent */}
{/* Documentation is wrong, look here! https://github.com/marmelab/react-admin/issues/2500
getSource() needs to get called without arguments before the return,
......@@ -151,9 +215,22 @@ export const SportEdit = props => (
export const SportCreate = props => (
<Create {...props} aside={<AsideSportCreate />}>
<SimpleForm>
<Typography variant="h4" align="left">Sport erstellen</Typography>
<TextInput source="name" fullWidth required />
<TextInput source="url" fullWidth required />
<Typography
variant="h4"
align="left"
>
Sport erstellen
</Typography>
<TextInput
source="name"
fullWidth
required
/>
<TextInput
source="url"
fullWidth
required
/>
</SimpleForm>
</Create>
);
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment