mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-04-25 04:09:12 +00:00
finish redux feature parity
This commit is contained in:
parent
f5220aa6dc
commit
5510d5a1c4
29 changed files with 220 additions and 100 deletions
|
@ -1,4 +1,4 @@
|
||||||
const log = new (require('./logger'))('World')
|
const log = new (require('./logger'))('Roleypoly')
|
||||||
const Sequelize = require('sequelize')
|
const Sequelize = require('sequelize')
|
||||||
const fetchModels = require('./models')
|
const fetchModels = require('./models')
|
||||||
const fetchApis = require('./api')
|
const fetchApis = require('./api')
|
||||||
|
@ -40,9 +40,9 @@ class Roleypoly {
|
||||||
// enableReadyCheck: true,
|
// enableReadyCheck: true,
|
||||||
// enableOfflineQueue: true
|
// enableOfflineQueue: true
|
||||||
// })
|
// })
|
||||||
|
|
||||||
this.ctx.discord = new (require('./services/discord'))(this.ctx)
|
this.ctx.discord = new (require('./services/discord'))(this.ctx)
|
||||||
this.ctx.sessions = new (require('./services/sessions'))(this.ctx)
|
this.ctx.sessions = new (require('./services/sessions'))(this.ctx)
|
||||||
|
this.ctx.P = new (require('./services/presentation'))(this.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
async mountRoutes () {
|
async mountRoutes () {
|
||||||
|
|
|
@ -36,6 +36,7 @@ module.exports = (R, $) => {
|
||||||
if (ctx.session.accessToken === undefined) {
|
if (ctx.session.accessToken === undefined) {
|
||||||
ctx.body = { err: 'not_logged_in' }
|
ctx.body = { err: 'not_logged_in' }
|
||||||
ctx.status = 401
|
ctx.status = 401
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await $.discord.getUser(ctx.session.accessToken)
|
const user = await $.discord.getUser(ctx.session.accessToken)
|
||||||
|
|
|
@ -2,7 +2,7 @@ module.exports = (R, $) => {
|
||||||
R.get('/api/servers', async (ctx) => {
|
R.get('/api/servers', async (ctx) => {
|
||||||
const { userId } = ctx.session
|
const { userId } = ctx.session
|
||||||
const srv = $.discord.getRelevantServers(userId)
|
const srv = $.discord.getRelevantServers(userId)
|
||||||
const presentable = $.discord.presentableServers(srv, userId)
|
const presentable = $.P.oldPresentableServers(srv, userId)
|
||||||
|
|
||||||
ctx.body = presentable
|
ctx.body = presentable
|
||||||
})
|
})
|
||||||
|
|
|
@ -37,9 +37,9 @@ async function start () {
|
||||||
await next()
|
await next()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e)
|
log.error(e)
|
||||||
ctx.status = 500
|
ctx.status = ctx.status || 500
|
||||||
if (DEVEL) {
|
if (DEVEL) {
|
||||||
ctx.body = e.stack
|
ctx.body = ctx.body || e.stack
|
||||||
} else {
|
} else {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
err: 'something terrible happened.'
|
err: 'something terrible happened.'
|
||||||
|
|
|
@ -7,7 +7,7 @@ module.exports = (sql, DataTypes) => {
|
||||||
categories: {
|
categories: {
|
||||||
type: DataTypes.JSON
|
type: DataTypes.JSON
|
||||||
},
|
},
|
||||||
note: {
|
message: {
|
||||||
type: DataTypes.TEXT
|
type: DataTypes.TEXT
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"koa-passport": "^4.0.1",
|
"koa-passport": "^4.0.1",
|
||||||
"koa-session": "^5.5.1",
|
"koa-session": "^5.5.1",
|
||||||
"ksuid": "^0.4.0",
|
"ksuid": "^0.4.0",
|
||||||
|
"lru-cache": "^4.1.1",
|
||||||
"passport-discord": "^0.1.3",
|
"passport-discord": "^0.1.3",
|
||||||
"passport-oauth2-refresh": "^1.0.0",
|
"passport-oauth2-refresh": "^1.0.0",
|
||||||
"pg": "^7.4.0",
|
"pg": "^7.4.0",
|
||||||
|
|
|
@ -15,6 +15,7 @@ class DiscordService extends Service {
|
||||||
this.client = new discord.Client()
|
this.client = new discord.Client()
|
||||||
|
|
||||||
this.startBot()
|
this.startBot()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async startBot () {
|
async startBot () {
|
||||||
|
@ -25,42 +26,12 @@ class DiscordService extends Service {
|
||||||
return this.client.guilds.filter((g) => g.members.has(userId))
|
return this.client.guilds.filter((g) => g.members.has(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
presentableServers (collection, userId) {
|
gm (serverId, userId) {
|
||||||
return collection.map((server) => {
|
return this.client.guilds.get(serverId).members.get(userId)
|
||||||
const gm = server.members.get(userId)
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: server.id,
|
|
||||||
gm: {
|
|
||||||
nickname: gm.nickname,
|
|
||||||
color: gm.displayHexColor
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
id: server.id,
|
|
||||||
name: server.name,
|
|
||||||
ownerID: server.ownerID,
|
|
||||||
icon: server.icon
|
|
||||||
},
|
|
||||||
roles: this.presentableRoles(server.id, gm),
|
|
||||||
message: 'moe moe kyuuuuuuuuun~',
|
|
||||||
perms: this.getPermissions(gm)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
presentableRoles (serverId, gm) {
|
getRoles (server) {
|
||||||
return this.client.guilds
|
return this.client.guilds.get(server).roles
|
||||||
.get(serverId)
|
|
||||||
.roles
|
|
||||||
.filter(r => r.id !== serverId)
|
|
||||||
.map((role) => ({
|
|
||||||
color: role.hexColor,
|
|
||||||
position: role.position,
|
|
||||||
calculatedPosition: role.calculatedPosition,
|
|
||||||
id: role.id,
|
|
||||||
name: role.name,
|
|
||||||
selected: gm.roles.has(role.id)
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getPermissions (gm) {
|
getPermissions (gm) {
|
||||||
|
|
49
Server/services/presentation.js
Normal file
49
Server/services/presentation.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const Service = require('./Service')
|
||||||
|
const LRU = require('lru-cache')
|
||||||
|
|
||||||
|
class PresentationService extends Service {
|
||||||
|
constructor (ctx) {
|
||||||
|
super(ctx)
|
||||||
|
this.M = ctx.M
|
||||||
|
this.discord = ctx.discord
|
||||||
|
|
||||||
|
this.cache = LRU({ max: 500, maxAge: 100 * 60 * 5 })
|
||||||
|
}
|
||||||
|
|
||||||
|
oldPresentableServers (collection, userId) {
|
||||||
|
return collection.map((server) => {
|
||||||
|
const gm = server.members.get(userId)
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: server.id,
|
||||||
|
gm: {
|
||||||
|
nickname: gm.nickname,
|
||||||
|
color: gm.displayHexColor
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
id: server.id,
|
||||||
|
name: server.name,
|
||||||
|
ownerID: server.ownerID,
|
||||||
|
icon: server.icon
|
||||||
|
},
|
||||||
|
roles: server.roles.filter(r => r.id !== server.id).map(r => ({
|
||||||
|
id: r.id,
|
||||||
|
color: r.color,
|
||||||
|
name: r.name,
|
||||||
|
selected: gm.roles.has(r.id),
|
||||||
|
position: r.position
|
||||||
|
})),
|
||||||
|
message: 'moe moe kyuuuuuuuuun~',
|
||||||
|
perms: this.discord.getPermissions(gm)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
rolesByServer (serverId, userId) {
|
||||||
|
// get from discord, merge with server categories
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PresentationService
|
42
Server/services/server.js
Normal file
42
Server/services/server.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
const Service = require('./Service')
|
||||||
|
|
||||||
|
class ServerService extends Service {
|
||||||
|
constructor (ctx) {
|
||||||
|
super(ctx)
|
||||||
|
this.Server = ctx.M.Server
|
||||||
|
this.P = ctx.P
|
||||||
|
}
|
||||||
|
|
||||||
|
async ensure (server) {
|
||||||
|
const srv = await this.get(server.id)
|
||||||
|
if (srv == null) {
|
||||||
|
return this.create({
|
||||||
|
id: server.id,
|
||||||
|
message: '',
|
||||||
|
categories: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create ({ id, message, categories }) {
|
||||||
|
const srv = this.Server.build({ id, message, categories })
|
||||||
|
|
||||||
|
return srv.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
update (id, newData) {
|
||||||
|
const srv = this.get(id)
|
||||||
|
|
||||||
|
return srv.update(newData)
|
||||||
|
}
|
||||||
|
|
||||||
|
get (id) {
|
||||||
|
return this.Server.findOne({
|
||||||
|
where: {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ServerService
|
|
@ -2022,6 +2022,13 @@ lru-cache@^4.0.1:
|
||||||
pseudomap "^1.0.1"
|
pseudomap "^1.0.1"
|
||||||
yallist "^2.0.0"
|
yallist "^2.0.0"
|
||||||
|
|
||||||
|
lru-cache@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
|
||||||
|
dependencies:
|
||||||
|
pseudomap "^1.0.2"
|
||||||
|
yallist "^2.1.2"
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
|
@ -2635,7 +2642,7 @@ promptly@2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
read "^1.0.4"
|
read "^1.0.4"
|
||||||
|
|
||||||
pseudomap@^1.0.1:
|
pseudomap@^1.0.1, pseudomap@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||||
|
|
||||||
|
@ -3441,7 +3448,7 @@ y18n@^3.2.1:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
||||||
|
|
||||||
yallist@^2.0.0:
|
yallist@^2.0.0, yallist@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"color": "^2.0.1",
|
"color": "^2.0.1",
|
||||||
"custom-react-scripts": "0.2.1",
|
"custom-react-scripts": "0.2.1",
|
||||||
"eslint": "^4.13.0",
|
"eslint": "^4.13.0",
|
||||||
|
"history": "^4.7.2",
|
||||||
"immutable": "^3.8.2",
|
"immutable": "^3.8.2",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
"react-redux": "^5.0.6",
|
"react-redux": "^5.0.6",
|
||||||
"react-router": "^4.2.0",
|
"react-router": "^4.2.0",
|
||||||
"react-router-dom": "^4.2.2",
|
"react-router-dom": "^4.2.2",
|
||||||
|
"react-router-redux": "^5.0.0-alpha.8",
|
||||||
"redux": "^3.7.2",
|
"redux": "^3.7.2",
|
||||||
"redux-devtools": "^3.4.1",
|
"redux-devtools": "^3.4.1",
|
||||||
"redux-devtools-dock-monitor": "^1.1.2",
|
"redux-devtools-dock-monitor": "^1.1.2",
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/png" sizes="any" href="%PUBLIC_URL%/favicon.png"/>
|
<link rel="icon" type="image/png" sizes="any" href="%PUBLIC_URL%/favicon.png"/>
|
||||||
<title>Roleypoly</title>
|
<title>Roleypoly</title>
|
||||||
<link rel="stylesheet" href="https://use.typekit.net/bck0pci.css">
|
<script src="https://use.typekit.net/bck0pci.js"></script>
|
||||||
|
<script>try{Typekit.load({ async: true });}catch(e){}</script>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/css/uikit.min.css" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/css/uikit.min.css" />
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit-icons.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit-icons.min.js"></script>
|
||||||
|
@ -12,7 +13,7 @@
|
||||||
<noscript>
|
<noscript>
|
||||||
You need to enable JavaScript to run this app.
|
You need to enable JavaScript to run this app.
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="root" class="tk-source-han-sans-japanese"></div>
|
<div id="root" class=""></div>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
If you open it directly in the browser, you will see an empty page.
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import './App.css'
|
import createHistory from 'history/createBrowserHistory'
|
||||||
|
import { ConnectedRouter } from 'react-router-redux'
|
||||||
import configureStore from './store/configureStore'
|
import configureStore from './store/configureStore'
|
||||||
|
import './App.css'
|
||||||
|
|
||||||
import Wrapper from './components/wrapper'
|
import Wrapper from './components/wrapper'
|
||||||
import AppRouter from './router'
|
import AppRouter from './router'
|
||||||
import { userInit } from './actions'
|
import { userInit } from './actions'
|
||||||
|
|
||||||
const store = configureStore()
|
const history = createHistory()
|
||||||
|
const store = configureStore(undefined, history)
|
||||||
|
|
||||||
window.__APP_STORE__ = store
|
window.__APP_STORE__ = store
|
||||||
|
|
||||||
|
@ -20,11 +23,11 @@ class App extends Component {
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<BrowserRouter>
|
<ConnectedRouter history={history}>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<AppRouter />
|
<AppRouter />
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
</BrowserRouter>
|
</ConnectedRouter>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,19 +14,23 @@ export const fetchServers = async dispatch => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const userInit = async dispatch => {
|
export const userInit = async dispatch => {
|
||||||
try {
|
if (!window.location.pathname.startsWith('/oauth')) {
|
||||||
const rsp = await superagent.get('/api/auth/user')
|
try {
|
||||||
|
const rsp = await superagent.get('/api/auth/user')
|
||||||
dispatch({
|
|
||||||
type: Symbol.for('set user'),
|
|
||||||
data: rsp.body
|
|
||||||
})
|
|
||||||
|
|
||||||
dispatch(fetchServers)
|
dispatch({
|
||||||
} catch (e) {
|
type: Symbol.for('set user'),
|
||||||
if (!window.location.pathname.startsWith('/oauth')) {
|
data: rsp.body
|
||||||
|
})
|
||||||
|
|
||||||
|
dispatch(fetchServers)
|
||||||
|
} catch (e) {
|
||||||
window.location.href = '/oauth/flow'
|
window.location.href = '/oauth/flow'
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dispatch({
|
||||||
|
type: Symbol.for('app ready')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,16 @@ export const roleUpdate = (id, oldState) => (dispatch, getState) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setup = id => async dispatch => {
|
export const setup = id => async dispatch => {
|
||||||
const rsp = await superagent.get(`/api/server/${id}`)
|
// const rsp = await superagent.get(`/api/server/${id}`)
|
||||||
const data = rsp.body
|
// const data = rsp.body
|
||||||
|
|
||||||
dispatch({
|
// dispatch({
|
||||||
type: Symbol.for('update server roles'),
|
// type: Symbol.for('update server roles'),
|
||||||
data: {
|
// data: {
|
||||||
id,
|
// id,
|
||||||
roles: data
|
// roles: data
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
dispatch(constructView(id))
|
dispatch(constructView(id))
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,7 @@ export const constructView = id => (dispatch, getState) => {
|
||||||
const roles = server.get('roles')
|
const roles = server.get('roles')
|
||||||
|
|
||||||
const categories = roles.groupBy(x => x.get('category'))
|
const categories = roles.groupBy(x => x.get('category'))
|
||||||
const selected = roles.reduce((acc, r) => {
|
const selected = roles.reduce((acc, r) => acc.set(r.get('id'), r.get('selected')), Map())
|
||||||
return acc.set(r.id, r.selected)
|
|
||||||
}, Map())
|
|
||||||
|
|
||||||
console.log(categories, selected)
|
console.log(categories, selected)
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -7,7 +7,6 @@ import './RolePicker.sass'
|
||||||
import Role from '../role'
|
import Role from '../role'
|
||||||
|
|
||||||
const mapState = ({ rolePicker, servers }, ownProps) => {
|
const mapState = ({ rolePicker, servers }, ownProps) => {
|
||||||
console.log(servers)
|
|
||||||
return {
|
return {
|
||||||
data: rolePicker,
|
data: rolePicker,
|
||||||
server: servers.get(ownProps.match.params.server)
|
server: servers.get(ownProps.match.params.server)
|
||||||
|
@ -21,8 +20,12 @@ class RolePicker extends Component {
|
||||||
dispatch(Actions.setup(server))
|
dispatch(Actions.setup(server))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSelected (id) {
|
||||||
|
return this.props.data.getIn([ 'rolesSelected', id ])
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
console.log(this.props)
|
console.log(this.constructor.name, this.props)
|
||||||
if (this.props.server === undefined) {
|
if (this.props.server === undefined) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -37,11 +40,11 @@ class RolePicker extends Component {
|
||||||
}
|
}
|
||||||
<section>
|
<section>
|
||||||
<h3>Roles</h3>
|
<h3>Roles</h3>
|
||||||
{/* {
|
{
|
||||||
this.props.data.roles.map((r, k) => {
|
this.props.server.get('roles').map((r, k) => {
|
||||||
return <Role key={k} role={r} onToggle={this.dispatch(Actions.roleUpdate(r.id, r.selected))} />
|
return <Role key={k} role={r} selected={this.isSelected(r.get('id'))} onToggle={() => this.props.dispatch(Actions.roleUpdate(r.get('id'), this.isSelected(r.get('id'))))} />
|
||||||
})
|
})
|
||||||
} */}
|
}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
border-color: var(--role-color-hover)
|
border-color: var(--role-color-hover)
|
||||||
background-color: transparent
|
background-color: transparent
|
||||||
&:active
|
&:active
|
||||||
box-shadow: none
|
box-shadow: none
|
||||||
|
|
||||||
|
&:active .role__option
|
||||||
|
box-shadow: none
|
||||||
|
|
||||||
|
|
||||||
&__option
|
&__option
|
||||||
border-radius: 50%
|
border-radius: 50%
|
||||||
|
|
|
@ -9,12 +9,14 @@ class Role extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
role: PropTypes.object.isRequired,
|
role: PropTypes.object.isRequired,
|
||||||
onToggle: PropTypes.func,
|
onToggle: PropTypes.func,
|
||||||
type: PropTypes.string
|
type: PropTypes.string,
|
||||||
|
selected: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { role } = this.props
|
let { role, selected } = this.props
|
||||||
let color = Color(role.color)
|
|
||||||
|
let color = Color(role.get('color'))
|
||||||
|
|
||||||
if (color.rgbNumber() === 0) {
|
if (color.rgbNumber() === 0) {
|
||||||
color = whiteColor
|
color = whiteColor
|
||||||
|
@ -24,17 +26,16 @@ class Role extends Component {
|
||||||
let hc = color.lighten(0.1)
|
let hc = color.lighten(0.1)
|
||||||
|
|
||||||
return <div
|
return <div
|
||||||
onClick={this.props.onToggle.bind(null, !role.selected, role.selected)}
|
onClick={this.props.onToggle.bind(null, !selected, selected)}
|
||||||
className='role'
|
className='role font-sans-serif'
|
||||||
style={{
|
style={{
|
||||||
'--role-color-hex': c.string(),
|
'--role-color-hex': c.string(),
|
||||||
'--role-color-hover': hc.string(),
|
'--role-color-hover': hc.string(),
|
||||||
'--role-color-rgba': `rgba(${c.red()}, ${c.green()}, ${c.blue()}, 0.7)`
|
'--role-color-rgba': `rgba(${c.red()}, ${c.green()}, ${c.blue()}, 0.7)`
|
||||||
}}>
|
}}>
|
||||||
{/* circle svg */}
|
<div className={`role__option ${(selected) ? 'selected' : ''}`}/>
|
||||||
<div className={`role__option ${(role.selected) ? 'selected' : ''}`}/>
|
|
||||||
<div className='role__name'>
|
<div className='role__name'>
|
||||||
{role.name}
|
{role.get('name')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,9 @@ import ServerCard from './ServerCard'
|
||||||
import UserCard from './UserCard'
|
import UserCard from './UserCard'
|
||||||
|
|
||||||
class ServersNavigation extends Component {
|
class ServersNavigation extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
user: ImmutablePropTypes.map.isRequired,
|
user: ImmutablePropTypes.map.isRequired,
|
||||||
servers: ImmutablePropTypes.setOf(ImmutablePropTypes.orderedMap).isRequired,
|
servers: ImmutablePropTypes.orderedMapOf(ImmutablePropTypes.map).isRequired,
|
||||||
className: PropTypes.string
|
className: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import Radium from 'radium'
|
|
||||||
import './ServerCard.sass'
|
import './ServerCard.sass'
|
||||||
|
import { withRouter } from 'react-router';
|
||||||
|
|
||||||
class ServerCard extends Component {
|
class ServerCard extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import './index.sass'
|
||||||
|
|
||||||
import Navigation from './Navigation'
|
import Navigation from './Navigation'
|
||||||
import RolePicker from '../role-picker'
|
import RolePicker from '../role-picker'
|
||||||
|
import { withRouter } from 'react-router';
|
||||||
|
|
||||||
// import mockData from './mockData'
|
// import mockData from './mockData'
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ body {
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-sans-serif {
|
||||||
|
font-family: sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--c-white: #efefef;
|
--c-white: #efefef;
|
||||||
--c-9: #EBD6D4;
|
--c-9: #EBD6D4;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { combineReducers } from 'redux'
|
||||||
import servers from './servers'
|
import servers from './servers'
|
||||||
import user from './user'
|
import user from './user'
|
||||||
import rolePicker from './role-picker'
|
import rolePicker from './role-picker'
|
||||||
|
import { routerMiddleware } from 'react-router-redux';
|
||||||
// import roles from './roles'
|
// import roles from './roles'
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
|
@ -25,6 +26,7 @@ const rootReducer = combineReducers({
|
||||||
appState,
|
appState,
|
||||||
servers,
|
servers,
|
||||||
user,
|
user,
|
||||||
|
router: routerMiddleware,
|
||||||
// roles,
|
// roles,
|
||||||
rolePicker
|
rolePicker
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Map, Set } from 'immutable'
|
import { Map, OrderedMap } from 'immutable'
|
||||||
|
|
||||||
const initialState = Map({
|
const initialState = Map({
|
||||||
hidden: true, // should the view be hidden?
|
hidden: true, // should the view be hidden?
|
||||||
emptyRoles: true, // helps derender roles so there's no visible element state change
|
emptyRoles: true, // helps derender roles so there's no visible element state change
|
||||||
viewMap: Set([]), // roles in categories
|
viewMap: OrderedMap({}), // roles in categories
|
||||||
originalRolesSelected: Map({}), // Map<role id, bool> -- original roles for diffing against selected
|
originalRolesSelected: Map({}), // Map<role id, bool> -- original roles for diffing against selected
|
||||||
rolesSelected: Map({}) // Map<role id, bool> -- new roles for diffing
|
rolesSelected: Map({}) // Map<role id, bool> -- new roles for diffing
|
||||||
})
|
})
|
||||||
|
@ -11,8 +11,8 @@ const initialState = Map({
|
||||||
export default (state = initialState, { type, data }) => {
|
export default (state = initialState, { type, data }) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Symbol.for('setup role picker'):
|
case Symbol.for('setup role picker'):
|
||||||
return state.merge(data)
|
return state.mergeDeep(data)
|
||||||
|
|
||||||
case Symbol.for('hide role picker ui'):
|
case Symbol.for('hide role picker ui'):
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
@ -24,12 +24,12 @@ export default (state = initialState, { type, data }) => {
|
||||||
...state,
|
...state,
|
||||||
emptyRoles: data
|
emptyRoles: data
|
||||||
}
|
}
|
||||||
|
|
||||||
case Symbol.for('zero role picker'):
|
|
||||||
return initialState
|
|
||||||
|
|
||||||
case Symbol.for('update selected roles'):
|
case Symbol.for('update selected roles'):
|
||||||
return state.set('rolesSelected', state.get('rolesSelected').set(data.id, data.state))
|
return state.setIn(['rolesSelected', data.id], data.state)
|
||||||
|
|
||||||
|
case Symbol.for('zero role picker'):
|
||||||
|
return initialState
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -5,9 +5,11 @@ import { connect } from 'react-redux'
|
||||||
import Servers from '../components/servers'
|
import Servers from '../components/servers'
|
||||||
import OauthCallback from '../components/oauth-callback'
|
import OauthCallback from '../components/oauth-callback'
|
||||||
import OauthFlow from '../components/oauth-flow'
|
import OauthFlow from '../components/oauth-flow'
|
||||||
|
import { withRouter } from 'react-router';
|
||||||
|
|
||||||
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
|
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
|
||||||
|
|
||||||
|
@withRouter
|
||||||
@connect(({ appState }) => ({ ready: appState.ready }))
|
@connect(({ appState }) => ({ ready: appState.ready }))
|
||||||
export default class AppRouter extends Component {
|
export default class AppRouter extends Component {
|
||||||
render () {
|
render () {
|
||||||
|
|
|
@ -5,13 +5,14 @@ import { createLogger } from 'redux-logger'
|
||||||
// import api from '../middleware/api'
|
// import api from '../middleware/api'
|
||||||
import rootReducer from '../reducers'
|
import rootReducer from '../reducers'
|
||||||
import DevTools from '../components/dev-tools'
|
import DevTools from '../components/dev-tools'
|
||||||
|
import { routerMiddleware } from 'react-router-redux'
|
||||||
|
|
||||||
const configureStore = preloadedState => {
|
const configureStore = (preloadedState, history) => {
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
rootReducer,
|
rootReducer,
|
||||||
preloadedState,
|
preloadedState,
|
||||||
compose(
|
compose(
|
||||||
applyMiddleware(thunk, createLogger()),
|
applyMiddleware(thunk, routerMiddleware(history), createLogger()),
|
||||||
DevTools.instrument()
|
DevTools.instrument()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { createStore, applyMiddleware } from 'redux'
|
import { createStore, applyMiddleware } from 'redux'
|
||||||
|
import { routerMiddleware } from 'react-router-redux'
|
||||||
|
|
||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk'
|
||||||
// import api from '../middleware/api'
|
// import api from '../middleware/api'
|
||||||
import rootReducer from '../reducers'
|
import rootReducer from '../reducers'
|
||||||
|
|
||||||
const configureStore = preloadedState => createStore(
|
const configureStore = (preloadedState, history) => createStore(
|
||||||
rootReducer,
|
rootReducer,
|
||||||
preloadedState,
|
preloadedState,
|
||||||
applyMiddleware(thunk)
|
applyMiddleware(thunk, routerMiddleware(history))
|
||||||
)
|
)
|
||||||
|
|
||||||
export default configureStore
|
export default configureStore
|
||||||
|
|
|
@ -6094,6 +6094,14 @@ react-router-dom@^4.2.2:
|
||||||
react-router "^4.2.0"
|
react-router "^4.2.0"
|
||||||
warning "^3.0.0"
|
warning "^3.0.0"
|
||||||
|
|
||||||
|
react-router-redux@^5.0.0-alpha.8:
|
||||||
|
version "5.0.0-alpha.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-5.0.0-alpha.8.tgz#5242c705730b2ac862aff7a8e90f870d0cf45e12"
|
||||||
|
dependencies:
|
||||||
|
history "^4.7.2"
|
||||||
|
prop-types "^15.6.0"
|
||||||
|
react-router "^4.2.0"
|
||||||
|
|
||||||
react-router@^4.2.0:
|
react-router@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986"
|
resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986"
|
||||||
|
|
13
start.sh
Executable file
13
start.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
cd Server
|
||||||
|
yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
cd UI
|
||||||
|
yarn
|
||||||
|
yarn start
|
Loading…
Add table
Reference in a new issue