Gisle Aune
6 years ago
14 changed files with 308 additions and 5 deletions
-
1build.js
-
6marko/page/data/changes.marko
-
2marko/page/data/components/add-channel-modal/index.marko
-
115marko/page/data/components/change/component.js
-
15marko/page/data/components/change/index.marko
-
8marko/page/data/components/change/style.less
-
16marko/page/data/components/changes-page/component.js
-
12marko/page/data/components/changes-page/index.marko
-
36marko/page/data/components/changes-page/style.less
-
1marko/page/data/components/data-menu/index.marko
-
2marko/page/data/components/edit-channel-modal/index.marko
-
15routes/data/changes.js
-
81rpdata/api/Change.js
-
1server.js
@ -0,0 +1,6 @@ |
|||
<include("../layout", {title: "Data", site: "data"})> |
|||
<@body> |
|||
<background src="/assets/images/bg.png" opacity=0.25 /> |
|||
<changes-page user=input.user changes=input.changes selected=input.selected /> |
|||
</@body> |
|||
</include> |
@ -0,0 +1,115 @@ |
|||
const moment = require("moment") |
|||
|
|||
module.exports = class { |
|||
onCreate() { |
|||
this.state = { |
|||
operation: "", |
|||
links: [], |
|||
parentLink: null, |
|||
} |
|||
} |
|||
|
|||
onInput(input) { |
|||
if (input.data) { |
|||
this.refresh(input.data) |
|||
} |
|||
} |
|||
|
|||
refresh(data) { |
|||
this.state.links = [] |
|||
this.state.operation = opText[data.op] |
|||
this.state.parentLink = null |
|||
|
|||
switch (data.model) { |
|||
case "Channel": { |
|||
const key = data.keys.find(k => k.id !== "*") |
|||
|
|||
this.state.operation += " channel" |
|||
this.state.links = [{ |
|||
text: key.id, |
|||
href: `/data/channels/`, |
|||
}] |
|||
|
|||
break |
|||
} |
|||
|
|||
case "Character": { |
|||
const character = data.objects.find(o => o.type === "Character") |
|||
|
|||
this.state.operation += " character" |
|||
this.state.links = [{ |
|||
text: `${character.name} (${character.id})`, |
|||
href: `/data/characters/`, |
|||
}] |
|||
|
|||
break |
|||
} |
|||
|
|||
case "Story": { |
|||
const key = data.keys.find(k => k.model === "Story" && k.id !== "*") |
|||
const story = data.objects.find(o => o.type === "Story") |
|||
|
|||
this.state.operation += " story" |
|||
this.state.links = [{ |
|||
text: story.name, |
|||
href: `/story/${key.id}`, |
|||
}] |
|||
|
|||
break |
|||
} |
|||
|
|||
case "Chapter": { |
|||
const storyKey = data.keys.find(k => k.model === "Story") |
|||
const chapterKey = data.keys.find(k => k.model === "Chapter") |
|||
const chapter = data.objects.find(o => o.type === "Chapter") |
|||
|
|||
this.state.operation += " chapter" |
|||
this.state.links = [{ |
|||
text: chapter.title, |
|||
href: `/story/${storyKey.id}#${chapterKey.id}`, |
|||
}] |
|||
|
|||
break |
|||
} |
|||
|
|||
case "Log": { |
|||
const key = data.keys.find(k => k.id !== "*") |
|||
|
|||
this.state.operation += " log" |
|||
this.state.links = [{ |
|||
text: key.id, |
|||
href: `/logs/${key.id}`, |
|||
}] |
|||
|
|||
break |
|||
} |
|||
|
|||
case "Post": { |
|||
const logKey = data.keys.find(k => k.model === "Log") |
|||
const postKeys = data.keys.filter(k => k.model === "Post") |
|||
const postObjs = data.objects.filter(o => o.type === "Post") |
|||
|
|||
this.state.operation += (postKeys.length > 1) ? " posts" : " post" |
|||
this.state.links = postObjs.map(po => ({ |
|||
text: `[${moment(po.time).format("HH:mm")}] ${po.nick}`, |
|||
href: `/logs/${logKey.id}#${po.id}`, |
|||
})) |
|||
this.state.parentLink = { |
|||
prefix: "in log", |
|||
text: `${logKey.id}`, |
|||
href: `/logs/${logKey.id}`, |
|||
} |
|||
|
|||
break |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
const opText = { |
|||
add: "added", |
|||
remove: "removed", |
|||
move: "moved", |
|||
edit: "edited", |
|||
import: "imported", |
|||
} |
@ -0,0 +1,15 @@ |
|||
import moment from "moment"; |
|||
|
|||
<div class="change"> |
|||
<span class="change-id color-menu">[${moment(input.data.date).format("MMM D HH:mm:SS")}] * </span> |
|||
<span class="author color-text">${input.data.author} </span> |
|||
<span class="text color-text">${state.operation} </span> |
|||
<span for(link in state.links | status-var=loop) key=link.href class="link"> |
|||
<a class="color-primary" href=link.href>${link.text}</a> |
|||
<span if(loop.getIndex() < state.links.length - 1) class="comma">, </span> |
|||
</span> |
|||
<if (state.parentLink != null)> |
|||
<span class="text"> ${state.parentLink.prefix} </span> |
|||
<a class="color-primary" href=state.parentLink.href>${state.parentLink.text}</a> |
|||
</if> |
|||
</div> |
@ -0,0 +1,8 @@ |
|||
div.change { |
|||
text-indent: -2ch; |
|||
margin-left: 2ch; |
|||
|
|||
a:hover { |
|||
text-decoration: underline; |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
module.exports = class { |
|||
onCreate(input) { |
|||
this.state = { |
|||
characters: input.characters, |
|||
modal: null, |
|||
} |
|||
} |
|||
|
|||
open(modal) { |
|||
this.state.modal = modal |
|||
} |
|||
|
|||
close() { |
|||
this.state.modal = null |
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
<data-menu categories=input.categories selected=(input.selected || {}) user=input.user on-open("open") /> |
|||
<main> |
|||
<div class="changes-page"> |
|||
<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> |
|||
<for (change in input.changes)> |
|||
<change data=change /> |
|||
</for> |
|||
</div> |
|||
</main> |
|||
<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") /> |
@ -0,0 +1,36 @@ |
|||
.changes-page { |
|||
width: 90%; |
|||
max-width: 95ch; |
|||
margin: auto; |
|||
|
|||
> p { |
|||
text-align: center; |
|||
} |
|||
|
|||
h1 { |
|||
font-weight: 200; |
|||
text-align: center; |
|||
} |
|||
|
|||
.header { |
|||
text-align: center; |
|||
vertical-align: middle; |
|||
margin-bottom: 1em; |
|||
|
|||
h1 { |
|||
display: block; |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
a { |
|||
vertical-align: middle; |
|||
display: inline-block; |
|||
padding: 0.5em 0.5ch 0.5em 0.5ch; |
|||
opacity: 0.5; |
|||
} |
|||
a:hover { |
|||
cursor: pointer; |
|||
opacity: 1; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
const express = require("express") |
|||
const router = express.Router() |
|||
|
|||
const {changesApi} = require("../../rpdata/api/Change") |
|||
|
|||
const changesTemplate = require("../../marko/page/data/changes.marko") |
|||
|
|||
router.get("/", async(req, res) => { |
|||
res.markoAsync(changesTemplate, { |
|||
changes: changesApi.list(), |
|||
selected: {changes: true}, |
|||
}) |
|||
}) |
|||
|
|||
module.exports = router |
@ -0,0 +1,81 @@ |
|||
const {query} = require("../client") |
|||
|
|||
class Change { |
|||
/** |
|||
* @param {string} id |
|||
* @param {string} model |
|||
* @param {string} op |
|||
* @param {string} author |
|||
* @param {Date | string | number} date |
|||
* @param {{model:string,id:string}[]} keys ' |
|||
* @param {{type:string, [x:string]:any}[]} objects |
|||
*/ |
|||
constructor(id, model, op, author, date, keys, objects) { |
|||
this.id = id |
|||
this.model = model |
|||
this.op = op |
|||
this.author = author |
|||
this.date = date |
|||
this.keys = keys |
|||
this.objects = objects |
|||
} |
|||
|
|||
static fromData(data) { |
|||
return new Change(data.id, data.model, data.op, data.author, data.date, data.keys, data.objects) |
|||
} |
|||
} |
|||
|
|||
class ChangesAPI { |
|||
/** |
|||
* Call `channels(filter)` query |
|||
* |
|||
* @param {{limit:int, keys: {model:string,id:string}[]}} filter |
|||
* @returns {Promise<Change[]>} |
|||
*/ |
|||
list(filter = null) { |
|||
return query(`
|
|||
query ListChanges($filter:ChangesFilter) { |
|||
changes(filter:$filter) { |
|||
id |
|||
model |
|||
op |
|||
author |
|||
date |
|||
keys { |
|||
model |
|||
id |
|||
} |
|||
objects { |
|||
type: __typename |
|||
|
|||
...on Character { |
|||
id |
|||
name |
|||
} |
|||
|
|||
...on Chapter { |
|||
id |
|||
title |
|||
} |
|||
|
|||
...on Story { |
|||
id |
|||
name |
|||
} |
|||
|
|||
...on Post { |
|||
id |
|||
time |
|||
nick |
|||
} |
|||
} |
|||
} |
|||
} |
|||
`, {filter}).then(({changes}) => {
|
|||
return changes.map(d => Change.fromData(d)) |
|||
}) |
|||
} |
|||
} |
|||
|
|||
module.exports = { Change, changesApi: new ChangesAPI } |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue