hippo-fw 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/client/hippo/__mocks__/config.js +4 -4
- data/client/hippo/boot.jsx +8 -8
- data/client/hippo/components/form.jsx +1 -2
- data/client/hippo/components/form/wrapper.jsx +20 -8
- data/client/hippo/config.android.js +8 -0
- data/client/hippo/config.ios.js +8 -0
- data/client/hippo/config.js +5 -71
- data/client/hippo/lib/pub_sub.js +34 -0
- data/client/hippo/models/base.js +6 -6
- data/client/hippo/models/config.js +60 -0
- data/client/hippo/models/pub_sub.js +157 -0
- data/client/hippo/models/pub_sub/channel.js +35 -0
- data/client/hippo/screens/definition.js +1 -1
- data/client/hippo/screens/index.js +2 -10
- data/client/hippo/screens/user-management/edit-form.jsx +10 -7
- data/client/hippo/user.js +1 -3
- data/client/hippo/workspace/index.jsx +16 -15
- data/client/hippo/workspace/menu.jsx +2 -8
- data/client/hippo/workspace/screen.jsx +6 -6
- data/config/database.yml +1 -0
- data/config/routes.rb +4 -4
- data/config/webpack.config.js +18 -16
- data/hippo-fw.gemspec +2 -2
- data/lib/hippo.rb +1 -3
- data/lib/hippo/api.rb +1 -0
- data/lib/hippo/api/cable.rb +19 -20
- data/lib/hippo/api/handlers/user_session.rb +1 -1
- data/lib/hippo/api/pub_sub.rb +7 -5
- data/lib/hippo/api/routing.rb +1 -1
- data/lib/hippo/api/updates.rb +1 -1
- data/lib/hippo/concerns/api_path.rb +2 -3
- data/lib/hippo/configuration.rb +2 -0
- data/lib/hippo/rails.rb +9 -0
- data/lib/hippo/user.rb +2 -1
- data/lib/hippo/version.rb +1 -1
- data/package-lock.json +6823 -0
- data/package.json +43 -34
- data/spec/client/models/pub_sub.spec.js +27 -0
- data/templates/js/config-data.js +1 -1
- data/templates/js/screen-definitions.js +2 -2
- data/yarn.lock +307 -15
- metadata +28 -9
- data/client/extension.js +0 -0
- data/client/hippo/models/PubSub.js +0 -208
- data/lib/generators/hippo/migrations/install_generator.rb +0 -42
- data/lib/hippo/rails_engine.rb +0 -5
@@ -0,0 +1,35 @@
|
|
1
|
+
import { omit } from 'lodash';
|
2
|
+
|
3
|
+
import { logger } from '../../lib/util';
|
4
|
+
import { BaseModel } from '../base';
|
5
|
+
|
6
|
+
const CHANNEL_SPLITTER = new RegExp('^(.*):(.*)/([^/]+)$');
|
7
|
+
|
8
|
+
export default class PubSubCableChannel {
|
9
|
+
|
10
|
+
constructor(pub_sub) {
|
11
|
+
this.channel = pub_sub.cable.subscriptions.create(
|
12
|
+
'pubsub', this,
|
13
|
+
);
|
14
|
+
this.pub_sub = pub_sub;
|
15
|
+
}
|
16
|
+
|
17
|
+
subscribe(channel) {
|
18
|
+
logger.info(`[pubsub] subscribe to: ${channel}`);
|
19
|
+
this.channel.perform('on', { channel });
|
20
|
+
}
|
21
|
+
|
22
|
+
unsubscribe(channel) {
|
23
|
+
logger.info(`[pubsub] unsubscribe from: ${channel}`);
|
24
|
+
this.channel.perform('off', { channel });
|
25
|
+
}
|
26
|
+
|
27
|
+
received(data) {
|
28
|
+
const [channel, _, modelId, id] = Array.from(
|
29
|
+
data.channel.match(CHANNEL_SPLITTER),
|
30
|
+
);
|
31
|
+
logger.info(`[pubsub] change recvd for: ${channel}`);
|
32
|
+
const model = BaseModel.findDerived(modelId);
|
33
|
+
this.pub_sub.onModelChange(model, id, omit(data, 'channel'));
|
34
|
+
}
|
35
|
+
}
|
@@ -8,7 +8,7 @@ import Instance, { displaying } from './instance';
|
|
8
8
|
import Registry from './index';
|
9
9
|
import Group from './group';
|
10
10
|
|
11
|
-
export {
|
11
|
+
export { asyncComponent } from 'react-async-component';
|
12
12
|
|
13
13
|
@identifiedBy('hippo/screen/definition')
|
14
14
|
export default class ScreenDefinition extends BaseModel {
|
@@ -7,8 +7,6 @@ const Screens = observable({
|
|
7
7
|
|
8
8
|
all: observable.map(),
|
9
9
|
|
10
|
-
active_screen_ids: observable.array(),
|
11
|
-
|
12
10
|
get activeGroups() {
|
13
11
|
const gids = Group.enabled_group_ids || map(Group.all, 'id');
|
14
12
|
const groups = map(gids, gid => Group.forId(gid));
|
@@ -16,19 +14,13 @@ const Screens = observable({
|
|
16
14
|
},
|
17
15
|
|
18
16
|
@computed get active() {
|
19
|
-
return map(
|
20
|
-
},
|
21
|
-
|
22
|
-
configure(screen_ids) {
|
23
|
-
this.active_screen_ids.replace(screen_ids);
|
17
|
+
return map(Config.screen_ids, id => this.all.get(id));
|
24
18
|
},
|
25
19
|
|
26
20
|
reset() {
|
27
|
-
|
21
|
+
Config.screen_ids.clear();
|
28
22
|
},
|
29
23
|
|
30
24
|
});
|
31
25
|
|
32
|
-
Config.screens = Screens;
|
33
|
-
|
34
26
|
export default Screens;
|
@@ -1,10 +1,9 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import { Row, Col } from 'react-flexbox-grid';
|
4
|
-
import { isNil, forIn, get, pick, mapValues, keys, extend } from 'lodash';
|
5
4
|
|
6
5
|
import { observer } from 'mobx-react';
|
7
|
-
import { action
|
6
|
+
import { action } from 'mobx';
|
8
7
|
|
9
8
|
import Box from 'grommet/components/Box';
|
10
9
|
import Button from 'grommet/components/Button';
|
@@ -29,7 +28,6 @@ export default class EditForm extends React.PureComponent {
|
|
29
28
|
|
30
29
|
constructor(props) {
|
31
30
|
super(props);
|
32
|
-
|
33
31
|
this.user = this.props.query.results.modelForRow(this.props.rowIndex);
|
34
32
|
}
|
35
33
|
|
@@ -39,7 +37,7 @@ export default class EditForm extends React.PureComponent {
|
|
39
37
|
|
40
38
|
@action.bound
|
41
39
|
onSave() {
|
42
|
-
this.
|
40
|
+
this.refs.form.persistTo(this.user);
|
43
41
|
this.user.save().then(this.onSaved);
|
44
42
|
}
|
45
43
|
|
@@ -59,16 +57,21 @@ export default class EditForm extends React.PureComponent {
|
|
59
57
|
|
60
58
|
render() {
|
61
59
|
return (
|
62
|
-
<Form
|
60
|
+
<Form
|
61
|
+
tag="div"
|
62
|
+
ref="form"
|
63
|
+
model={this.user}
|
64
|
+
className="user-edit-form"
|
65
|
+
>
|
63
66
|
<Warning message={this.errorMessage} />
|
64
67
|
<Row middle='sm'>
|
65
68
|
<Field md={4} xs={6} name="login" validate={nonBlank} />
|
66
|
-
<Field md={4} xs={6} name="name"
|
69
|
+
<Field md={4} xs={6} name="name" validate={nonBlank} />
|
67
70
|
<Field md={4} xs={6} name="email" validate={validEmail} />
|
68
71
|
<Field md={4} xs={6} type="password" name="password" />
|
69
72
|
<Field md={4} xs={6} type="checkbox" name="is_admin" validate={booleanValue} />
|
70
73
|
<Col md={4} xs={6}>
|
71
|
-
<Box
|
74
|
+
<Box direction="row">
|
72
75
|
<Button label="Cancel" onClick={this.onCancel} accent />
|
73
76
|
<Button
|
74
77
|
label="Save"
|
data/client/hippo/user.js
CHANGED
@@ -73,9 +73,7 @@ export class UserModel extends BaseModel {
|
|
73
73
|
setFromSessionRequest(req) {
|
74
74
|
merge(this, pick(req, 'errors', 'lastServerMessage'));
|
75
75
|
if (req.isValid) {
|
76
|
-
Config.
|
77
|
-
Config.persistToStorage();
|
78
|
-
Config.bootstrapUserData();
|
76
|
+
Config.update(req.data);
|
79
77
|
this.errors = {};
|
80
78
|
}
|
81
79
|
return this;
|
@@ -3,9 +3,13 @@ import React from 'react';
|
|
3
3
|
import { action, observable } from 'mobx';
|
4
4
|
import { observer } from 'mobx-react';
|
5
5
|
import { bindAll } from 'lodash';
|
6
|
-
import {
|
6
|
+
import {
|
7
|
+
BrowserRouter as Router,
|
8
|
+
Route,
|
9
|
+
} from 'react-router-dom';
|
7
10
|
|
8
|
-
|
11
|
+
|
12
|
+
import App from 'grommet/components/App';
|
9
13
|
import Sidebar from 'react-sidebar';
|
10
14
|
|
11
15
|
import 'hippo/config-data';
|
@@ -19,6 +23,12 @@ import './styles.scss';
|
|
19
23
|
|
20
24
|
const DOCKED_WIDTH_BREAKPOINT = 950;
|
21
25
|
|
26
|
+
function NoMatch() {
|
27
|
+
return (
|
28
|
+
<h1>Not Found</h1>
|
29
|
+
);
|
30
|
+
}
|
31
|
+
|
22
32
|
@observer
|
23
33
|
class Workspace extends React.Component {
|
24
34
|
|
@@ -59,27 +69,18 @@ class Workspace extends React.Component {
|
|
59
69
|
docked={this.sidebarDocked}
|
60
70
|
onSetOpen={this.onSetSidebarOpen}
|
61
71
|
>
|
62
|
-
|
72
|
+
<Route name='screen' path="/:screenId/:identifier?" component={Screen} />
|
73
|
+
<Route path="*" component={NoMatch} />
|
63
74
|
</Sidebar>
|
64
75
|
</App>
|
65
76
|
);
|
66
77
|
}
|
67
78
|
}
|
68
79
|
|
69
|
-
|
70
|
-
function NoMatch() {
|
71
|
-
return (
|
72
|
-
<h1>Not Found</h1>
|
73
|
-
);
|
74
|
-
}
|
75
|
-
|
76
80
|
export default function WorkspaceRoot() {
|
77
81
|
return (
|
78
|
-
<Router
|
79
|
-
<Route path="/" component={Workspace}
|
80
|
-
<Route name='screen' path="/:screenId(/:identifier)" component={Screen} />
|
81
|
-
<Route path="*" component={NoMatch} />
|
82
|
-
</Route>
|
82
|
+
<Router>
|
83
|
+
<Route path="/" component={Workspace} />
|
83
84
|
</Router>
|
84
85
|
);
|
85
86
|
}
|
@@ -1,21 +1,16 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import classnames from 'classnames';
|
3
2
|
import { observer } from 'mobx-react';
|
4
3
|
import { action } from 'mobx';
|
5
4
|
import PropTypes from 'prop-types';
|
6
5
|
import Sidebar from 'grommet/components/Sidebar';
|
7
|
-
import Heading from 'grommet/components/Heading';
|
8
|
-
import Footer from 'grommet/components/Footer';
|
9
6
|
import Header from 'grommet/components/Header';
|
10
7
|
import Anchor from 'grommet/components/Anchor';
|
11
8
|
import Menu from 'grommet/components/Menu';
|
12
9
|
import Group from './menu-group';
|
13
10
|
import Screens from '../screens';
|
14
|
-
import Icon from '../components/icon';
|
15
11
|
|
16
|
-
import User from '../user';
|
17
12
|
|
18
|
-
|
13
|
+
import User from '../user';
|
19
14
|
|
20
15
|
@observer
|
21
16
|
class Logout extends React.PureComponent {
|
@@ -30,8 +25,7 @@ class Logout extends React.PureComponent {
|
|
30
25
|
ev.stopPropagation();
|
31
26
|
ev.preventDefault();
|
32
27
|
User.logout();
|
33
|
-
|
34
|
-
router.push('/');
|
28
|
+
this.context.router.history.push('/');
|
35
29
|
}
|
36
30
|
|
37
31
|
render() {
|
@@ -1,8 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import classnames from 'classnames';
|
4
3
|
import { observer } from 'mobx-react';
|
5
|
-
import { Grid } from 'react-flexbox-grid';
|
6
4
|
import Box from 'grommet/components/Box';
|
7
5
|
import Screens from '../screens';
|
8
6
|
import ScreenInstances from '../screens/instance';
|
@@ -19,13 +17,15 @@ ScreenView.displayName = 'ScreenView';
|
|
19
17
|
export default class Screen extends React.Component {
|
20
18
|
|
21
19
|
static propTypes = {
|
22
|
-
|
23
|
-
|
20
|
+
match: PropTypes.shape({
|
21
|
+
params: PropTypes.shape({
|
22
|
+
screenId: PropTypes.string,
|
23
|
+
}),
|
24
24
|
}).isRequired,
|
25
25
|
}
|
26
26
|
|
27
27
|
componentDidMount() {
|
28
|
-
const { screenId } = this.props.params;
|
28
|
+
const { screenId } = this.props.match.params;
|
29
29
|
if (screenId) {
|
30
30
|
const definition = Screens.all.get(screenId);
|
31
31
|
if (definition) { definition.display(); }
|
@@ -42,7 +42,7 @@ export default class Screen extends React.Component {
|
|
42
42
|
flex="grow"
|
43
43
|
>
|
44
44
|
{ScreenInstances.displaying.map(s =>
|
45
|
-
<ScreenView key={s.id} {...this.props.params} screen={s} />)}
|
45
|
+
<ScreenView key={s.id} {...this.props.match.params} screen={s} />)}
|
46
46
|
</Box>
|
47
47
|
|
48
48
|
);
|
data/config/database.yml
CHANGED
data/config/routes.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Hippo::API
|
2
2
|
|
3
3
|
routes.for_extension 'hippo' do
|
4
|
-
get 'job-
|
4
|
+
get 'job-status/:id.json' do
|
5
5
|
wrap_reply do
|
6
6
|
status = Hippo::Job.status_for_id(params[:id])
|
7
7
|
raise ActiveRecord::RecordNotFound unless status
|
@@ -9,10 +9,10 @@ module Hippo::API
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
post "user-
|
13
|
-
get "user-
|
12
|
+
post "user-session.json", &Hippo::API::Handlers::UserSession.create
|
13
|
+
get "user-session/test.json", &Hippo::API::Handlers::UserSession.check
|
14
14
|
|
15
|
-
delete "user-
|
15
|
+
delete "user-session/:id.json" do
|
16
16
|
wrap_reply do
|
17
17
|
{ success: true, message: "Logout succeeded", data: {}, token: '' }
|
18
18
|
end
|
data/config/webpack.config.js
CHANGED
@@ -3,15 +3,15 @@ const path = require('path');
|
|
3
3
|
|
4
4
|
const config = {
|
5
5
|
entry: {
|
6
|
-
|
6
|
+
app: [
|
7
7
|
'react-hot-loader/patch',
|
8
8
|
'<%= "#{Hippo::Extensions.controlling.identifier}/index.js" %>',
|
9
9
|
],
|
10
10
|
},
|
11
11
|
output: {
|
12
12
|
path: '<%= config_directory.join('..','public', 'assets') %>',
|
13
|
-
publicPath: '<%= Hippo.env.production? ? '/assets/' : 'http://test.hippo.dev:8889/assets/' %>',
|
14
13
|
filename: '[name]-[hash].js',
|
14
|
+
publicPath: '<%= Hippo.env.production? ? '/assets/' : 'http://test.hippo.dev:8889/assets/' %>',
|
15
15
|
},
|
16
16
|
resolve: {
|
17
17
|
modules: [
|
@@ -44,16 +44,16 @@ const config = {
|
|
44
44
|
},
|
45
45
|
},
|
46
46
|
{ test: /\.scss$/,
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
47
|
+
use: [
|
48
|
+
'style-loader',
|
49
|
+
'css-loader',
|
50
|
+
{
|
51
|
+
loader: 'sass-loader',
|
52
|
+
options: {
|
53
|
+
includePaths: [path.resolve('./node_modules')],
|
54
|
+
},
|
55
|
+
},
|
56
|
+
],
|
57
57
|
},
|
58
58
|
],
|
59
59
|
},
|
@@ -71,10 +71,12 @@ const config = {
|
|
71
71
|
inline: true,
|
72
72
|
port: 8889,
|
73
73
|
historyApiFallback: true,
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
headers: {
|
75
|
+
"Access-Control-Allow-Origin": "*",
|
76
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
77
|
+
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
|
78
|
+
},
|
79
|
+
disableHostCheck: true,
|
78
80
|
stats: {
|
79
81
|
colors: true,
|
80
82
|
profile: true,
|
data/hippo-fw.gemspec
CHANGED
@@ -26,8 +26,8 @@ Gem::Specification.new do |spec|
|
|
26
26
|
|
27
27
|
spec.add_dependency "activejob", "~> 5.0.0"
|
28
28
|
spec.add_dependency "activerecord", "~> 5.0.0"
|
29
|
-
spec.add_dependency "
|
30
|
-
|
29
|
+
spec.add_dependency "litecable", "~> 0.4.1"
|
30
|
+
spec.add_dependency "websocket", "~> 1.2.4"
|
31
31
|
spec.add_dependency "mail", "~> 2.6"
|
32
32
|
spec.add_dependency "scenic", "~> 1.4"
|
33
33
|
spec.add_dependency "liquid", "~> 4.0"
|
data/lib/hippo.rb
CHANGED
@@ -7,13 +7,11 @@ module Hippo
|
|
7
7
|
end
|
8
8
|
|
9
9
|
require_relative "hippo/version"
|
10
|
+
require_relative "hippo/rails"
|
10
11
|
require_relative "hippo/environment"
|
11
12
|
require_relative "hippo/configuration"
|
12
13
|
require_relative "hippo/redis"
|
13
14
|
require_relative "hippo/logger"
|
14
|
-
if defined?(::Rails)
|
15
|
-
require_relative "hippo/rails_engine"
|
16
|
-
end
|
17
15
|
require_relative "hippo/db"
|
18
16
|
require_relative "hippo/strings"
|
19
17
|
require_relative "hippo/numbers"
|
data/lib/hippo/api.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative 'api/generic_controller'
|
|
8
8
|
require_relative 'api/cable'
|
9
9
|
require_relative 'api/sprockets_extension'
|
10
10
|
require_relative 'api/helper_methods'
|
11
|
+
require_relative 'api/cable'
|
11
12
|
require_relative 'api/pub_sub'
|
12
13
|
require_rel 'api/handlers/*.rb'
|
13
14
|
require_relative 'api/route_set'
|
data/lib/hippo/api/cable.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require
|
2
|
-
# require 'action_cable/subscription_adapter/postgresql'
|
1
|
+
require "lite_cable"
|
3
2
|
|
4
3
|
module Hippo
|
5
4
|
module API
|
@@ -11,18 +10,20 @@ module Hippo
|
|
11
10
|
@@server.call(request.env)
|
12
11
|
end
|
13
12
|
|
14
|
-
class Channel <
|
13
|
+
class Channel < LiteCable::Channel::Base
|
15
14
|
end
|
16
15
|
|
17
|
-
class Connection <
|
16
|
+
class Connection < LiteCable::Connection::Base
|
18
17
|
identified_by :current_user
|
19
18
|
|
20
19
|
def connect
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
token = request.params['token']
|
21
|
+
begin
|
22
|
+
self.current_user = User.for_jwt_token(token) if token
|
23
|
+
rescue JWT::DecodeError
|
24
|
+
end
|
25
|
+
unless self.current_user
|
26
|
+
Hippo.logger.warn("Rejecting ws connection due to unauthorized access")
|
26
27
|
reject_unauthorized_connection
|
27
28
|
end
|
28
29
|
end
|
@@ -35,18 +36,16 @@ module Hippo
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def self.configure
|
39
|
+
require_relative './updates'
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
ActionCable::Server::Base.config = config
|
49
|
-
@@server = ActionCable.server
|
41
|
+
if Hippo.config.api_use_any_cable
|
42
|
+
|
43
|
+
else
|
44
|
+
require "lite_cable/server"
|
45
|
+
@@server = LiteCable::Server::Middleware.new(
|
46
|
+
Hippo::API::Root, connection_class: Hippo::API::Cable::Connection
|
47
|
+
)
|
48
|
+
end
|
50
49
|
Updates.relay!
|
51
50
|
end
|
52
51
|
|