Gisle Aune
6 years ago
15 changed files with 409 additions and 23 deletions
-
8marko/components/menu-link/component.js
-
2marko/page/logs-content/components/logs-content-menu/index.marko
-
147marko/page/logs/components/add-filter-modal-body/component.js
-
12marko/page/logs/components/add-filter-modal-body/index.marko
-
16marko/page/logs/components/add-filter-modal/component.js
-
7marko/page/logs/components/add-filter-modal/index.marko
-
16marko/page/logs/components/add-filter-modal/style.less
-
64marko/page/logs/components/logs-menu/component.js
-
6marko/page/logs/components/logs-menu/index.marko
-
37marko/page/logs/components/page/component.js
-
5marko/page/logs/components/page/index.marko
-
2marko/page/logs/list.marko
-
22routes/logs/index.js
-
49rpdata/api/Character.js
-
39rpdata/api/LogHeader.js
@ -0,0 +1,147 @@ |
|||
const {channelApi} = require("../../../../../rpdata/api/Channel") |
|||
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader") |
|||
|
|||
module.exports = class { |
|||
onCreate() { |
|||
this.state = { |
|||
search: "", |
|||
filters: [], |
|||
channels: [], |
|||
eventNames: [], |
|||
} |
|||
|
|||
this.first = true |
|||
} |
|||
|
|||
onInput(input) { |
|||
if (input.filters) { |
|||
if (this.timeout != null) { |
|||
setTimeout(() => { |
|||
this.searchFilters() |
|||
}, 1) |
|||
} |
|||
} |
|||
|
|||
console.log(input.eventNames) |
|||
} |
|||
|
|||
onMount() { |
|||
this.timeout = null |
|||
|
|||
if (this.state.channels.length === 0) { |
|||
channelApi.list().then(channels => { |
|||
this.state.channels = channels |
|||
this.searchFilters() |
|||
}).catch(err => { |
|||
console.warn("Failed to fetch channels:", err) |
|||
}) |
|||
} |
|||
|
|||
if (this.state.eventNames.length === 0) { |
|||
logHeaderApi.eventNames().then(eventNames => { |
|||
this.state.eventNames = eventNames |
|||
this.searchFilters() |
|||
}).catch(err => { |
|||
console.warn("Failed to fetch eventNames:", err) |
|||
}) |
|||
} |
|||
|
|||
this.getEl("search").addEventListener("keydown", ev => { |
|||
if (this.waiting) { |
|||
return |
|||
} |
|||
|
|||
if (this.timeout != null) { |
|||
clearTimeout(this.timeout) |
|||
} |
|||
|
|||
this.timeout = setTimeout(() => { |
|||
this.timeout = null |
|||
this.state.search = ev.target.value |
|||
|
|||
this.searchFilters() |
|||
}, 200) |
|||
}) |
|||
} |
|||
|
|||
onUnmount() { |
|||
clearTimeout(this.timeout) |
|||
this.timeout = null |
|||
|
|||
this.state.search = "" |
|||
this.state.filters = [] |
|||
} |
|||
|
|||
add(type, value, filter) { |
|||
this.emit("add", type, value) |
|||
|
|||
this.state.filters = this.state.filters.filter(f => f != filter) |
|||
} |
|||
|
|||
searchFilters() { |
|||
const filters = [] |
|||
const search = this.state.search.toLowerCase() |
|||
|
|||
for (const channel of this.state.channels) { |
|||
if (search == "" || channel.name.toLowerCase().includes(search)) { |
|||
if (this.input.filter.channels && this.input.filter.channels.includes(channel.name)) { |
|||
continue |
|||
} |
|||
|
|||
filters.push({ |
|||
colorClass: "color-tag-location", |
|||
text: channel.name, |
|||
type: "channels", |
|||
value: channel.name, |
|||
}) |
|||
} |
|||
} |
|||
|
|||
for (const name of this.state.eventNames) { |
|||
if (search == "" || name.toLowerCase().includes(search)) { |
|||
if (this.input.filter.events && this.input.filter.events.includes(name)) { |
|||
continue |
|||
} |
|||
|
|||
filters.push({ |
|||
colorClass: "color-tag-event", |
|||
text: name, |
|||
type: "events", |
|||
value: name, |
|||
}) |
|||
} |
|||
} |
|||
|
|||
for (const character of this.input.characters) { |
|||
if (search == "" || character.name.toLowerCase().includes(search)) { |
|||
if (this.input.filter.characters && this.input.filter.characters.includes(character.id)) { |
|||
continue |
|||
} |
|||
|
|||
filters.push({ |
|||
colorClass: "color-tag-character", |
|||
text: character.name, |
|||
type: "characters", |
|||
value: character.id, |
|||
}) |
|||
} |
|||
} |
|||
|
|||
filters.sort((a, b) => { |
|||
let aCompare = a.text |
|||
let bCompare = b.text |
|||
|
|||
if (a.text.charAt(0) === "#") { |
|||
aCompare = a.text.slice(1) |
|||
} |
|||
if (b.text.charAt(0) === "#") { |
|||
bCompare = b.text.slice(1) |
|||
} |
|||
|
|||
return aCompare.localeCompare(bCompare) |
|||
}) |
|||
|
|||
this.state.filters = filters |
|||
} |
|||
|
|||
} |
@ -0,0 +1,12 @@ |
|||
<label>Search</label> |
|||
<input key="search" placeholder="" class="big" value=state.search /> |
|||
|
|||
<label>Filters</label> |
|||
<div if(state.search.length > 0) class="filter-row" > |
|||
<div class=["content", "color-text"]>Search: ${state.search}</div> |
|||
<button disabled=state.loading on-click("emit", "add", "search", state.search)>${input.filter.search ? "Replace" : "Add"}</button> |
|||
</div> |
|||
<div for(filter in state.filters) class="filter-row" > |
|||
<div class=["content", filter.colorClass]>${filter.text}</div> |
|||
<button disabled=state.loading on-click("add", filter.type, filter.value, filter)>Add</button> |
|||
</div> |
@ -0,0 +1,16 @@ |
|||
const moment = require("moment") |
|||
|
|||
const {logsApi} = require("../../../../../rpdata/api/Log") |
|||
|
|||
module.exports = class { |
|||
onCreate(input) { |
|||
this.state = { |
|||
filters: [], |
|||
search: "", |
|||
} |
|||
} |
|||
|
|||
close() { |
|||
this.emit("close") |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
import moment from "moment" |
|||
|
|||
<modal class="modal color-text nolabel" key="modal" enabled=(input.enabled) closable on-close("close") > |
|||
<h1 key="stuff">Add Filter</h1> |
|||
|
|||
<add-filter-modal-body characters=input.characters filter=input.filter on-add("emit", "add") /> |
|||
</modal> |
@ -0,0 +1,16 @@ |
|||
div.filter-row { |
|||
padding: 0.25em; |
|||
border-bottom: 1px solid rgba(0, 220, 255, 0.125); |
|||
|
|||
div.content { |
|||
width: 80%; |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
button { |
|||
width: 20% !important; |
|||
display: inline-block !important; |
|||
margin: 0 !important; |
|||
} |
|||
} |
@ -1,4 +1,68 @@ |
|||
module.exports = class { |
|||
onCreate() { |
|||
this.state = { |
|||
filters: [], |
|||
filtered: false, |
|||
} |
|||
} |
|||
|
|||
onInput(input) { |
|||
if (!input.filter) { |
|||
this.state.filters = [] |
|||
this.state.filtered = false |
|||
return |
|||
} |
|||
|
|||
const filters = [] |
|||
const {characters, channels, events, search} = input.filter |
|||
|
|||
if (search != null) { |
|||
filters.push({ |
|||
type: "search", |
|||
key: "search", |
|||
icon: "T", |
|||
color: "color-text", |
|||
text: search, |
|||
}) |
|||
} |
|||
|
|||
for (const character of (characters || [])) { |
|||
filters.push({ |
|||
type: "characters", |
|||
key: character, |
|||
icon: "C", |
|||
color: "color-tag-character", |
|||
id: character, |
|||
text: (input.characters.find(c => c.id === character) || {name: "Unknown ("+character+")"}).name, |
|||
}) |
|||
} |
|||
|
|||
for (const channel of (channels || [])) { |
|||
filters.push({ |
|||
type: "channels", |
|||
key: channel.replace(/'/g, "__"), |
|||
icon: "#", |
|||
color: "color-tag-location", |
|||
id: channel, |
|||
text: channel, |
|||
}) |
|||
} |
|||
|
|||
for (const event of (events || [])) { |
|||
filters.push({ |
|||
type: "events", |
|||
key: event.replace(/['\s\.]/g, "__"), |
|||
icon: "E", |
|||
color: "color-tag-event", |
|||
id: event, |
|||
text: event, |
|||
}) |
|||
} |
|||
|
|||
this.state.filters = filters |
|||
this.state.filtered = (filters.length > 0) |
|||
} |
|||
|
|||
select(value) { |
|||
this.emit("select", value) |
|||
} |
@ -1,10 +1,12 @@ |
|||
<menu user=input.user> |
|||
<menu-header key="logs">Logs</menu-header> |
|||
<menu-link key="logs" selected=input.selected.index icon="L" href="/logs/">All</menu-link> |
|||
<menu-link key="logs" selected=(input.selected.index && !state.filtered) icon="L" href="/logs/">All</menu-link> |
|||
<if-permitted key="if-permitted" user=input.user permission="log.add"> |
|||
<menu-link key="add_log" dark on-click("select", "add") icon="+">Add Log</menu-link> |
|||
<menu-link key="add_log" dark on-click("select", "log.add") icon="+">Add Log</menu-link> |
|||
</if-permitted> |
|||
<menu-gap /> |
|||
<menu-header key="filters">Filters</menu-header> |
|||
<menu-link for(filter in state.filters) textClass=filter.color unselectable icon=filter.icon on-click("emit", "removefilter", filter.type, filter.id)>${filter.text}</menu-link> |
|||
<menu-link key="add_filter" dark on-click("select", "filter.add") icon="+">Add Filter</menu-link> |
|||
<menu-gap /> |
|||
</menu> |
@ -1,6 +1,7 @@ |
|||
<background src="/assets/images/bg.png" opacity=0.25 /> |
|||
<logs-menu key="menu" on-select("open") selected=(input.selected || {}) user=input.user /> |
|||
<logs-menu key="menu" on-select("open") on-removefilter("removeFilter") selected=(input.selected || {}) user=input.user filter=state.filter characters=input.characters /> |
|||
<main> |
|||
<logs-list logs=state.logs /> |
|||
</main> |
|||
<add-log-modal enabled=(state.modal === "add") on-close("close") /> |
|||
<add-log-modal enabled=(state.modal === "log.add") on-close("close") /> |
|||
<add-filter-modal enabled=(state.modal === "filter.add") characters=input.characters filter=state.filter on-add("addFilter") on-close("close") /> |
@ -1,6 +1,6 @@ |
|||
<include("../layout", {title: "Logs", site: "logs"})> |
|||
<@body> |
|||
<!-- Page needed to get component.js functionality --> |
|||
<page logs=input.logs user=input.user selected=input.selected /> |
|||
<page logs=input.logs filter=input.filter characters=input.characters user=input.user selected=input.selected /> |
|||
</@body> |
|||
</include> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue