1. refactored to use get/set instead of raw lens

2. updated webpack dev config to use python proxy api server
master
Malar Kannan 2017-07-19 16:53:24 +05:30
parent 3cc73e5404
commit c6c8655649
9 changed files with 134 additions and 65 deletions

View File

@ -17,6 +17,7 @@ const getClientEnvironment = require('./env');
const paths = require('./paths'); const paths = require('./paths');
// Webpack uses `publicPath` to determine where the app is being served from. // Webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path. // It requires a trailing slash, or the file assets will get an incorrect path.
// const publicPath = 'http://localhost:3000/';
const publicPath = paths.servedPath; const publicPath = paths.servedPath;
// Some apps do not use client-side routing with pushState. // Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths. // For these, "homepage" can be set to "." to enable relative asset paths.

View File

@ -77,7 +77,9 @@ module.exports = function(proxy, allowedHost) {
disableDotRule: true, disableDotRule: true,
}, },
public: allowedHost, public: allowedHost,
proxy, proxy: {
"/api":"http://localhost:5000/"
},
setup(app) { setup(app) {
// This lets us open files from the runtime error overlay. // This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware()); app.use(errorOverlayMiddleware());

View File

@ -113,13 +113,11 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
// } // }
// ); // );
startWebPackDevServer(()=>{ startWebPackDevServer(()=>{
// child_process.spawn('webpack',['--watch','--config','config/webpack.config.flask.js'],{
// stdio:'inherit'
// });
child_process.spawn('python',['walle_server.py'],{ child_process.spawn('python',['walle_server.py'],{
stdio:'inherit' stdio:'inherit'
}); });
}); });
// Create the production build and print the deployment instructions. // Create the production build and print the deployment instructions.
function build(previousFileSizes) { function build(previousFileSizes) {
console.log('Creating an optimized production build...'); console.log('Creating an optimized production build...');
@ -169,10 +167,11 @@ function copyPublicFolder() {
function startWebPackDevServer(pyServer){ function startWebPackDevServer(pyServer){
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0'; const HOST = process.env.HOST || '0.0.0.0';
fs.emptyDirSync(paths.appBuild); // fs.emptyDirSync(paths.appBuild);
fs.ensureSymlink(paths.appPng,path.resolve(paths.appBuild,'png')); // fs.ensureSymlink(paths.appPng,path.resolve(paths.appBuild,'png'));
// Merge with the public folder // // Merge with the public folder
copyPublicFolder(); // copyPublicFolder();
// We attempt to use the default port but if it is busy, we offer the user to // We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `detect()` Promise resolves to the next free port. // run on a different port. `detect()` Promise resolves to the next free port.
choosePort(HOST, DEFAULT_PORT) choosePort(HOST, DEFAULT_PORT)
@ -201,8 +200,9 @@ function startWebPackDevServer(pyServer){
} }
if (isInteractive) { if (isInteractive) {
clearConsole(); clearConsole();
const urls = prepareUrls(protocol, HOST, '5000'); const pyurls = prepareUrls(protocol, HOST, '5000');
pyServer(); pyServer();
// openBrowser(pyurls.localUrlForBrowser);
openBrowser(urls.localUrlForBrowser); openBrowser(urls.localUrlForBrowser);
} }
}); });

View File

@ -27,7 +27,7 @@ export class Main extends React.Component<any, any> {
</Header.Content> </Header.Content>
</Header> </Header>
</Segment> </Segment>
<LexSetup {...this.props} fileName="/new_es.xml"/> <LexSetup {...this.props} fileName="/new_es_orig.xml"/>
</div> </div>
); );
} }

View File

@ -13,7 +13,7 @@ const { Box } = require('reflexbox');
const serialize = function(obj: any) { const serialize = function(obj: any) {
var str = []; var str = [];
for(var p in obj){ for (var p in obj) {
if (obj.hasOwnProperty(p)) { if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p])); str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
} }
@ -29,15 +29,14 @@ export class LexEdit extends React.Component<any, any> {
} }
public render() { public render() {
let li = this.state.lexItem; let li = this.state.lexItem;
let editLang = _.get<any>(li, this.props.fieldMetaMap.lang.lens, 'en'); let editLang = this.props.fieldMetaMap.lang.get(li);
let langSelOpts = _.get<any>(this.props.selectionMeta, editLang, []); let langSelOpts = _.get<any>(this.props.selectionMeta, editLang, []);
let lexFields = _.keys(this.props.fieldMetaMap).map(field => { let lexFields = _.keys(this.props.fieldMetaMap).map(field => {
let lens = this.props.fieldMetaMap[field].lens; let fieldMeta = this.props.fieldMetaMap[field];
let defaultText = _.get<any>(li, lens, ''); let defaultText = fieldMeta.get(li);
let originalText = _.get<any>(this.props.lexItem, lens, ''); let originalText = fieldMeta.get(this.props.lexItem);
let options = this.props.fieldMetaMap[field].options; let options = fieldMeta.options;
let changed = defaultText !== originalText && this.props.existing; let changed = defaultText !== originalText && this.props.existing;
// console.log('changed:',changed);
let sh = (e: any) => { let sh = (e: any) => {
let eventData = {}; let eventData = {};
eventData[field] = e.target.value; eventData[field] = e.target.value;
@ -48,10 +47,10 @@ export class LexEdit extends React.Component<any, any> {
return textInput(params); return textInput(params);
} else if (this.props.fieldMetaMap[field].type === 'select') { } else if (this.props.fieldMetaMap[field].type === 'select') {
return selectInput(params); return selectInput(params);
} else if (this.props.fieldMetaMap[field].type === 'preview' } else if (this.props.fieldMetaMap[field].type === 'preview') {
&& defaultText !== '') {
return imagePreview(params); return imagePreview(params);
} else { } else {
console.log('field discarded :', field);
return null; return null;
} }
}); });
@ -103,14 +102,18 @@ export class LexEdit extends React.Component<any, any> {
private handleOnLoad(event: any) { private handleOnLoad(event: any) {
// this.props.load(this.state.lexItem) // this.props.load(this.state.lexItem)
let lexItem = this.props.lexItem; let li = this.state.lexItem;
let word = _.get<any>(lexItem, this.props.fieldMetaMap.label.lens, ''); let word = this.props.fieldMetaMap.label.get(li);
let pos = _.get<any>(lexItem, this.props.fieldMetaMap.pos.lens, ''); let pos = this.props.fieldMetaMap.pos.get(li);
let args = serialize({word,pos}); let args = serialize({ word, pos });
fetch('/morph?'+args) let morphQuery = '/api/morph?' + args;
fetch(morphQuery)
.then((response) => response.text()) .then((response) => response.text())
.then((jsonMorph) => { .then((jsonMorph) => {
console.log(jsonMorph); let morphDict = JSON.parse(jsonMorph);
let morphMeta = this.props.fieldMetaMap.morphclass;
let lexItem = morphMeta.set(this.state.lexItem, morphDict.morphclass);
this.setState({ lexItem });
}) })
.catch((e) => { .catch((e) => {
console.log('errored :', e); console.log('errored :', e);
@ -119,10 +122,9 @@ export class LexEdit extends React.Component<any, any> {
private handleOnChange(event: any) { private handleOnChange(event: any) {
let type = _.keys(event)[0]; let type = _.keys(event)[0];
let value = _.values(event)[0]; let value = _.values(event)[0] as string;
let lens = this.props.fieldMetaMap[type].lens; let meta = this.props.fieldMetaMap[type];
let lexItem = _.cloneDeep(this.state.lexItem); let lexItem = meta.set(this.state.lexItem, value);
_.set(lexItem, lens, value);
this.setState({ lexItem }); this.setState({ lexItem });
} }

View File

@ -10,10 +10,10 @@ const { Flex } = require('reflexbox');
// container component // container component
export class LexEditor extends React.Component<any, any> { export class LexEditor extends React.Component<any, any> {
public render() { public render() {
let searchLens = this.props.fieldMetaMap[this.props.searchState.searchType].lens; let searchMeta = this.props.fieldMetaMap[this.props.searchState.searchType];
let searchText = this.props.searchState.searchValue; let searchText = this.props.searchState.searchValue;
let matchedEntries = _.chain(this.props.allEntries) let matchedEntries = _.chain(this.props.allEntries)
.filter((q: any) => _.get<any>(q, searchLens, '') === searchText) .filter((q: any) => searchMeta.get(q) === searchText)
.take(10) .take(10)
.value(); .value();
let { fieldMetaMap: fieldMetaMap, save: save } = this.props; let { fieldMetaMap: fieldMetaMap, save: save } = this.props;
@ -27,7 +27,7 @@ export class LexEditor extends React.Component<any, any> {
matchedEntries={matchedEntries} matchedEntries={matchedEntries}
selectionMeta={this.props.selectFields} selectionMeta={this.props.selectFields}
searchText={searchText} searchText={searchText}
searchLens={searchLens} searchMeta={searchMeta}
/> />
</div> </div>
); );
@ -91,8 +91,7 @@ function LexMatches(params: any) {
/> />
); );
}); });
let addProps = {}; let addProps = props.searchMeta.set({}, props.searchText);
_.set(addProps, props.searchLens, props.searchText);
let addEntry = ( let addEntry = (
<LexEdit <LexEdit
{...props} {...props}

View File

@ -4,21 +4,79 @@ import * as XML from 'xml2js';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { LexEditor } from './LexEditor'; import { LexEditor } from './LexEditor';
function simpleAccessor(lens: string, def: string = '') {
return {
get: (li: any) => {
let val = _.get<any>(li, lens, def);
return val;
},
set: (li: any, value: string) => {
let lexItem = _.cloneDeep(li);
let ret = _.set<any>(lexItem, lens, value);
return ret;
}
};
}
const fieldMetaMap = { const fieldMetaMap = {
label: { lens: 'label[0]', type: 'text' }, label: {
unl: { lens: 'unl[0]', type: 'text' }, type: 'text',
synset: { lens: 'lexprops[0].wnsynset[0]', type: 'text' }, ...simpleAccessor('label[0]'),
guid: { lens: 'guid[0]', type: 'text' },
pos: { lens: 'pos[0]', type: 'select' },
image: { lens: 'image[0]', type: 'preview' },
relations: { lens: 'relations[0]', type: 'text' },
frame: { lens: 'syntacticprops[0].property[0]._', type: 'select' },
morphclass: {
lens: 'lexprops[0].morphology[0].morph[0]._',
type: 'select'
}, },
stats: { lens: 'stats[0].property[0]._', type: 'text' }, unl: { type: 'text', ...simpleAccessor('unl[0]'), },
lang: { lens: '$.id', type: 'select', options: ['en', 'es'] }, synset: { type: 'text', ...simpleAccessor('lexprops[0].wnsynset[0]'), },
guid: { type: 'text', ...simpleAccessor('guid[0]'), },
pos: { type: 'select', ...simpleAccessor('pos[0]'), },
image: { type: 'text', ...simpleAccessor('image[0]'), },
relations: { type: 'text', ...simpleAccessor('relations[0]'), },
frame: { type: 'select', ...simpleAccessor('syntacticprops[0].property[0]._'), },
morphclass: {
type: 'select',
get: (li: any) => {
let lens = 'lexprops[0].morphology[0].morph';
let def = [{ _: '', $: { form: 'morphclass' } }];
let morphProps = _.get<any>(li, lens, def);
let prop = _.filter<any>(morphProps, (m) => {
return m.$.form === 'morphclass';
});
let mcls = _.get<any>(prop, '[0]._', '');
return mcls;
},
set: (li: any, value: string) => {
let lexItem = _.cloneDeep(li);
let lens = 'lexprops[0].morphology[0].morph';
let morphProps = _.get<any>(lexItem, lens, []);
if (morphProps.length > 0) {
let prop = _.filter<any>(morphProps, (m) => {
return m.$.form === 'morphclass';
});
if (prop.length > 0) {
_.set(prop[0], '_', value);
} else {
let def = { _: value, $: { form: 'morphclass' } };
morphProps.push(def);
}
} else {
let def = [{ _: value, $: { form: 'morphclass' } }];
_.set(lexItem, lens, def);
}
return lexItem;
}
},
morphexceptions: {
type: 'list',
get: (li: any) => {
let lens = 'lexprops[0].morphology[0].morph';
let def = [{ _: 'M0', $: { form: 'morphclass' } }];
let morphProps = _.get<any>(li, lens, def);
let morphExps = _.filter<any>(morphProps, (m) => {
return m.$.form !== 'morphclass';
});
return morphExps;
}
},
stats: { type: 'text', ...simpleAccessor('stats[0].property[0]._'), },
lang: { type: 'select', options: ['en', 'es'], ...simpleAccessor('$.id', 'en'), },
}; };
const xmlToEntries = (xmlData: any) => { const xmlToEntries = (xmlData: any) => {
@ -34,7 +92,7 @@ const xmlToEntries = (xmlData: any) => {
) )
.value(); .value();
let langReducer = ((result: any, q: any) => { let langReducer = ((result: any, q: any) => {
let lang = _.get<any>(q, fieldMetaMap.lang.lens, 'en'); let lang = fieldMetaMap.lang.get(q);
(result[lang] || (result[lang] = [])).push(q); (result[lang] || (result[lang] = [])).push(q);
return result; return result;
}); });
@ -44,10 +102,9 @@ const xmlToEntries = (xmlData: any) => {
let langOpts = _.fromPairs(_.keys(fieldMetaMap).filter((s) => { let langOpts = _.fromPairs(_.keys(fieldMetaMap).filter((s) => {
return fieldMetaMap[s].type === 'select'; return fieldMetaMap[s].type === 'select';
}).map((s) => { }).map((s) => {
let lens = fieldMetaMap[s].lens;
let entries = _.get<any>(langEntries, lang, 'en'); let entries = _.get<any>(langEntries, lang, 'en');
let selectOptions = _.uniq(entries.map((q: any) => { let selectOptions = _.uniq(entries.map((q: any) => {
return _.get<any>(q, lens, ''); return fieldMetaMap[s].get(q);
})); }));
return [s, selectOptions]; return [s, selectOptions];
})); }));
@ -78,12 +135,15 @@ export class LexSetup extends React.Component<any, any> {
} }
render() { render() {
return this.state.xmlLoaded ? ( let dimmer = (
<LexEditor {...xmlToEntries(this.props.xmlData)} {...this.props} /> <Dimmer active={true} inverted={true}>
) : ( <Loader inverted={true}>Loading</Loader>
<Dimmer active={true} inverted={true}> </Dimmer>
<Loader inverted={true}>Loading</Loader> );
</Dimmer> let xmlEntries = xmlToEntries(this.props.xmlData);
); let editor = (
<LexEditor {...xmlEntries} {...this.props} />
);
return this.state.xmlLoaded ? editor : dimmer;
} }
} }

View File

@ -82,9 +82,9 @@ export function selectInput(params: any) {
export function imagePreview(params: any) { export function imagePreview(params: any) {
let { field, defaultText, changed } = params; let { field, defaultText, changed } = params;
let imageSrc = imageRoot + defaultText; let imageSrc = imageRoot + defaultText;
return ( return defaultText !== '' ? (
<LexSingleInput key={field} label={changedLabel(changed, field)}> <LexSingleInput key={field} label={changedLabel(changed, field)}>
<Image src={imageSrc} size="tiny" bordered={true} /> <Image src={imageSrc} size="tiny" bordered={true} />
</LexSingleInput> </LexSingleInput>
); ) : null;
} }

View File

@ -1,22 +1,27 @@
from flask import Flask,send_from_directory,request from flask import Flask,send_from_directory,request
app = Flask(__name__,static_url_path='',static_folder='build') app = Flask(__name__,static_url_path='',static_folder='build')
from freespeech_walle.get_morph_rule import get_morph # from freespeech_walle.get_morph_rule import get_morph
from freespeech_walle.wizard_helpers import get_morph_rule,get_frequency
import json import json
# from flask_cors import CORS, cross_origin
# CORS(app)
@app.route('/') @app.route('/')
def walle_index(): def walle_index():
return app.send_static_file('index.html') return app.send_static_file('index.html')
@app.route('/test') @app.route('/api/test')
def walle_test(): def walle_test():
return "test" return "test"
@app.route('/morph') @app.route('/api/morph')
def walle_morph(): def walle_morph():
word = request.args.get('word') word = request.args.get('word','water')
pos = request.args.get('pos') pos_req = request.args.get('pos','N')
return json.dumps(get_morph(word,pos)) pos = pos_req if pos_req != '' else 'N';
return json.dumps(get_morph_rule.get_morph(word,pos))
# hmr streaming # hmr streaming
# import requests # import requests