the last few things.
This commit is contained in:
@@ -1,11 +1,27 @@
|
|||||||
|
const { changesApi } = require("../../../../../rpdata/api/Change")
|
||||||
|
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate(input) {
|
onCreate(input) {
|
||||||
this.state = {
|
this.state = {
|
||||||
characters: input.characters,
|
changes: input.changes,
|
||||||
|
shownAll: false,
|
||||||
modal: null,
|
modal: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearLimit(e) {
|
||||||
|
// Disable mobile URL fallback.
|
||||||
|
if (e && e.preventDefault) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
changesApi.list({limit: 0}).then(changes => {
|
||||||
|
this.state.changes = changes
|
||||||
|
this.state.shownAll = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
open(modal) {
|
open(modal) {
|
||||||
this.state.modal = modal
|
this.state.modal = modal
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@
|
|||||||
<div class="changes-page">
|
<div class="changes-page">
|
||||||
<h1 class="color-primary">Changes</h1>
|
<h1 class="color-primary">Changes</h1>
|
||||||
<p>All changes to <em>listed</em> resources is stored for 90 days for transparency reasons. The current state of an object after each change exists, but is only available through the GraphQL API at this time.</p>
|
<p>All changes to <em>listed</em> resources is stored for 90 days for transparency reasons. The current state of an object after each change exists, but is only available through the GraphQL API at this time.</p>
|
||||||
<for (change in input.changes)>
|
<for (change in state.changes)>
|
||||||
<change data=change />
|
<change data=change />
|
||||||
</for>
|
</for>
|
||||||
|
<a if(!state.shownAll) href="/data/changes?limit=0" class="show-more-button" on-click("clearLimit")>Show All</a>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<add-character-modal enabled=(state.modal === "character.add") user=input.user on-added("characterAdded") on-close("close") />
|
<add-character-modal enabled=(state.modal === "character.add") user=input.user on-added("characterAdded") on-close("close") />
|
||||||
<add-channel-modal enabled=(state.modal === "channel.add") user=input.user on-close("close") />
|
<add-channel-modal enabled=(state.modal === "channel.add") user=input.user on-close("close") />
|
||||||
|
<add-file-modal enabled=(state.modal === "file.add") user=input.user on-close("close") />
|
||||||
|
|||||||
@@ -33,4 +33,21 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-more-button {
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 0.5em 2em;
|
||||||
|
font-size: 2em;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
color: #DA1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-more-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,96 +1,10 @@
|
|||||||
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader")
|
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate(input) {
|
onCreate(input) {
|
||||||
this.state = {
|
this.state = {
|
||||||
id: input.log.id,
|
id: input.log.id,
|
||||||
channelName: input.log.channelName,
|
channelName: input.log.channelName,
|
||||||
eventName: input.log.eventName,
|
eventName: input.log.eventName,
|
||||||
nexts: [],
|
|
||||||
prevs: [],
|
|
||||||
loaded: false,
|
|
||||||
error: null,
|
error: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount() {
|
|
||||||
this.timeout = setTimeout(() => {
|
|
||||||
logHeaderApi.list().then(logs => {
|
|
||||||
const index = logs.findIndex(l => l.id === this.state.id);
|
|
||||||
if (index === -1) {
|
|
||||||
return Promise.reject("This log not found in list.")
|
|
||||||
}
|
|
||||||
const log = logs[index]
|
|
||||||
const characterIds = log.characters.map(c => c.id);
|
|
||||||
const nexts = []
|
|
||||||
const prevs = []
|
|
||||||
let foundGroups = {}
|
|
||||||
let foundChannel = false
|
|
||||||
|
|
||||||
for (let i = index - 1; i >= 0; --i) {
|
|
||||||
const log2 = logs[i]
|
|
||||||
const hasEvent = (log.eventName ? log.eventName === log2.eventName : false)
|
|
||||||
const hasChannel = (log.channelName === log2.channelName)
|
|
||||||
|
|
||||||
const characters = log2.findCharacters(...characterIds)
|
|
||||||
const characterIdsKey = characters.map(c => c.id).sort().join(",")
|
|
||||||
|
|
||||||
const suggestion = {log: log2, characters, hasEvent, hasChannel}
|
|
||||||
|
|
||||||
if (hasChannel && !foundChannel) {
|
|
||||||
foundChannel = true
|
|
||||||
foundGroups[characterIdsKey] = true
|
|
||||||
|
|
||||||
nexts.push(suggestion)
|
|
||||||
} else if (hasEvent) {
|
|
||||||
foundGroups[characterIdsKey] = true
|
|
||||||
|
|
||||||
nexts.push(suggestion)
|
|
||||||
} else if (nexts.length < 8 && !hasEvent && characters.length > 1 && !foundGroups[characterIdsKey]) {
|
|
||||||
foundGroups[characterIdsKey] = true
|
|
||||||
nexts.push(suggestion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foundGroups = {}
|
|
||||||
foundChannel = false
|
|
||||||
|
|
||||||
for (let i = index + 1; i < logs.length; ++i) {
|
|
||||||
const log2 = logs[i]
|
|
||||||
const hasEvent = (log.eventName ? log.eventName === log2.eventName : false)
|
|
||||||
const hasChannel = (log.channelName === log2.channelName)
|
|
||||||
|
|
||||||
const characters = log2.findCharacters(...characterIds)
|
|
||||||
const characterIdsKey = characters.map(c => c.id).sort().join(",")
|
|
||||||
|
|
||||||
const suggestion = {log: log2, characters, hasEvent, hasChannel}
|
|
||||||
|
|
||||||
if (hasChannel && !foundChannel) {
|
|
||||||
foundChannel = true
|
|
||||||
foundGroups[characterIdsKey] = true
|
|
||||||
|
|
||||||
prevs.push(suggestion)
|
|
||||||
} else if (hasEvent) {
|
|
||||||
foundGroups[characterIdsKey] = true
|
|
||||||
|
|
||||||
prevs.push(suggestion)
|
|
||||||
} else if (prevs.length < 8 && !hasEvent && characters.length > 1 && !foundGroups[characterIdsKey]) {
|
|
||||||
foundGroups[characterIdsKey] = true
|
|
||||||
prevs.push(suggestion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.nexts = nexts;
|
|
||||||
this.state.prevs = prevs;
|
|
||||||
this.state.loaded = true;
|
|
||||||
}).catch(err => {
|
|
||||||
console.warn("Suggestions load error:", err)
|
|
||||||
this.suggestionsError = "Failed to load suggestions: " + err.toString()
|
|
||||||
})
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
onUnmount() {
|
|
||||||
clearTimeout(this.timeout)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
import moment from "moment"
|
import moment from "moment"
|
||||||
|
|
||||||
<div class="log-suggestions">
|
<div class="log-suggestions">
|
||||||
<if (state.loaded && state.error == null)>
|
<if (input.log.nextLogs.length > 0 || input.log.prevLogs.length > 0)>
|
||||||
<if (state.nexts.length > 0 || state.prevs.length > 0)>
|
<if (input.log.nextLogs.length > 0)>
|
||||||
<if (state.nexts.length > 0)>
|
|
||||||
<h2 class="color-primary">Next Logs</h2>
|
<h2 class="color-primary">Next Logs</h2>
|
||||||
<div for(s in state.nexts) class="suggestion color-primary">
|
<div for(s in input.log.nextLogs) class="suggestion color-primary">
|
||||||
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.name || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
|
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.title || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
|
||||||
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
|
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
|
||||||
<div class="suggestion-tags">
|
<div class="suggestion-tags">
|
||||||
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${s.log.eventName}</div>
|
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${input.log.eventName}</div>
|
||||||
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
|
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
|
||||||
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
|
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</if>
|
</if>
|
||||||
<if (state.prevs.length > 0)>
|
<if (input.log.prevLogs.length > 0)>
|
||||||
<h2 class="color-primary">Previous Logs</h2>
|
<h2 class="color-primary">Previous Logs</h2>
|
||||||
<div for(s in state.prevs) class="suggestion color-primary">
|
<div for(s in input.log.prevLogs) class="suggestion color-primary">
|
||||||
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.name || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
|
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.title || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
|
||||||
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
|
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
|
||||||
<div class="suggestion-tags">
|
<div class="suggestion-tags">
|
||||||
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${s.log.eventName}</div>
|
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${input.log.eventName}</div>
|
||||||
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
|
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
|
||||||
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
|
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,11 +30,4 @@ import moment from "moment"
|
|||||||
<else>
|
<else>
|
||||||
<div class="empty color-menu">(No suggestions)</div>
|
<div class="empty color-menu">(No suggestions)</div>
|
||||||
</else>
|
</else>
|
||||||
</if>
|
|
||||||
<else-if(state.error != null)>
|
|
||||||
<div class="error color-danger">{state.error}</div>
|
|
||||||
</else-if>
|
|
||||||
<else>
|
|
||||||
<div class="loading color-menu">Loading suggestions...</div>
|
|
||||||
</else>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -79,9 +79,14 @@ module.exports = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearLimit() {
|
clearLimit(e) {
|
||||||
this.state.filter = Object.assign({}, this.state.filter, {limit: 0})
|
this.state.filter = Object.assign({}, this.state.filter, {limit: 0})
|
||||||
|
|
||||||
|
// Disable mobile URL fallback.
|
||||||
|
if (e && e.preventDefault) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
this.refresh()
|
this.refresh()
|
||||||
this.updateQuery(this.state.filter)
|
this.updateQuery(this.state.filter)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<main class="logs-page with-right">
|
<main class="logs-page with-right">
|
||||||
<logs-table logs=state.logs on-addfilter("addFilter") />
|
<logs-table logs=state.logs on-addfilter("addFilter") />
|
||||||
<if(state.filter.limit > 0)>
|
<if(state.filter.limit > 0)>
|
||||||
<div class="show-more-button" on-click("clearLimit")>
|
<a href="/logs?limit=0" class="show-more-button" on-click("clearLimit")>
|
||||||
<span>Show All</span>
|
<span>Show All</span>
|
||||||
</div>
|
</a>
|
||||||
</if>
|
</if>
|
||||||
</main>
|
</main>
|
||||||
<add-log-modal enabled=(state.modal === "log.add") on-close("close") />
|
<add-log-modal enabled=(state.modal === "log.add") on-close("close") />
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
main.logs-page {
|
main.logs-page {
|
||||||
div.show-more-button {
|
.show-more-button {
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
padding: 0.5em 2em;
|
padding: 0.5em 2em;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
display: block;
|
||||||
|
|
||||||
color: #DA1;
|
color: #DA1;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.show-more-button:hover {
|
.show-more-button:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ const strategy = new Auth0Strategy({
|
|||||||
domain: config.auth0.domain,
|
domain: config.auth0.domain,
|
||||||
clientID: config.auth0.clientId,
|
clientID: config.auth0.clientId,
|
||||||
clientSecret: config.auth0.secret, // Replace this with the client secret for your app
|
clientSecret: config.auth0.secret, // Replace this with the client secret for your app
|
||||||
callbackURL: config.root + "/auth/callback"
|
callbackURL: config.root + "/auth/callback",
|
||||||
|
state: true,
|
||||||
}, (accessToken, refreshToken, extraParams, profile, done) => {
|
}, (accessToken, refreshToken, extraParams, profile, done) => {
|
||||||
// accessToken is the token to call Auth0 API (not needed in the most cases)
|
// accessToken is the token to call Auth0 API (not needed in the most cases)
|
||||||
// extraParams.id_token has the JSON Web Token
|
// extraParams.id_token has the JSON Web Token
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = session({
|
|||||||
secret: config.session.secret,
|
secret: config.session.secret,
|
||||||
store: new RedisStore(config.redis),
|
store: new RedisStore(config.redis),
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: config.session.secure
|
secure: config.session.secure,
|
||||||
},
|
},
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
|
|||||||
+8
-4
@@ -17,13 +17,17 @@ router.get("/login", saveReferer, passport.authenticate("auth0", {scope: "openid
|
|||||||
res.redirect("/")
|
res.redirect("/")
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get("/callback", passport.authenticate("auth0"), (req, res) => {
|
router.get("/callback", function (req, res, next) {
|
||||||
if (req.user == null) {
|
passport.authenticate("auth0", function (err, user, info) {
|
||||||
throw new Error("user null");
|
if (err) { return next(err) }
|
||||||
}
|
if (!user) { console.log(err, user, info); return res.redirect("/auth/login") }
|
||||||
|
req.logIn(user, function (err) {
|
||||||
|
if (err) { return next(err) }
|
||||||
|
|
||||||
res.redirect(req.session.loginReferrer || "/");
|
res.redirect(req.session.loginReferrer || "/");
|
||||||
})
|
})
|
||||||
|
})(req, res, next);
|
||||||
|
})
|
||||||
|
|
||||||
router.get("/user", (req, res) => {
|
router.get("/user", (req, res) => {
|
||||||
if (req.user == null) {
|
if (req.user == null) {
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ const {changesApi} = require("../../rpdata/api/Change")
|
|||||||
const changesTemplate = require("../../marko/page/data/changes.marko")
|
const changesTemplate = require("../../marko/page/data/changes.marko")
|
||||||
|
|
||||||
router.get("/", async(req, res) => {
|
router.get("/", async(req, res) => {
|
||||||
|
const limit = parseInt(req.query.limit) || 100
|
||||||
|
|
||||||
res.markoAsync(changesTemplate, {
|
res.markoAsync(changesTemplate, {
|
||||||
changes: changesApi.list({limit: 1000}),
|
changes: changesApi.list({limit}),
|
||||||
selected: {changes: true},
|
selected: {changes: true},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+19
-3
@@ -31,7 +31,11 @@ class Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromData(data) {
|
static fromData(data) {
|
||||||
return new Log(data.id, data.shortId, data.date, data.title, data.eventName, data.description, data.open, data.channel, data.characters, data.posts)
|
return new Log(
|
||||||
|
data.id, data.shortId, data.date,
|
||||||
|
data.title, data.eventName, data.description,
|
||||||
|
data.open, data.channel, data.characters, data.posts
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,10 +74,22 @@ class LogAPI {
|
|||||||
nick
|
nick
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
nextLogs {
|
||||||
|
log {id title date channelName}
|
||||||
|
hasEvent
|
||||||
|
hasChannel
|
||||||
|
characters {name}
|
||||||
|
}
|
||||||
|
prevLogs {
|
||||||
|
log {id title date channelName}
|
||||||
|
hasEvent
|
||||||
|
hasChannel
|
||||||
|
characters {name}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, {id}).then(({log}) => {
|
`, {id}).then(({log}) => {
|
||||||
return Log.fromData(log)
|
return log
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +235,7 @@ class LogAPI {
|
|||||||
subscribeChanges(logId) {
|
subscribeChanges(logId) {
|
||||||
return new Subscription(`
|
return new Subscription(`
|
||||||
subscription Changes($keys: [ChangeKeyInput!]!) {
|
subscription Changes($keys: [ChangeKeyInput!]!) {
|
||||||
changes(keys: $keys) {
|
changes(filter: {keys: $keys}) {
|
||||||
id
|
id
|
||||||
model
|
model
|
||||||
op
|
op
|
||||||
|
|||||||
Reference in New Issue
Block a user