client, logs-content: Added change subscription setup and hooked it up to the logs-content page.
the build was successful
the build was successful
This commit is contained in:
@@ -19,16 +19,12 @@ module.exports = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onInput(input) {
|
onInput(input) {
|
||||||
if (input.log && !this.first) {
|
|
||||||
this.state.values = {
|
this.state.values = {
|
||||||
title: input.log.title,
|
title: input.log.title,
|
||||||
event: input.log.eventName,
|
event: input.log.eventName,
|
||||||
description: input.log.description,
|
description: input.log.description,
|
||||||
open: input.log.open,
|
open: input.log.open,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.first = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
change(key, ev) {
|
change(key, ev) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const moment = require("moment")
|
const moment = require("moment")
|
||||||
|
|
||||||
const {postApi} = require("../../../../../rpdata/api/Post")
|
const {postApi} = require("../../../../../rpdata/api/Post")
|
||||||
|
const {logsApi} = require("../../../../../rpdata/api/Log")
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate(input) {
|
onCreate(input) {
|
||||||
@@ -11,6 +12,22 @@ module.exports = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMount() {
|
||||||
|
this.sub = logsApi.subscribeChanges(this.state.log.id)
|
||||||
|
|
||||||
|
this.sub.on("data", data => {
|
||||||
|
this.handleChange(data.changes)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.sub.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmount() {
|
||||||
|
if (this.sub != null) {
|
||||||
|
this.sub.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open(modal) {
|
open(modal) {
|
||||||
this.state.modal = modal
|
this.state.modal = modal
|
||||||
}
|
}
|
||||||
@@ -30,8 +47,6 @@ module.exports = class {
|
|||||||
for (const patch of patches) {
|
for (const patch of patches) {
|
||||||
const index = posts.findIndex(p => p.id === patch.id)
|
const index = posts.findIndex(p => p.id === patch.id)
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
console.warn("Post not found for patch:", patch)
|
|
||||||
// TODO: Force full refresh
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +57,7 @@ module.exports = class {
|
|||||||
posts.sort((a, b) => a.position - b.position)
|
posts.sort((a, b) => a.position - b.position)
|
||||||
for (let i = 1; i < posts.length; ++i) {
|
for (let i = 1; i < posts.length; ++i) {
|
||||||
if (posts[i].position !== posts[i - 1].position + 1) {
|
if (posts[i].position !== posts[i - 1].position + 1) {
|
||||||
console.warn("Discontinuity detected!")
|
console.warn("Discontinuity detected:", i, posts)
|
||||||
// TODO: Force full refresh
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,15 +79,7 @@ module.exports = class {
|
|||||||
|
|
||||||
removePost(post) {
|
removePost(post) {
|
||||||
postApi.remove({id: post.id}).then(() => {
|
postApi.remove({id: post.id}).then(() => {
|
||||||
this.state.log.posts = this.state.log.posts.filter(p => p.id !== post.id)
|
this.postRemoved(post)
|
||||||
|
|
||||||
for (const p of this.state.log.posts) {
|
|
||||||
if (p.position > post.position) {
|
|
||||||
p.position--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.log = Object.assign({}, this.state.log)
|
|
||||||
}).catch(errs => {
|
}).catch(errs => {
|
||||||
console.warn("Failed to delete:", errs)
|
console.warn("Failed to delete:", errs)
|
||||||
this.state.error = "Failed to delete: " + (errs.message || errs[0].message)
|
this.state.error = "Failed to delete: " + (errs.message || errs[0].message)
|
||||||
@@ -88,11 +94,69 @@ module.exports = class {
|
|||||||
this.state.log = Object.assign(Object.assign({}, this.state.log), patch)
|
this.state.log = Object.assign(Object.assign({}, this.state.log), patch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postRemoved(post) {
|
||||||
|
if (this.state.log.posts.find(p => p.id === post.id) == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const posts = this.state.log.posts.filter(p => p.id !== post.id).map(p => {
|
||||||
|
if (p.position > post.position) {
|
||||||
|
return Object.assign({}, p, {position: p.position - 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
})
|
||||||
|
|
||||||
|
this.state.log = Object.assign({}, this.state.log, {posts: posts})
|
||||||
|
}
|
||||||
|
|
||||||
postAdded(post) {
|
postAdded(post) {
|
||||||
this.state.log.posts = this.state.log.posts.concat([post])
|
this.state.log.posts = this.state.log.posts.concat([post])
|
||||||
this.state.log = Object.assign({}, this.state.log)
|
this.state.log = Object.assign({}, this.state.log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChange(change) {
|
||||||
|
switch (`${change.model}.${change.op}`) {
|
||||||
|
case "Post.add": {
|
||||||
|
for (const post of change.objects.filter(o => o.type === "Post")) {
|
||||||
|
this.postAdded(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "Post.move":
|
||||||
|
case "Post.edit": {
|
||||||
|
this.patch(change.objects.filter(o => o.type === "Post"))
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "Post.remove": {
|
||||||
|
for (const post of change.objects.filter(o => o.type === "Post")) {
|
||||||
|
this.postRemoved(post)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "Log.edit": {
|
||||||
|
const patch = change.objects.find(o => o.type === "Log")
|
||||||
|
if (patch == null) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logEdited(patch)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "Log.remove": {
|
||||||
|
this.logRemoved()
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logRemoved() {
|
logRemoved() {
|
||||||
this.state.removed = true
|
this.state.removed = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader")
|
const { logHeaderApi } = require("../../../../../rpdata/api/LogHeader")
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate(input) {
|
onCreate(input) {
|
||||||
|
|||||||
Generated
+1130
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@
|
|||||||
"express-http-proxy": "^1.2.0",
|
"express-http-proxy": "^1.2.0",
|
||||||
"express-session": "^1.15.6",
|
"express-session": "^1.15.6",
|
||||||
"graphql-query-compress": "^1.1.0",
|
"graphql-query-compress": "^1.1.0",
|
||||||
|
"http-proxy-middleware": "^0.19.1",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"jsonwebtoken": "^8.3.0",
|
"jsonwebtoken": "^8.3.0",
|
||||||
"lasso": "^3.2.6",
|
"lasso": "^3.2.6",
|
||||||
@@ -41,5 +42,8 @@
|
|||||||
"passport": "^0.4.0",
|
"passport": "^0.4.0",
|
||||||
"passport-auth0": "^1.0.0",
|
"passport-auth0": "^1.0.0",
|
||||||
"pluralize": "^7.0.0"
|
"pluralize": "^7.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/http-proxy-middleware": "^0.19.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
const proxy = require("http-proxy-middleware")
|
||||||
const express = require("express")
|
const express = require("express")
|
||||||
const jwt = require("jsonwebtoken")
|
const jwt = require("jsonwebtoken")
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ router.post("/", (req, res) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.use("/", proxy(config.graphqlEndpoint, {ws: true}))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} user
|
* @param {string} user
|
||||||
|
|||||||
+43
-2
@@ -1,4 +1,4 @@
|
|||||||
const {query} = require("../client")
|
const {query, Subscription} = require("../client")
|
||||||
|
|
||||||
const {Character} = require("./Character")
|
const {Character} = require("./Character")
|
||||||
const {Channel} = require("./Channel")
|
const {Channel} = require("./Channel")
|
||||||
@@ -193,7 +193,6 @@ class LogAPI {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call `removeLog(input)` mutation, returns the id
|
* Call `removeLog(input)` mutation, returns the id
|
||||||
*
|
*
|
||||||
@@ -211,6 +210,48 @@ class LogAPI {
|
|||||||
return editLog
|
return editLog
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to the changes.
|
||||||
|
*
|
||||||
|
* @param {string} logId The long logId, the short one won't do.
|
||||||
|
*/
|
||||||
|
subscribeChanges(logId) {
|
||||||
|
return new Subscription(`
|
||||||
|
subscription Changes($keys: [ChangeKeyInput!]!) {
|
||||||
|
changes(keys: $keys) {
|
||||||
|
id
|
||||||
|
model
|
||||||
|
op
|
||||||
|
author
|
||||||
|
listed
|
||||||
|
keys {
|
||||||
|
model
|
||||||
|
id
|
||||||
|
}
|
||||||
|
date
|
||||||
|
objects {
|
||||||
|
type: __typename
|
||||||
|
...on Log {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
eventName
|
||||||
|
description
|
||||||
|
open
|
||||||
|
}
|
||||||
|
...on Post {
|
||||||
|
id
|
||||||
|
time
|
||||||
|
kind
|
||||||
|
nick
|
||||||
|
text
|
||||||
|
position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, {keys: [{model: "Log", id: logId}]})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { Log, logsApi: new LogAPI }
|
module.exports = { Log, logsApi: new LogAPI }
|
||||||
+86
-1
@@ -1,3 +1,4 @@
|
|||||||
|
const EventEmitter = require("events")
|
||||||
const fetch = require("isomorphic-fetch")
|
const fetch = require("isomorphic-fetch")
|
||||||
const config = require("../config")
|
const config = require("../config")
|
||||||
const compressQuery = require("graphql-query-compress")
|
const compressQuery = require("graphql-query-compress")
|
||||||
@@ -30,4 +31,88 @@ function query(query, variables = {}, options = {}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { query }
|
class Subscription extends EventEmitter {
|
||||||
|
constructor(query, variables) {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.query = query
|
||||||
|
this.variables = Object.assign({}, variables)
|
||||||
|
this.websocket = null
|
||||||
|
this.verboseLogging = false
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
const baseUrl = (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.host
|
||||||
|
let id = 1
|
||||||
|
|
||||||
|
this.websocket = new WebSocket(baseUrl + config.graphqlEndpoint, "graphql-ws")
|
||||||
|
|
||||||
|
this.websocket.onopen = () => {
|
||||||
|
this.websocket.send(JSON.stringify({type: "connection_init", payload: {}}));
|
||||||
|
this.websocket.send(JSON.stringify({id: (id++).toFixed(0), type: "start", payload: {
|
||||||
|
query: this.query,
|
||||||
|
variables: this.variables,
|
||||||
|
extensions: {},
|
||||||
|
}}));
|
||||||
|
|
||||||
|
console.log("WS Open")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.websocket.onmessage = (ev) => {
|
||||||
|
let data = {}
|
||||||
|
try {
|
||||||
|
data = JSON.parse(ev.data)
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("Error", err, ev)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.verboseLogging) {
|
||||||
|
console.log("WS Data:", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data.type) {
|
||||||
|
case "connection_ack": {
|
||||||
|
this.emit("connect")
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "connection_error": {
|
||||||
|
console.warn("WS Connection Error", data.payload.message)
|
||||||
|
this.websocket.close()
|
||||||
|
|
||||||
|
this.emit("error", new Error(data.payload.message))
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "data": {
|
||||||
|
if (data.payload.errors != null && data.payload.errors.length > 0) {
|
||||||
|
this.emit("error", data.payload.errors)
|
||||||
|
} else {
|
||||||
|
this.emit("data", data.payload.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.websocket.onerror = (err) => {
|
||||||
|
console.warn("WS Error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.websocket.onclose = () => {
|
||||||
|
this.emit("disconnect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
if (this.websocket != null) {
|
||||||
|
this.websocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { query, Subscription }
|
||||||
@@ -8,6 +8,7 @@ const config = require("./config")
|
|||||||
// Express depedencies
|
// Express depedencies
|
||||||
const express = require("express")
|
const express = require("express")
|
||||||
const proxy = require("express-http-proxy")
|
const proxy = require("express-http-proxy")
|
||||||
|
const proxy2 = require("http-proxy-middleware")
|
||||||
const lasso = require("lasso")
|
const lasso = require("lasso")
|
||||||
const lassoMiddleware = require("lasso/middleware")
|
const lassoMiddleware = require("lasso/middleware")
|
||||||
const markoExpress = require("marko/express")
|
const markoExpress = require("marko/express")
|
||||||
|
|||||||
Reference in New Issue
Block a user