Skip to content
Open
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
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ help:
@echo "release - package and upload a release"
@echo "sdist - package"

clean: clean-build clean-pyc
clean: clean-build clean-pyc clean-docs

clean-build:
rm -fr build/
Expand All @@ -23,6 +23,9 @@ clean-pyc:
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +

clean-docs:
$(MAKE) -C docs clean

lint:
flake8 rest_admin tests

Expand Down
49 changes: 49 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

const browserify = require('browserify');
const gulp = require('gulp');
const concat = require('gulp-concat');
const babel = require('gulp-babel');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
const gutil = require('gulp-util');

const path = {
SCHEMA_REACT_SRC: 'rest_admin/plugins/react/templates/rest_admin_react/schema.jsx',
SCHEMA_ES5_DEST: 'rest_admin/plugins/react/templates/rest_admin_react/es5/',
STATIC_REACT_SRC: 'rest_admin/plugins/react/static/rest_admin_react/index.js',
STATIC_ES5_DEST: 'rest_admin/plugins/react/static/rest_admin_react/es5/'
};

const BABEL_PRESETS = ['es2015', 'react', 'stage-0']

gulp.task('react_schema', () => {
return gulp.src(path.SCHEMA_REACT_SRC)
.pipe(babel({
presets: BABEL_PRESETS
}))
.pipe(gulp.dest(path.SCHEMA_ES5_DEST));
});

/*
gulp.task('react_static', () => {
return gulp.src(path.REACT_STATIC_SRC
});
*/

gulp.task('react_static', function () {

// set up the browserify instance on a task basis
const b = browserify(path.STATIC_REACT_SRC).transform('babelify', {presets: BABEL_PRESETS});

return b.bundle()
.pipe(source('index.js'))
.pipe(buffer())
//.pipe(sourcemaps.init({loadMaps: true}))
// Add transformation tasks to the pipeline here.
//.pipe(uglify())
.on('error', gutil.log)
//.pipe(sourcemaps.write('./'))
.pipe(concat('bundle.js'))
.pipe(gulp.dest(path.STATIC_ES5_DEST));
});
46 changes: 46 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "django-rest-admin",
"version": "0.1.0",
"description": "Front-end from RESTful Django Admin",
"main": "index.js",
"directories": {
"doc": "docs",
"test": "tests"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/avsd/django-rest-admin.git"
},
"author": "David Avsajanishvili",
"license": "SEE LICENSE IN ./LICENSE",
"bugs": {
"url": "https://github.com/avsd/django-rest-admin/issues"
},
"homepage": "https://github.com/avsd/django-rest-admin#readme",
"devDependencies": {
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-0": "^6.3.13",
"babelify": "^7.2.0",
"browserify": "^13.0.0",
"es6-promise": "^3.0.2",
"gulp": "^3.9.0",
"gulp-babel": "^6.1.1",
"gulp-concat": "^2.6.0",
"isomorphic-fetch": "^2.2.1",
"react": "^0.14.6",
"react-dom": "^0.14.6",
"react-intl": "^1.2.2",
"react-redux": "^4.0.6",
"react-router": "^2.0.0-rc5",
"react-router-redux": "^2.1.0",
"redux": "^3.0.6",
"redux-logger": "^2.4.0",
"redux-thunk": "^1.0.3",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
}
}
2 changes: 1 addition & 1 deletion rest_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'version.txt')) as f:
__version__ = f.read().strip()

from .core.sites import RestAdminSite, site # noqa
from .core.sites import AdminSite, site # noqa
24 changes: 20 additions & 4 deletions rest_admin/core/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,21 @@ def has_module_perms(self):
return any(filter(lambda itm: itm.module_perms, self._models))


class RestAdminSite(object):
class AdminSite(object):
"""Django REST Admin site"""

def __init__(self, admin_site, name='rest_admin'):
self.name = name
self.admin_site = admin_site

def get_apps(self, request):
"""Returns list of apps"""
"""
Converts a dictionary of registered admin instances to the dictionary
of ``DjangoApp`` instances.

The admin instances are extracted from `django.contrib.admin.sites.AdminSite` instance.

"""
app_dict = {}
for model, model_admin in self.admin_site._registry.items():
app_label = model._meta.app_label
Expand All @@ -88,6 +94,9 @@ def get_apps(self, request):
return sorted(filter(lambda itm: itm.models, app_dict.values()), key=lambda itm: itm.name)

def get_api_urls(self):
"""
Returns API urls created using Django REST Framework.
"""
from .views import AppsViewSet
from rest_framework import routers

Expand Down Expand Up @@ -148,8 +157,15 @@ def get_schema_urls(self):
return [
url('^$', RedirectView.as_view(url='/', permanent=False), name='schema-root'),
url('^index.jsx',
TemplateView.as_view(template_name='rest_admin/schema/index.jsx', content_type='text/jsx'),
TemplateView.as_view(
template_name='rest_admin_react/index.jsx',
content_type='text/jsx'),
name='index'),
url('^index.js',
TemplateView.as_view(
template_name='rest_admin_react/compiled/index.js',
content_type='text/javascript'),
name='index-compiled'),
] # TODO

def get_index_urls(self):
Expand Down Expand Up @@ -190,4 +206,4 @@ def urls(self):
# To be consistent with Django admin (see `django.contrib.admin.sites`).
# This global object represents the default admin site, for the common case.
# You can instantiate AdminSite in your own code to create a custom admin site.
site = RestAdminSite(django_admin_sites.site)
site = AdminSite(django_admin_sites.site)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/es5/
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom'


export default (props) => (
<p>
Loading...
</p>
);

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom'


export default (props) => (
<p>
You don't have permission to edit anything.
</p>
);

41 changes: 41 additions & 0 deletions rest_admin/plugins/react/static/rest_admin_react/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import ReactDOM from 'react-dom';

import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import { createStore, applyMiddleware, combineReducers } from 'redux'
import { Provider } from 'react-redux'
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
import { syncHistory, routeReducer } from 'react-router-redux'

import reducers from './modules/reducers.js'
import django_apps from './routes/django_apps/index.js'

const reducer = combineReducers(Object.assign({}, reducers, {
routing: routeReducer
}))

// Middlewares
const loggerMiddleware = createLogger()
const reduxRouterMiddleware = syncHistory(browserHistory)

const createStoreWithMiddleware = applyMiddleware(
reduxRouterMiddleware, // Sync dispatched route actions to the history
thunkMiddleware, // lets us dispatch() functions
loggerMiddleware // neat middleware that logs actions
)(createStore)

const store = createStoreWithMiddleware(reducer)

document.addEventListener("DOMContentLoaded", function(event) {
ReactDOM.render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/rest_admin/">
<IndexRoute component={django_apps.Apps} />
</Route>
</Router>
</Provider>,
document.getElementById('content')
)
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { apiGet } from '../../utils.js'

export const DJANGO_APPS_REFRESH = 'DJANGO_APPS_REFRESH';
export const DJANGO_APPS_REQUEST = 'DJANGO_APPS_REQUEST';
export const DJANGO_APPS_RECEIVE = 'DJANGO_APPS_RECEIVE';


/*
* Initiate refresh of Django admin apps and models list from the API.
*/
export function refresh() {
return { type: DJANGO_APPS_REFRESH }
}



/*
* Send asynchronous API request to fetch data about Django admin apps and models.
*/
export function request() {
return { type: DJANGO_APPS_REQUEST }
}


/*
* Process Django admin apps and models data received from the REST API.
*/
export function receive(json) {
return {
type: DJANGO_APPS_RECEIVE,
items: json,
receivedAt: Date.now()
}
}


/*
* Thunk action creator for fetching Django apps from API asynchronously.
*/
export const fetchDjangoApps = () => dispatch => {
dispatch(request());
return apiGet('apps/')
.then(json =>
dispatch(receive(json))
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
DJANGO_APPS_REFRESH,
DJANGO_APPS_REQUEST,
DJANGO_APPS_RECEIVE
} from './actions.js'


/*
* Reducer for Django apps and ModelAdmin's
*/
function django_apps(state = {
isFetching: false,
didInvalidate: false,
items: null
}, action) {
switch (action.type) {

case DJANGO_APPS_REFRESH:
return Object.assign({}, state, {
didInvalidate: true
});

case DJANGO_APPS_REQUEST:
return Object.assign({}, state, {
isFetching: true,
didInvalidate: false
});

case DJANGO_APPS_RECEIVE:
return Object.assign({}, state, {
isFetching: false,
didInvalidate: false,
items: action.items,
receivedAt: action.receivedAt
});
default:
return state
}
}

export default django_apps;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import django_apps from './django_apps/reducers.js'

export default {
django_apps
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router';


const App = ({
name,
label,
url,
children,
}) => (
<div className={'module app-LABEL'.replace('LABEL', label)}>
<table>
<caption>
<Link to={url} className="section" title={
'Models in the NAME application'.replace('NAME', name)
}>{name}</Link>
</caption>
{children}
</table>
</div>

);

App.propTypes = {
children: React.PropTypes.arrayOf(React.PropTypes.element).isRequired,
label: React.PropTypes.string.isRequired,
url: React.PropTypes.string
}

export default App
Loading