-
Notifications
You must be signed in to change notification settings - Fork 1
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
Draft: Experiment form using React #1455
base: develop
Are you sure you want to change the base?
Conversation
class ExperimentViewSet(viewsets.ModelViewSet): | ||
queryset = Experiment.objects.all() | ||
serializer_class = ExperimentSerializer | ||
permission_classes = [permissions.IsAuthenticated] | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This creates GET, GET(id), POST, PUT & DELETE endpoints for the experiment (and its relations as defined in the serializers)
@api_view(["GET"]) | ||
def playlists(request): | ||
"""Return a list of all playlists""" | ||
playlists = [{"id": playlist.id, "name": playlist.name} for playlist in Playlist.objects.all()] | ||
return Response(playlists) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used by the experiment form in react to be able to show all playlists and pick one from a multi select input
@api_view(["GET"]) | ||
def block_rules(request): | ||
"""Return a list of available block rules""" | ||
rules = [{"id": rule_id, "name": rule_class.__name__} for rule_id, rule_class in BLOCK_RULES.items()] | ||
return Response(rules) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used by the experiment form to display all rules in a select input
path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), | ||
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used by the experiment form react application to obtain a JWT token that is used to authenticate the user in Rest API requests
fields = ["id", "index", "dashboard", "randomize", "blocks"] | ||
|
||
|
||
class ExperimentSerializer(serializers.ModelSerializer): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the weak part about this setup (for now) I think. It seems to be a bit convoluted but I do think it should be able to simplify it. It's like this right now because I had to deal with different scenarios like many to many relationships, or just FKs, do the related objects have PKs already or not, and so on. Maybe a good step is just to create and save an empty experiment before you get to the form. Then at least the experiment already exists and we can remove the create
method in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we load this file and the built JS + CSS files, I think we can integrate it into the Django admin interface quite easily and maybe even remove the whole JWT mumbo jumbo.
const [jwt, setJwt] = useState<string | null>(localStorage.getItem('jwt')); | ||
|
||
const handleLogin = (newJwt: string) => { | ||
localStorage.setItem('jwt', newJwt); | ||
setJwt(newJwt); | ||
}; | ||
|
||
const handleLogout = () => { | ||
localStorage.removeItem('jwt'); | ||
setJwt(null); | ||
}; | ||
|
||
if (!jwt) { | ||
return <Login onLogin={handleLogin} />; | ||
} else { | ||
try { | ||
const payload = JSON.parse(atob(jwt.split('.')[1])); | ||
if (payload.exp && Date.now() >= payload.exp * 1000) { | ||
handleLogout(); | ||
return <Login onLogin={handleLogin} />; | ||
} | ||
} catch (error) { | ||
handleLogout(); | ||
return <Login onLogin={handleLogin} />; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is just a fairly simple way of checking if we are logged in using the JWT token in the local storage and redirect to the login page if not logged in or the JWT has expired (valid for 60 minutes right now, see the Django settings). If we build in the refresh token mechanism it'll be valid for 1 day.
…nd ESLint configuration
…or experiment forms
…ge component for consistent layout
…xperimentsOverview
…or improved URL management
…nality and user interaction
…proved form structure and usability
…prove content management
… add and delete functionality
…ntentForm for cleaner code
…n App and ExperimentsOverview
…ive tab rendering
…e translations in ExperimentForm
9e4c89c
to
efd5a61
Compare
…mproved user feedback
efa2132
to
940ffde
Compare
…ntentForm for enhanced content editing
… placeholder functionality
… translated content in blocks
…izer; implement useBlockPlaylists hook for fetching playlists
…nt playlist selection in forms
…to include blocks
…tton icon to show loading state
No description provided.