Browse Source

data: Added channel list/add/edit

1.0
Gisle Aune 6 years ago
parent
commit
a5ac48e3d6
  1. 2
      marko/components/compact-list-property/index.marko
  2. 4
      marko/components/compact-list-property/style.less
  3. 3
      marko/components/toggle/style.less
  4. 6
      marko/page/data/channels.marko
  5. 50
      marko/page/data/components/add-channel-modal/component.js
  6. 24
      marko/page/data/components/add-channel-modal/index.marko
  7. 5
      marko/page/data/components/channel-list/index.marko
  8. 20
      marko/page/data/components/channel/component.js
  9. 10
      marko/page/data/components/channel/index.marko
  10. 34
      marko/page/data/components/channels-page/component.js
  11. 5
      marko/page/data/components/channels-page/index.marko
  12. 2
      marko/page/data/components/character/index.marko
  13. 2
      marko/page/data/components/characters-page/component.js
  14. 8
      marko/page/data/components/data-menu/index.marko
  15. 57
      marko/page/data/components/edit-channel-modal/component.js
  16. 21
      marko/page/data/components/edit-channel-modal/index.marko
  17. 2
      marko/page/data/components/edit-character-modal/index.marko
  18. 15
      routes/data/channels.js
  19. 69
      rpdata/api/Channel.js
  20. 1
      server.js

2
marko/components/compact-list-property/index.marko

@ -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>

4
marko/components/compact-list-property/style.less

@ -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 {

3
marko/components/toggle/style.less

@ -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;

6
marko/page/data/channels.marko

@ -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>

50
marko/page/data/components/add-channel-modal/component.js

@ -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
})
}
}

24
marko/page/data/components/add-channel-modal/index.marko

@ -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>

5
marko/page/data/components/channel-list/index.marko

@ -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>

20
marko/page/data/components/channel/component.js

@ -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
}
}

10
marko/page/data/components/channel/index.marko

@ -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>

34
marko/page/data/components/channels-page/component.js

@ -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))
}
}

5
marko/page/data/components/channels-page/index.marko

@ -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") />

2
marko/page/data/components/character/index.marko

@ -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>

2
marko/page/data/components/characters-page/component.js

@ -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
}

8
marko/page/data/components/data-menu/index.marko

@ -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>

57
marko/page/data/components/edit-channel-modal/component.js

@ -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
})
}
}

21
marko/page/data/components/edit-channel-modal/index.marko

@ -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>

2
marko/page/data/components/edit-character-modal/index.marko

@ -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>

15
routes/data/channels.js

@ -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

69
rpdata/api/Channel.js

@ -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 }

1
server.js

@ -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) {

Loading…
Cancel
Save