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,15 +19,11 @@ module.exports = class {
|
||||
}
|
||||
|
||||
onInput(input) {
|
||||
if (input.log && !this.first) {
|
||||
this.state.values = {
|
||||
title: input.log.title,
|
||||
event: input.log.eventName,
|
||||
description: input.log.description,
|
||||
open: input.log.open,
|
||||
}
|
||||
|
||||
this.first = true
|
||||
this.state.values = {
|
||||
title: input.log.title,
|
||||
event: input.log.eventName,
|
||||
description: input.log.description,
|
||||
open: input.log.open,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const moment = require("moment")
|
||||
|
||||
const {postApi} = require("../../../../../rpdata/api/Post")
|
||||
const {logsApi} = require("../../../../../rpdata/api/Log")
|
||||
|
||||
module.exports = class {
|
||||
onCreate(input) {
|
||||
@@ -9,6 +10,22 @@ module.exports = class {
|
||||
modal: null,
|
||||
removed: false,
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -30,8 +47,6 @@ module.exports = class {
|
||||
for (const patch of patches) {
|
||||
const index = posts.findIndex(p => p.id === patch.id)
|
||||
if (index == -1) {
|
||||
console.warn("Post not found for patch:", patch)
|
||||
// TODO: Force full refresh
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -42,8 +57,7 @@ module.exports = class {
|
||||
posts.sort((a, b) => a.position - b.position)
|
||||
for (let i = 1; i < posts.length; ++i) {
|
||||
if (posts[i].position !== posts[i - 1].position + 1) {
|
||||
console.warn("Discontinuity detected!")
|
||||
// TODO: Force full refresh
|
||||
console.warn("Discontinuity detected:", i, posts)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,15 +79,7 @@ module.exports = class {
|
||||
|
||||
removePost(post) {
|
||||
postApi.remove({id: post.id}).then(() => {
|
||||
this.state.log.posts = this.state.log.posts.filter(p => p.id !== post.id)
|
||||
|
||||
for (const p of this.state.log.posts) {
|
||||
if (p.position > post.position) {
|
||||
p.position--
|
||||
}
|
||||
}
|
||||
|
||||
this.state.log = Object.assign({}, this.state.log)
|
||||
this.postRemoved(post)
|
||||
}).catch(errs => {
|
||||
console.warn("Failed to delete:", errs)
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
this.state.log.posts = this.state.log.posts.concat([post])
|
||||
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() {
|
||||
this.state.removed = true
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader")
|
||||
const { logHeaderApi } = require("../../../../../rpdata/api/LogHeader")
|
||||
|
||||
module.exports = class {
|
||||
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-session": "^1.15.6",
|
||||
"graphql-query-compress": "^1.1.0",
|
||||
"http-proxy-middleware": "^0.19.1",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"jsonwebtoken": "^8.3.0",
|
||||
"lasso": "^3.2.6",
|
||||
@@ -41,5 +42,8 @@
|
||||
"passport": "^0.4.0",
|
||||
"passport-auth0": "^1.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 jwt = require("jsonwebtoken")
|
||||
|
||||
@@ -44,6 +45,7 @@ router.post("/", (req, res) => {
|
||||
})
|
||||
})
|
||||
|
||||
router.use("/", proxy(config.graphqlEndpoint, {ws: true}))
|
||||
|
||||
/**
|
||||
* @param {string} user
|
||||
|
||||
+43
-2
@@ -1,4 +1,4 @@
|
||||
const {query} = require("../client")
|
||||
const {query, Subscription} = require("../client")
|
||||
|
||||
const {Character} = require("./Character")
|
||||
const {Channel} = require("./Channel")
|
||||
@@ -193,7 +193,6 @@ class LogAPI {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call `removeLog(input)` mutation, returns the id
|
||||
*
|
||||
@@ -211,6 +210,48 @@ class LogAPI {
|
||||
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 }
|
||||
+86
-1
@@ -1,3 +1,4 @@
|
||||
const EventEmitter = require("events")
|
||||
const fetch = require("isomorphic-fetch")
|
||||
const config = require("../config")
|
||||
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
|
||||
const express = require("express")
|
||||
const proxy = require("express-http-proxy")
|
||||
const proxy2 = require("http-proxy-middleware")
|
||||
const lasso = require("lasso")
|
||||
const lassoMiddleware = require("lasso/middleware")
|
||||
const markoExpress = require("marko/express")
|
||||
|
||||
Reference in New Issue
Block a user