Last active
November 28, 2017 10:10
-
-
Save lwzm/7fbcadce992a7e2789bf22b75e721e67 to your computer and use it in GitHub Desktop.
ng-admin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="zh"> | |
<head> | |
<title>My Ng Admin</title> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/build/ng-admin.min.css"> | |
</head> | |
<body ng-app="myApp" ng-strict-di> | |
<div ui-view="ng-admin"></div> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/ng-admin.min.js"></script> | |
<script src="dist/bundle.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'babel-polyfill' | |
import chunk from 'lodash/map' | |
const app = angular.module('myApp', ['ng-admin']) | |
//console.log(async () => 1) | |
app.config(["$httpProvider", (http) => { | |
const myInterceptor = { | |
request: (config) => { | |
if (config.params && config.params.___strip_id_todo) { | |
delete config.params.___strip_id_todo | |
const url = config.url | |
config.url = url.slice(0, url.lastIndexOf("/")) | |
} | |
return config | |
}, | |
} | |
http.interceptors.push(() => myInterceptor) | |
}]) | |
app.config(['NgAdminConfigurationProvider', "RestangularProvider", (nga, rest) => { | |
// create an admin application | |
const admin = nga.application('test', false) | |
.baseApiUrl('/api/') | |
nga.configure(admin) | |
rest.addFullRequestInterceptor((element, operation, what, url, headers, params, httpConfig) => { | |
headers = headers || {} | |
switch (operation) { | |
case 'get': | |
case 'patch': | |
case 'remove': | |
headers["Accept"] = "application/vnd.pgrst.object+json" | |
const idKey = admin.getEntity(what).identifier().name() | |
const idValue = decodeURI(url.slice(url.lastIndexOf("/") + 1)) | |
params[idKey] = `eq.${idValue}` | |
params.___strip_id_todo = true | |
break | |
case 'getList': | |
headers['Prefer'] = "count=exact" | |
const filters = params._filters | |
delete params._filters | |
for (const key in filters) { | |
let v = filters[key] | |
if (v != null) { | |
const _ = key.split('...') | |
const k = _[0] | |
const operator = _[1] || 'eq' | |
if (v instanceof Date) { | |
v = v.toISOString() | |
} | |
params[k] = `${operator}.${v}` | |
} | |
} | |
//headers['Range-Unit'] = what | |
const p = params._page | |
const u = params._perPage | |
headers['Range'] = `${(p - 1) * u}-${p * u - 1}` | |
delete params._page | |
delete params._perPage | |
if (params._sortField) { | |
params.order = params._sortField + '.' + params._sortDir.toLowerCase() | |
delete params._sortField | |
delete params._sortDir | |
} | |
break | |
} | |
}) | |
rest.addResponseInterceptor((data, operation, what, url, response, deferred) => { | |
switch (operation) { | |
case 'getList': | |
response.totalCount = response.headers('Content-Range').split('/')[1] | |
break | |
} | |
return data | |
}) | |
const addEntity = (name, opts) => { | |
const {fields1, fields2, idToken} = opts | |
const entity = nga.entity(name).updateMethod('patch') | |
const filters = [] | |
if (!idToken) { | |
const id = nga.field('id') | |
.label("ID") | |
.pinned(true) // place ID-searching at top-right corner forever | |
fields1.unshift(id) | |
filters.unshift(id) | |
} | |
const fields = fields1.concat(fields2 || []) | |
for (const field of fields1) { // or `field of fields` | |
const name = field.name() | |
const type = field.type() | |
field.label(name) // patch it, prefer raw rather than capitalized | |
switch (type) { | |
case 'number': | |
case 'float': | |
case 'date': | |
case 'datetime': | |
filters.push(field) | |
filters.push( | |
nga.field(`${name}...gte`, type) | |
.label(`${name} >=`) | |
) | |
filters.push( | |
nga.field(`${name}...lte`, type) | |
.label(`${name} <=`) | |
) | |
break | |
case 'string': | |
case 'text': | |
case 'wysiwyg': | |
case 'email': | |
filters.push( | |
nga.field(`${name}...like`, type) | |
.label(`${name} ~=`) | |
) | |
break | |
default: | |
filters.push(field) | |
break | |
} | |
} | |
entity.listView().fields(fields1) | |
.filters(filters) | |
.perPage(10) // 10 lines is height enough, i hate scrolling | |
.exportFields(fields1) | |
entity.editionView().fields(fields) | |
entity.creationView().fields(fields) | |
// at last | |
// sortField, isDetailLink, identifier | |
if (idToken) { | |
const table = entity.listView() | |
const id = table.getField(idToken) | |
table.sortField(idToken) | |
id.isDetailLink(true) | |
entity.identifier(id) | |
} | |
admin.addEntity(entity) | |
return entity | |
} | |
/* | |
* append at here | |
* ... | |
*/ | |
const todo = addEntity("todos", { | |
fields1: [ | |
nga.field('task', 'text').isDetailLink(true).sortable(false), | |
nga.field('done', 'boolean').choices([ | |
{ value: false, label: 'false'}, | |
{ value: true, label: 'true'}, | |
]), | |
nga.field('due', 'datetime'), | |
], | |
fields2: [ | |
nga.field('others', 'json'), | |
], | |
}) | |
const user = addEntity("users", { | |
idToken: "name", | |
fields1: [ | |
nga.field('name', 'string'), | |
nga.field('password', 'string'), | |
], | |
}) | |
const zone = addEntity("zone", { | |
fields1: [ | |
nga.field('name', 'string'), | |
nga.field('beds', 'number'), | |
], | |
}) | |
const targetFiledID = nga.field('id') | |
const zoneReference = nga.field('zone', 'reference') | |
.targetEntity(zone) | |
.targetField(nga.field('name')) | |
const remoteCompleteID = { | |
searchQuery: (search) => { | |
return { | |
'id...eq': search, | |
} | |
}, | |
refreshDelay: 300, | |
} | |
const doctor = addEntity("doctor", { | |
fields1: [ | |
zoneReference, | |
nga.field('name', 'string'), | |
nga.field('info', 'json'), | |
], | |
}) | |
const patient = addEntity("patient", { | |
fields1: [ | |
nga.field('bed', 'number'), | |
nga.field('state', 'string'), | |
zoneReference, | |
nga.field('info', 'json'), | |
], | |
}) | |
const log = addEntity("log", { | |
fields1: [ | |
nga.field('datetime', 'datetime'), | |
nga.field('key', 'string'), | |
nga.field('patient', 'reference') | |
.targetEntity(patient) | |
.targetField(targetFiledID) | |
.perPage(100) | |
, | |
nga.field('info', 'json'), | |
], | |
}) | |
//const cfg = addEntity("cfg", [ | |
// nga.field('k', 'string'), | |
// nga.field('v', 'json'), | |
// nga.field('comment', 'text'), | |
//], "k") | |
const post = addEntity("posts", { | |
fields1: [ | |
nga.field('title', 'string'), | |
nga.field('content', 'wysiwyg'), | |
//nga.field('user', 'string'), | |
nga.field('user', 'reference') | |
.targetEntity(user) | |
.targetField(nga.field('name')) | |
.label("User Name") | |
.perPage(5) | |
.remoteComplete(true, { | |
searchQuery: (search) => { | |
return { | |
'name...like': `*${search}*`, | |
} | |
}, | |
refreshDelay: 300, | |
}) | |
, | |
//nga.field('d', 'reference') | |
// .targetEntity(doctor) | |
// .targetField(targetFiledID) | |
// .perPage(2) | |
// .remoteComplete(true, remoteCompleteID) | |
//, | |
], | |
}) | |
const mapdata = addEntity("mapdata", { | |
fields1: [ | |
nga.field("nid"), | |
nga.field("title"), | |
nga.field("location_type"), | |
nga.field("province_state"), | |
nga.field("city"), | |
], | |
fields2: [ | |
nga.field("address_line_1"), | |
nga.field("address_line_2"), | |
nga.field("latitude"), | |
nga.field("longitude"), | |
nga.field("hours"), | |
nga.field("tel"), | |
nga.field("otherinfo", "text"), | |
nga.field("location_id"), | |
nga.field("citycode"), | |
nga.field("locked"), | |
nga.field("lockid"), | |
nga.field("psw"), | |
], | |
}) | |
// ... | |
}]) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "my-admin", | |
"version": "1.0.0", | |
"main": "index.js", | |
"license": "MIT", | |
"scripts": { | |
}, | |
"devDependencies": { | |
"babel-core": "^6.26.0", | |
"babel-loader": "^7.1.2", | |
"babel-polyfill": "^6.26.0", | |
"babel-preset-env": "^1.6.1", | |
"webpack": "^3.8.1" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
drop table api.log; | |
drop table api.patient; | |
drop table api.doctor; | |
drop table api.zone; | |
BEGIN; | |
CREATE TABLE api.zone ( | |
id SERIAL PRIMARY KEY, | |
name TEXT NOT NULL, | |
beds INTEGER | |
); | |
CREATE TABLE api.doctor ( | |
id SERIAL PRIMARY KEY, | |
name TEXT NOT NULL UNIQUE, | |
zone INTEGER REFERENCES api.zone, | |
info JSONB | |
); | |
CREATE TABLE api.patient ( | |
id SERIAL PRIMARY KEY, | |
bed INTEGER, | |
state TEXT NOT NULL DEFAULT 'pending', | |
zone INTEGER NOT NULL REFERENCES api.zone, | |
info JSONB | |
); | |
CREATE TABLE api.log ( | |
id SERIAL PRIMARY KEY, | |
datetime TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, | |
key TEXT, | |
patient INTEGER NOT NULL REFERENCES api.patient, | |
info JSONB | |
); | |
grant all on api.zone to web_anon; | |
grant all on api.zone_id_seq to web_anon; | |
grant all on api.doctor to web_anon; | |
grant all on api.doctor_id_seq to web_anon; | |
grant all on api.patient to web_anon; | |
grant all on api.patient_id_seq to web_anon; | |
grant all on api.log to web_anon; | |
grant all on api.log_id_seq to web_anon; | |
COMMIT; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require('path') | |
module.exports = { | |
watch: true, | |
entry: './index.js', | |
output: { | |
filename: 'bundle.js', | |
path: path.resolve(__dirname, 'dist'), | |
}, | |
module: { | |
loaders: [ | |
{ | |
test: /\.(js|jsx)$/, | |
exclude: /(node_modules|bower_components)/, | |
use: { | |
loader: 'babel-loader', | |
options: { | |
presets: [ | |
'env', | |
], | |
}, | |
}, | |
}, | |
], | |
}, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment