Skip to content

Commit

Permalink
Merge pull request #28 from aclowes/readonly-mode
Browse files Browse the repository at this point in the history
readonly mode
  • Loading branch information
aclowes authored Sep 16, 2017
2 parents fcde0c3 + 7b7805d commit 6737b20
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 11 deletions.
8 changes: 4 additions & 4 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {YawnNavBar, YawnNavItem} from './utilities';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {user: null, error: null, reload: false};
this.state = {user: {}, error: null, reload: false};
}

componentDidMount() {
Expand All @@ -36,7 +36,7 @@ export default class App extends React.Component {
logout = (event) => {
event.preventDefault();
API.delete(`/api/users/logout/`, {}, (payload, error) => {
this.setState({user: null, error});
this.setState({user: {}, error});
this.props.router.push('/login');
});
};
Expand All @@ -48,7 +48,7 @@ export default class App extends React.Component {
};

renderToolbar() {
const user = this.state.user && `(${this.state.user.username})`;
const userAction = this.state.user.id ? `Logout (${this.state.user.username})` : 'Login';
return (
<div>
<Nav>
Expand All @@ -62,7 +62,7 @@ export default class App extends React.Component {
<NavItem onClick={this.refresh}>
<Glyphicon glyph="refresh"/>
</NavItem>
<NavItem onClick={this.logout}>Logout {user}</NavItem>
<NavItem onClick={this.logout}>{userAction}</NavItem>
</Nav>
</div>
)
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/WorkflowDetailForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ export default class WorkflowDetailForm extends React.Component {
handleSubmit = (event) => {
const update = formValues(this.state);
API.patch(`/api/workflows/${this.props.workflow.id}/`, update, (payload, error) => {
this.setState({...formValues(payload), error, editable: false});
// if there is an error, don't parse the payload
const form = error ? {} : formValues(payload);
this.setState({...form, error, editable: false});
});
event.preventDefault();
};
Expand Down Expand Up @@ -131,4 +133,4 @@ export default class WorkflowDetailForm extends React.Component {
)
}
}
}
}
3 changes: 1 addition & 2 deletions frontend/src/tests/__snapshots__/App.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ exports[`homepage renders 1`] = `
onClick={[Function]}
role="button"
>
Logout
(test user)
Login
</a>
</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# Versions should comply with PEP440. For a discussion on single-sourcing
# the version across setup.py and the project code, see
# https://packaging.python.org/en/latest/single_source_version.html
version='0.1.6',
version='0.1.7',

description='Yet Another Workflow Engine, a subprocess-based DAG execution system',
long_description=long_description,
Expand Down
9 changes: 8 additions & 1 deletion yawn/user/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from rest_framework.decorators import list_route
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework.settings import api_settings

from yawn.user.permissions import ModelPermissions
from .serializers import UserSerializer, LoginSerializer


Expand All @@ -15,12 +17,17 @@ class UserViewSet(viewsets.GenericViewSet,
viewsets.mixins.UpdateModelMixin):
"""
User endpoint, GET(list, detail), PATCH to change
This ViewSet has `permission_classes` set and `/me/` has the default permissions
so that the default permission class can be set to IsAuthenticatedOrReadOnly
without leaking user API tokens.
"""
queryset = User.objects.all().order_by('id')

serializer_class = UserSerializer
permission_classes = (ModelPermissions,)

@list_route(methods=['get'])
@list_route(methods=['get'], permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES)
def me(self, request):
serializer = self.get_serializer(request.user)
return Response(serializer.data)
Expand Down
10 changes: 9 additions & 1 deletion yawn/worker/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import typing # NOQA
import collections

import time
from django.db import transaction
from django.db.models import functions

Expand Down Expand Up @@ -43,14 +44,16 @@ def run(self):
Main event loop.
Why not threads/gevent/asyncio?
Because this is simple and maybe even more efficient!
Because this is simple and maybe more efficient
"""
self.handle_signals()
self.executor = Manager()
self.state = State.running
loop_start = time.time()
logger.warning('Starting YAWN worker with concurrency=%s', self.concurrency)

while True:

if self.state == State.running:

# update own status and check for lost workers
Expand All @@ -72,6 +75,11 @@ def run(self):
self.results.extend(self.executor.read_output())
self.save_results()

# don't run the loop more than once per second
loop_duration = time.time() - loop_start
time.sleep(max(1 - loop_duration, 0))
loop_start += loop_duration

logger.warning('Exiting')
self.worker.status = Worker.EXITED
self.worker.save()
Expand Down

0 comments on commit 6737b20

Please sign in to comment.