data: Added channel list/add/edit
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<td class=["compact-list-property", input.short ? "short" : null, input.long ? "long" : null]>
|
||||
<div class="label color-menu">${input.label}</div>
|
||||
<div class=["value", input.primary ? "color-primary" : "color-text"]>${input.value}</div>
|
||||
<div class=["value", input.primary ? "color-primary" : "color-text", input.weak ? "weak" : null] title=input.title>${input.value}</div>
|
||||
</td>
|
||||
@@ -13,6 +13,10 @@ td.compact-list-property {
|
||||
padding-bottom: 0.25em;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
div.value.weak {
|
||||
opacity: 0.3333;
|
||||
}
|
||||
}
|
||||
|
||||
td.compact-list-property.short {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
div.toggle {
|
||||
div.toggle-pill {
|
||||
display: inline-block;
|
||||
margin: 0.5em;
|
||||
margin-bottom: 0;
|
||||
margin: 0 0.5em;
|
||||
|
||||
a.toggle-option {
|
||||
padding: 0.125em 0.5ch;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<include("../layout", {title: "Data", site: "data"})>
|
||||
<@body>
|
||||
<background src="/assets/images/bg.png" opacity=0.25 />
|
||||
<channels-page user=input.user channels=input.channels selected=input.selected />
|
||||
</@body>
|
||||
</include>
|
||||
@@ -0,0 +1,50 @@
|
||||
const moment = require("moment")
|
||||
|
||||
const {channelApi} = require("../../../../../rpdata/api/Channel")
|
||||
|
||||
module.exports = class {
|
||||
onCreate(input) {
|
||||
this.state = {
|
||||
error: null,
|
||||
loading: false,
|
||||
values: {
|
||||
name: "",
|
||||
locationName: "",
|
||||
eventName: "",
|
||||
logged: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
change(key, ev) {
|
||||
this.state.values = Object.assign({}, this.state.values, {[key]: ev.target.value})
|
||||
}
|
||||
|
||||
open() {
|
||||
|
||||
}
|
||||
|
||||
close() {
|
||||
this.emit("close")
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.state.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
const input = Object.assign({}, this.state.values)
|
||||
|
||||
this.state.loading = true
|
||||
channelApi.add(input).then((res) => {
|
||||
this.emit("added", res)
|
||||
this.emit("close")
|
||||
}).catch(errs => {
|
||||
console.warn("Failed to add:", errs)
|
||||
|
||||
this.state.error = "Failed to add: " + JSON.stringify(errs)
|
||||
}).then(() => {
|
||||
this.state.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<modal class="modal color-text nolabel" key="modal" enabled=(input.enabled) closable on-close("close") on-open("open") >
|
||||
<h1>Add Channel</h1>
|
||||
|
||||
<p class="color-error">${state.error}</p>
|
||||
|
||||
<label>Name</label>
|
||||
<input key="name" placeholder="(Required)" class="big" on-change("change", "name") value=state.values.name />
|
||||
|
||||
<label>Event Name</label>
|
||||
<input key="eventName" placeholder="(None)" on-change("change", "eventName") value=state.values.eventName />
|
||||
|
||||
<label>Location Name</label>
|
||||
<input key="locationName" placeholder="(None)" on-change("change", "locationName") value=state.values.locationName />
|
||||
|
||||
<label>Logged</label>
|
||||
<toggle value=state.values.logged on="On" off="Off"
|
||||
onDesc="Log new posts in this channel."
|
||||
offDesc="The logbot will not monitor this channel."
|
||||
on-change("change", "logged") />
|
||||
|
||||
<p class="color-danger" if(state.values.logged)>The logbot is not yet available, so this does nothing right now.</p>
|
||||
|
||||
<button disabled=state.loading on-click("save")>Save</button>
|
||||
</modal>
|
||||
@@ -0,0 +1,5 @@
|
||||
<compact-list>
|
||||
<compact-list-item for(channel in input.channels) key=(channel.name.replace("'", "_APOS_"))>
|
||||
<channel data=channel on-edited("emit", "edited", channel)/>
|
||||
</compact-list-item>
|
||||
</compact-list>
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = class {
|
||||
onCreate() {
|
||||
this.state = {
|
||||
modal: null,
|
||||
deleted: false,
|
||||
}
|
||||
}
|
||||
|
||||
open(modal) {
|
||||
this.state.modal = modal
|
||||
}
|
||||
|
||||
close() {
|
||||
this.state.modal = null
|
||||
}
|
||||
|
||||
removed() {
|
||||
this.state.deleted = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<if (!state.deleted)>
|
||||
<compact-list-property primary label="Name" value=input.data.name />
|
||||
<compact-list-property label="Event" weak=(input.data.eventName === "") value=(input.data.eventName || "None") />
|
||||
<compact-list-property long label="Location" weak=(input.data.locationName === "") value=(input.data.locationName || "None") />
|
||||
<compact-list-property short weak=!input.data.logged short label="Logged" value=(input.data.logged ? "On" : "Off") />
|
||||
<compact-list-options>
|
||||
<a on-click("open", "edit")>Edit</a>
|
||||
</compact-list-options>
|
||||
<edit-channel-modal enabled=(state.modal === "edit") channel=input.data on-edited("emit", "edited") on-close("close") />
|
||||
</if>
|
||||
@@ -0,0 +1,34 @@
|
||||
module.exports = class {
|
||||
onCreate(input) {
|
||||
this.state = {
|
||||
channels: input.channels,
|
||||
modal: null,
|
||||
}
|
||||
}
|
||||
|
||||
open(modal) {
|
||||
this.state.modal = modal
|
||||
}
|
||||
|
||||
close() {
|
||||
this.state.modal = null
|
||||
}
|
||||
|
||||
channelEdited(channel, patch) {
|
||||
const channels = this.state.channels.slice()
|
||||
const index = channels.findIndex(c => c.name === channel.name)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
channels[index] = Object.assign({}, channels[index], patch)
|
||||
|
||||
this.state.channels = channels
|
||||
|
||||
console.log(channels[index])
|
||||
}
|
||||
|
||||
channelAdded(channel) {
|
||||
this.state.channels = this.state.channels.concat(channel).sort((a,b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<data-menu categories=input.categories selected=(input.selected || {}) user=input.user on-open("open") />
|
||||
<main>
|
||||
<channel-list channels=state.channels on-edited("channelEdited") />
|
||||
</main>
|
||||
<add-channel-modal enabled=(state.modal === "channel.add") user=input.user on-added("channelAdded") on-close("close") />
|
||||
@@ -1,6 +1,6 @@
|
||||
<if (!state.deleted)>
|
||||
<compact-list-property primary short label="ID" value=input.data.id />
|
||||
<compact-list-property label="Nick" value=(input.data.nick) weak=("+" + (input.data.nicks.length - 1)) showWeak=(input.data.nicks.length > 0) />
|
||||
<compact-list-property title=input.data.nicks.join(", ") label="Nick" value=(input.data.nick) />
|
||||
<compact-list-property long label="Name" value=input.data.name />
|
||||
<compact-list-property short label="Author" value=input.data.author />
|
||||
<compact-list-options long>
|
||||
|
||||
@@ -25,7 +25,7 @@ module.exports = class {
|
||||
return
|
||||
}
|
||||
|
||||
characters[index] = Object.assign(characters[index], patch)
|
||||
characters[index] = Object.assign({}, characters[index], patch)
|
||||
|
||||
this.state.characters = characters
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<menu user=input.user>
|
||||
<menu-header>List</menu-header>
|
||||
<menu-link key="characters" selected=input.selected.characters icon="C" href="/data/characters/">Characters</menu-link>
|
||||
<menu-link key="channels" selected=input.selected.channels icon="#" href="/data/characters/">Channels</menu-link>
|
||||
<menu-link key="channels" selected=input.selected.channels icon="#" href="/data/channels/">Channels</menu-link>
|
||||
<menu-gap />
|
||||
<menu-header>Options</menu-header>
|
||||
<menu-link dark key="characters_add" icon="+" on-click("emit", "open", "character.add")>Add Character</menu-link>
|
||||
<menu-link dark key="channels_add" icon="+" on-click("emit", "open", "channel.add")>Add Channel</menu-link>
|
||||
<menu-header>Add</menu-header>
|
||||
<menu-link dark key="characters_add" icon="+" on-click("emit", "open", "character.add")>Character</menu-link>
|
||||
<menu-link dark key="channels_add" icon="+" on-click("emit", "open", "channel.add")>Channel</menu-link>
|
||||
</menu>
|
||||
@@ -0,0 +1,57 @@
|
||||
const moment = require("moment")
|
||||
|
||||
const {channelApi} = require("../../../../../rpdata/api/Channel")
|
||||
|
||||
module.exports = class {
|
||||
onCreate(input) {
|
||||
this.state = {
|
||||
error: null,
|
||||
loading: false,
|
||||
values: {
|
||||
locationName: "",
|
||||
eventName: "",
|
||||
logged: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
change(key, ev) {
|
||||
this.state.values = Object.assign({}, this.state.values, {[key]: ev.target.value})
|
||||
}
|
||||
|
||||
onInput(input) {
|
||||
this.state.values = {
|
||||
eventName: input.channel.eventName,
|
||||
locationName: input.channel.locationName,
|
||||
logged: input.channel.logged,
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
|
||||
}
|
||||
|
||||
close() {
|
||||
this.emit("close")
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.state.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
const input = Object.assign({name: this.input.channel.name}, this.state.values)
|
||||
|
||||
this.state.loading = true
|
||||
channelApi.edit(input).then((res) => {
|
||||
this.emit("edited", res)
|
||||
this.emit("close")
|
||||
}).catch(errs => {
|
||||
console.warn("Failed to edit:", errs)
|
||||
|
||||
this.state.error = "Failed to edit: " + errs[0].message
|
||||
}).then(() => {
|
||||
this.state.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<modal class="modal color-text nolabel" key="modal" enabled=(input.enabled) closable on-close("close") on-open("open") >
|
||||
<h1>Edit ${input.channel.name}</h1>
|
||||
|
||||
<p class="color-error">${state.error}</p>
|
||||
|
||||
<label>Event Name</label>
|
||||
<input key="eventName" placeholder="(None)" on-change("change", "eventName") value=state.values.eventName />
|
||||
|
||||
<label>Location Name</label>
|
||||
<input key="locationName" placeholder="(None)" on-change("change", "locationName") value=state.values.locationName />
|
||||
|
||||
<label>Logged</label>
|
||||
<toggle value=state.values.logged on="On" off="Off"
|
||||
onDesc="Log new posts in this channel."
|
||||
offDesc="The logbot will not monitor this channel."
|
||||
on-change("change", "logged") />
|
||||
|
||||
<p class="color-danger" if(state.values.logged)>The logbot is not yet available, so this does nothing right now.</p>
|
||||
|
||||
<button disabled=state.loading on-click("save")>Save</button>
|
||||
</modal>
|
||||
@@ -12,5 +12,5 @@
|
||||
<label>Description</label>
|
||||
<textarea key="description" placeholder="Description" on-change("change", "description") value=state.values.description />
|
||||
|
||||
<button disabled=state.loading on-click("save")>Save character!</button>
|
||||
<button disabled=state.loading on-click("save")>Save</button>
|
||||
</modal>
|
||||
@@ -0,0 +1,15 @@
|
||||
const express = require("express")
|
||||
const router = express.Router()
|
||||
|
||||
const {channelApi} = require("../../rpdata/api/Channel")
|
||||
|
||||
const channelsTemplate = require("../../marko/page/data/channels.marko")
|
||||
|
||||
router.get("/", async(req, res) => {
|
||||
res.markoAsync(channelsTemplate, {
|
||||
channels: channelApi.list(),
|
||||
selected: { channels: true },
|
||||
})
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
+68
-1
@@ -14,4 +14,71 @@ class Channel {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Channel }
|
||||
class ChannelAPI {
|
||||
/**
|
||||
* Call `channels(filter)` query
|
||||
*
|
||||
* @param {{logged:boolean, eventName:string, locationName:string}} filter
|
||||
* @returns {Promise<Channel[]>}
|
||||
*/
|
||||
list(filter = {}) {
|
||||
return query(`
|
||||
query ListChannel($filter: ChannelsFilter) {
|
||||
channels(filter: $filter) {
|
||||
name
|
||||
logged
|
||||
hub
|
||||
eventName
|
||||
locationName
|
||||
}
|
||||
}
|
||||
`, {filter}).then(({channels}) => {
|
||||
return channels.map(d => Channel.fromData(d))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `channels(filter)` query
|
||||
*
|
||||
* @param {{name:string, logged:boolean, eventName:string, locationName:string}} filter
|
||||
* @returns {Promise<Channel>}
|
||||
*/
|
||||
add(input = {}) {
|
||||
return query(`
|
||||
mutation AddChannel($input: ChannelAddInput!) {
|
||||
addChannel(input: $input) {
|
||||
name
|
||||
hub
|
||||
logged
|
||||
eventName
|
||||
locationName
|
||||
}
|
||||
}
|
||||
`, {input}, {permissions: ["channel.add"]}).then(({addChannel}) => {
|
||||
return Channel.fromData(addChannel)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `channels(filter)` query
|
||||
*
|
||||
* @param {{name:string, logged:boolean, eventName:string, locationName:string}} filter
|
||||
* @returns {Promise<{name:string, logged:boolean, eventName:string, locationName:string}>}
|
||||
*/
|
||||
edit(input = {}) {
|
||||
return query(`
|
||||
mutation EditChannel($input: ChannelEditInput!) {
|
||||
editChannel(input: $input) {
|
||||
name
|
||||
logged
|
||||
eventName
|
||||
locationName
|
||||
}
|
||||
}
|
||||
`, {input}, {permissions: ["channel.edit"]}).then(({editChannel}) => {
|
||||
return editChannel
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Channel, channelApi: new ChannelAPI }
|
||||
@@ -82,6 +82,7 @@ app.use("/logs/", require("./routes/logs"))
|
||||
app.use("/logs/:id([0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-9]{9}_[A-Za-z\,\']{2,})/", require("./routes/logs-content"))
|
||||
app.use("/data/", require("./routes/data"))
|
||||
app.use("/data/characters/", require("./routes/data/characters"))
|
||||
app.use("/data/channels/", require("./routes/data/channels"))
|
||||
|
||||
// Entry point
|
||||
app.get("/", function(req, res) {
|
||||
|
||||
Reference in New Issue
Block a user