Compare commits

..

20 Commits

Author SHA1 Message Date
FoxxMD
fd5a92758d Merge branch 'edge' 2021-11-28 19:43:20 -05:00
FoxxMD
027199d788 docs(heroku): Add information on dyno usage 2021-11-15 17:27:42 -05:00
FoxxMD
2a9f01b928 fix(heroku): Add OPERATOR to heroku deploy template 2021-11-15 17:26:34 -05:00
FoxxMD
cf54502f0d fix(heroku): Add redirect uri env to heroku deploy template 2021-11-15 17:26:34 -05:00
FoxxMD
2a3663ccc9 refactor(heroku): heroku-specific docker change
* Add image for web and worker
* Refactor port usage to conform to heroku's usage
2021-11-15 17:26:34 -05:00
FoxxMD
dc2eeffcb5 fix(bot): Remove own profile "sub" from default moderated subreddits to run on
The user profile for the bot account is returning as a moderated "subreddit" EX (/u/ContextMotBot) but its not useable by CM because it does not have a wiki and users don't use this as a sub. Filter it out of moderated subreddits when using the default behavior.
2021-11-15 13:19:21 -05:00
FoxxMD
39daa11f2d Merge branch 'edge' 2021-11-15 12:53:28 -05:00
FoxxMD
93de38a845 fix(filter): Missing 'op' property test on itemIs for comment 2021-11-15 12:47:34 -05:00
FoxxMD
43caaca1f2 fix(config): Fix wrong provider data used when bot has no caching config
Use previously built defaultProvider, instead of hardcoded memory config, so any cache config from operator waterfalls to bot/subreddit

Closes #46
2021-11-02 15:55:03 -04:00
FoxxMD
7bcc0195fe fix(author): change include/exclude on RULE to be optional
One of these properties must be present for the rule to be valid. This is enforced at runtime. Change the schema so that both are optional from the config-side though.
2021-11-02 09:41:55 -04:00
FoxxMD
dac6541e28 Merge branch 'edge' 2021-11-01 16:12:43 -04:00
FoxxMD
2504a34a34 refactor(docker): Remove old steps from node-canvas dep
Not using node-canvas anymore so dockerfile can be simplified #48
2021-11-01 15:55:12 -04:00
FoxxMD
e19639ad0d fix(ui): Forgot to add tailwin css to git
Oops!
2021-11-01 15:06:50 -04:00
FoxxMD
b8084e02b5 Merge branch 'colorImprovements' into edge 2021-11-01 14:58:01 -04:00
FoxxMD
2cea119657 feat(ui): Add tooltip descriptions for depleted/limit reset stats
Closes #36
2021-11-01 14:52:35 -04:00
FoxxMD
6f16d289dd feat(ui): Add lang attribute for html
Closes #35
2021-11-01 14:22:20 -04:00
FoxxMD
a96575c6b3 refactor(ui): Use local tailwind css asset
Closes #34
2021-11-01 14:19:47 -04:00
FoxxMD
0a82e83352 refactor(ui)!: Implement colorbind color changes for rest of UI and remove dark/light mode
* Apply changes made in ac409dce to the rest of the application
* Remove dark/light mode -- now always dark mode (easier to maintain this way)
* Remove dependency on tailwind dark css
2021-11-01 14:14:49 -04:00
FoxxMD
6370a2976a Merge branch 'edge' into colorImprovements 2021-11-01 10:23:40 -04:00
FoxxMD
ac409dce3d POC color improvements for color blindness
Needs another pass and consolidate/clean up for pages other than status
2021-10-20 21:12:31 -04:00
32 changed files with 217 additions and 270 deletions

View File

@@ -1,14 +1,10 @@
FROM node:16-alpine3.12
FROM node:16-alpine3.14
ENV TZ=Etc/GMT
RUN apk update
# required dependencies in order to compile linux-musl (node-canvas) on alpine
# https://github.com/node-gfx/node-canvas-prebuilt/issues/77#issuecomment-884365161
RUN apk add --no-cache build-base g++ cairo-dev jpeg-dev pango-dev giflib-dev
# required dependencies in order to compile linux-musl (node-canvas) on alpine
RUN apk add --update --repository http://dl-3.alpinelinux.org/alpine/edge/testing libmount ttf-dejavu ttf-droid ttf-freefont ttf-liberation ttf-ubuntu-font-family fontconfig vips
# vips required to run sharp library for image comparison
RUN echo "http://dl-4.alpinelinux.org/alpine/v3.14/community" >> /etc/apk/repositories \
&& apk --update add vips
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
@@ -17,9 +13,7 @@ WORKDIR /usr/app
COPY package*.json ./
COPY tsconfig.json .
# no prebuild support for node-canvas on alpine so need to compile
# https://github.com/Automattic/node-canvas#compiling
RUN npm install --build-from-source
RUN npm install
ADD . /usr/app

View File

@@ -17,12 +17,22 @@
"REFRESH_TOKEN": {
"description": "Refresh token retrieved from authenticating an account with your Reddit Application",
"value": "",
"required": true
"required": false
},
"ACCESS_TOKEN": {
"description": "Access token retrieved from authenticating an account with your Reddit Application",
"value": "",
"required": true
"required": false
},
"REDIRECT_URI": {
"description": "Redirect URI you specified when creating your Reddit Application. Required if you want to use the web interface. In the provided example replace 'your-heroku-app-name' with the name of your HEROKU app.",
"value": "https://your-heroku-6app-name.herokuapp.com/callback",
"required": false
},
"OPERATOR": {
"description": "Your reddit username WITHOUT any prefixes EXAMPLE /u/FoxxMD => FoxxMD. Specified user will be recognized as an admin.",
"value": "",
"required": false
},
"WIKI_CONFIG": {
"description": "Relative url to contextbot wiki page EX https://reddit.com/r/subreddit/wiki/<path>",

View File

@@ -50,6 +50,18 @@ tsc -p .
### [Heroku Quick Deploy](https://heroku.com/about)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://dashboard.heroku.com/new?template=https://github.com/FoxxMD/context-mod)
This template provides a **web** and **worker** dyno for heroku.
* **Web** -- Will run the bot **and** the web interface for ContextMod.
* **Worker** -- Will run **just** the bot.
Be aware that Heroku's [free dyno plan](https://devcenter.heroku.com/articles/free-dyno-hours#dyno-sleeping) enacts some limits:
* A **Web** dyno will go to sleep (pause) after 30 minutes without web activity -- so your bot will ALSO go to sleep at this time
* The **Worker** dyno **will not** go to sleep but you will NOT be able to access the web interface. You can, however, still see how Cm is running by reading the logs for the dyno.
If you want to use a free dyno it is recommended you perform first-time setup (bot authentication and configuration, testing, etc...) with the **Web** dyno, then SWITCH to a **Worker** dyno so it can run 24/7.
# Bot Authentication
Next you need to create a bot and authenticate it with Reddit. Follow the [bot authentication guide](/docs/botAuthentication.md) to complete this step.

29
heroku.Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM node:16-alpine3.14
ENV TZ=Etc/GMT
# vips required to run sharp library for image comparison
RUN echo "http://dl-4.alpinelinux.org/alpine/v3.14/community" >> /etc/apk/repositories \
&& apk --update add vips
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /usr/app
COPY package*.json ./
COPY tsconfig.json .
RUN npm install
ADD . /usr/app
RUN npm run build
ENV NPM_CONFIG_LOGLEVEL debug
ARG log_dir=/home/node/logs
RUN mkdir -p $log_dir
VOLUME $log_dir
ENV LOG_DIR=$log_dir
CMD [ "node", "src/index.js", "run", "all", "--port $PORT"]

View File

@@ -1,3 +1,4 @@
build:
docker:
worker: Dockerfile
web: heroku.Dockerfile
worker: heroku.Dockerfile

View File

@@ -324,8 +324,8 @@ class Bot {
const normalExcludes = this.excludeSubreddits.map(x => x.toLowerCase());
subsToRun = availSubs.filter(x => !normalExcludes.includes(x.display_name.toLowerCase()));
} else {
this.logger.info('No user-defined subreddit constraints detected, will run on all moderated subreddits');
subsToRun = availSubs;
this.logger.info(`No user-defined subreddit constraints detected, will run on all moderated subreddits EXCEPT own profile (${this.botAccount})`);
subsToRun = availSubs.filter(x => x.display_name_prefixed !== this.botAccount);
}
}

View File

@@ -656,10 +656,7 @@ export const buildOperatorConfigWithDefaults = (data: OperatorJsonConfig): Opera
...cacheTTLDefaults,
actionedEventsDefault: opActionedEventsDefault,
actionedEventsMax: opActionedEventsMax,
provider: {
store: 'memory',
...cacheOptDefaults
}
provider: {...defaultProvider}
};
} else {
const {

View File

@@ -12,11 +12,11 @@ export interface AuthorRuleConfig {
/**
* Will "pass" if any set of AuthorCriteria passes
* */
include: AuthorCriteria[];
include?: AuthorCriteria[];
/**
* Only runs if include is not present. Will "pass" if any of set of the AuthorCriteria does not pass
* */
exclude: AuthorCriteria[];
exclude?: AuthorCriteria[];
}
export interface AuthorRuleOptions extends AuthorRuleConfig, RuleOptions {
@@ -34,8 +34,13 @@ export class AuthorRule extends Rule {
constructor(options: AuthorRuleOptions) {
super(options);
this.include = options.include.map(x => new Author(x));
this.exclude = options.exclude.map(x => new Author(x));
const {
include,
exclude,
} = options;
this.include = include !== undefined ? include.map(x => new Author(x)) : [];
this.exclude = exclude !== undefined ? exclude.map(x => new Author(x)) : [];
if(this.include.length === 0 && this.exclude.length === 0) {
throw new Error('At least one of the properties [include,exclude] on Author Rule must not be empty');

View File

@@ -671,8 +671,6 @@
}
},
"required": [
"exclude",
"include",
"kind"
],
"type": "object"

View File

@@ -617,8 +617,6 @@
}
},
"required": [
"exclude",
"include",
"kind"
],
"type": "object"

View File

@@ -594,8 +594,6 @@
}
},
"required": [
"exclude",
"include",
"kind"
],
"type": "object"

View File

@@ -898,6 +898,18 @@ export class SubredditResources {
return false
}
break;
case 'op':
if(item instanceof Submission) {
log.warn(`On a Submission the 'op' property will always be true. Did you mean to use this on a comment instead?`);
break;
}
// @ts-ignore
if (item.is_submitter !== crit[k]) {
// @ts-ignore
log.debug(`Failed: Expected => ${k}:${crit[k]} | Found => ${k}:${item[k]}`)
return false
}
break;
default:
// @ts-ignore
if (item[k] !== undefined) {

View File

@@ -4,7 +4,7 @@ a {
.loading {
height: 35px;
fill: black;
fill: white;
display: none;
}
@@ -12,10 +12,6 @@ a {
display: inline;
}
.dark .loading {
fill: white;
}
.sub {
display: none;
}
@@ -91,3 +87,19 @@ a {
pointer-events: initial;
text-decoration: initial;
}
.blue {
color: rgb(97, 175, 239)
}
.red {
color: rgb(255 123 133);
}
.green {
color: rgb(170 255 109);
}
.purple {
color: rgb(224 124 253);
}
.yellow {
color: rgb(253 198 94);
}

View File

@@ -0,0 +1,10 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="q" viewBox="0 0 24 24">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</symbol>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 486 B

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,11 @@
<html>
<html lang="en">
<%- include('partials/head', {title: 'CM OAuth Helper'}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white font-sans">
<div class="min-w-screen min-h-screen">
<%- include('partials/title', {title: ' OAuth Helper'}) %>
<div class="container mx-auto">
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="bg-gray-600">
<div class="p-6 md:px-10 md:py-6">
<div class="text-xl mb-4">Congrats! You did the thing.</div>
<div class="space-y-3">

View File

@@ -1,11 +1,6 @@
<html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind.min.css"
integrity="sha512-wl80ucxCRpLkfaCnbM88y4AxnutbGk327762eM9E/rRTvY/ZGAHWMZrYUq66VQBYMIYDFpDdJAOGSLyIPHZ2IQ=="
crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind-dark.min.css"
integrity="sha512-WvyKyiVHgInX5UQt67447ExtRRZG/8GUijaq1MpqTNYp8wY4/EJOG5bI80sRp/5crDy4Z6bBUydZI2OFV3Vbtg=="
crossorigin="anonymous"/>
<link rel="stylesheet" href="/public/tailwind.min.css"/>
<script src="https://code.iconify.design/1/1.0.4/iconify.min.js"></script>
<link rel="stylesheet" href="/public/themeToggle.css">
<link rel="stylesheet" href="/public/app.css">
@@ -15,13 +10,12 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!--icons from https://heroicons.com -->
</head>
<body style="user-select: none;" class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body style="user-select: none;" class="bg-gray-900 text-white font-sans">
<div class="min-w-screen min-h-screen bg-gray-800">
<%- include('partials/title') %>
<div class="container mx-auto">
<div class="grid">
<div class="dark:text-white mb-3 pl-2">
<div class="my-3 pl-2">
Schema <a href="/config?schema=subreddit" id="subredditSchemaType">Subreddit</a> / <a href="/config?schema=operator" id="operatorSchemaType">Operator</a> |
<span class="has-tooltip">
<span style="z-index:999; margin-top: 30px;" class='tooltip rounded shadow-lg p-3 bg-gray-100 text-black space-y-2'>
@@ -63,35 +57,6 @@
</div>
<%- include('partials/footer') %>
</div>
<script>
document.querySelectorAll('.theme').forEach(el => {
el.addEventListener('click', e => {
e.preventDefault();
if (e.target.id === 'dark') {
document.body.classList.add('dark');
localStorage.setItem('ms-dark', 'yes');
} else {
document.body.classList.remove('dark');
localStorage.setItem('ms-dark', 'no');
}
document.querySelectorAll('.theme').forEach(el => {
el.classList.remove('font-bold', 'no-underline', 'pointer-events-none');
});
e.target.classList.add('font-bold', 'no-underline', 'pointer-events-none');
})
})
document.querySelector("#themeToggle").checked = localStorage.getItem('ms-dark') !== 'no';
document.querySelector("#themeToggle").onchange = (e) => {
if (e.target.checked === true) {
document.body.classList.add('dark');
localStorage.setItem('ms-dark', 'yes');
} else {
document.body.classList.remove('dark');
localStorage.setItem('ms-dark', 'no');
}
}
</script>
<script src="/monaco/dev/vs/loader.js"></script>
<script>
require.config({ paths: { vs: 'monaco/dev/vs' } });

View File

@@ -1,12 +1,11 @@
<html>
<html lang="en">
<%- include('partials/head', {title: 'CM'}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white font-sans">
<div class="min-w-screen min-h-screen">
<%- include('partials/title', {title: 'Error'}) %>
<div class="container mx-auto">
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="bg-gray-600">
<div class="p-6 md:px-10 md:py-6">
<div class="text-xl mb-4">Oops 😬</div>
<div class="space-y-3">

View File

@@ -1,11 +1,6 @@
<html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind.min.css"
integrity="sha512-wl80ucxCRpLkfaCnbM88y4AxnutbGk327762eM9E/rRTvY/ZGAHWMZrYUq66VQBYMIYDFpDdJAOGSLyIPHZ2IQ=="
crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind-dark.min.css"
integrity="sha512-WvyKyiVHgInX5UQt67447ExtRRZG/8GUijaq1MpqTNYp8wY4/EJOG5bI80sRp/5crDy4Z6bBUydZI2OFV3Vbtg=="
crossorigin="anonymous"/>
<link rel="stylesheet" href="/public/tailwind.min.css"/>
<script src="https://code.iconify.design/1/1.0.4/iconify.min.js"></script>
<link rel="stylesheet" href="/public/themeToggle.css">
<link rel="stylesheet" href="/public/app.css">
@@ -20,19 +15,19 @@
}
</style>
</head>
<body>
<body class="bg-gray-900 text-white font-sans">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<div class="min-w-screen min-h-screen">
<%- include('partials/title') %>
<div class="container mx-auto">
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white px-3 py-6 space-y-3">
<div class="px-3 py-6 space-y-3">
<% if(data.length === 0) { %>
No events have been actioned yet!
<% } %>
<% data.forEach(function (eRes){ %>
<div class="shadow-lg">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 dark:bg-gray-700 dark:text-white">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-700">
<div class="flex items-center justify-between">
<div>
<span class="peek"><%- eRes.activity.peek %></span><a target="_blank" href="https://reddit.com<%= eRes.activity.link%>">(Link)</a>
@@ -42,7 +37,7 @@
</div>
</div>
</div>
<div class="p-4 pl-6 pt-3 space-y-2">
<div class="p-4 pl-6 pt-3 space-y-2 bg-gray-500">
<div><span class="font-semibold">Check:</span> <%= eRes.check %><span class="px-3">&#10132;</span><%= eRes.ruleSummary %></div>
<div>
<span class="font-semibold">Rules:</span>
@@ -67,34 +62,5 @@
</div>
<%- include('partials/footer') %>
</div>
<script>
document.querySelectorAll('.theme').forEach(el => {
el.addEventListener('click', e => {
e.preventDefault();
if (e.target.id === 'dark') {
document.body.classList.add('dark');
localStorage.setItem('ms-dark', 'yes');
} else {
document.body.classList.remove('dark');
localStorage.setItem('ms-dark', 'no');
}
document.querySelectorAll('.theme').forEach(el => {
el.classList.remove('font-bold', 'no-underline', 'pointer-events-none');
});
e.target.classList.add('font-bold', 'no-underline', 'pointer-events-none');
})
})
document.querySelector("#themeToggle").checked = localStorage.getItem('ms-dark') !== 'no';
document.querySelector("#themeToggle").onchange = (e) => {
if (e.target.checked === true) {
document.body.classList.add('dark');
localStorage.setItem('ms-dark', 'yes');
} else {
document.body.classList.remove('dark');
localStorage.setItem('ms-dark', 'no');
}
}
</script>
</body>
</html>

View File

@@ -1,12 +1,11 @@
<html>
<html lang="en">
<%- include('partials/head', {title: 'CM OAuth Helper'}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white font-sans">
<div class="min-w-screen min-h-screen">
<%- include('partials/title', {title: ' OAuth Helper'}) %>
<div class="container mx-auto">
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="bg-gray-600">
<div class="p-6 md:px-10 md:py-6">
<div class="text-xl mb-4">Hi! Looks like you're setting up your bot. To get running:</div>
<div class="text-lg text-semibold my-3">1. Set your redirect URL</div>

View File

@@ -1,12 +1,11 @@
<html>
<html lang="en">
<%- include('partials/head', {title: 'CM OAuth Helper'}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white">
<div class="min-w-screen min-h-screen font-sans">
<%- include('partials/title', {title: ' OAuth Helper'}) %>
<div class="container mx-auto">
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="bg-gray-600">
<div class="p-6 md:px-10 md:py-6">
<div class="text-xl mb-4">Hi! Looks like you're accepting an invite to authorize an account to run on this ContextMod instance:</div>
<div class="text-lg text-semibold my-3">1. Review permissions</div>

View File

@@ -1,12 +1,11 @@
<html>
<html lang="en">
<%- include('partials/head', {title: 'Access Denied'}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white font-sans">
<div class="min-w-screen min-h-screen">
<%- include('partials/title', {title: ''}) %>
<div class="container mx-auto">
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="bg-gray-600">
<div class="p-6 md:px-10 md:py-6">
<div class="text-xl mb-4">Sorry!</div>
<div class="space-y-3">
@@ -28,6 +27,5 @@
</div>
<%- include('partials/footer') %>
</div>
<%- include('partials/themeJs') %>
</body>
</html>

View File

@@ -1,14 +1,13 @@
<html>
<html lang="en">
<%- include('partials/head', {title: undefined}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white font-sans">
<div class="min-w-screen min-h-screen">
<%- include('partials/header') %>
<%- include('partials/botsTab') %>
<div class="container mx-auto">
<%- include('partials/subredditsTab') %>
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="bg-gray-700">
<div class="pb-6 md:px-7">
<div class="sub active" data-subreddit="All" data-bot="All">
Instance is currently <b>OFFLINE</b>
@@ -31,7 +30,6 @@
</div>
<%- include('partials/footer') %>
<%- include('partials/instanceTabJs') %>
<%- include('partials/themeJs') %>
<%- include('partials/logSettingsJs') %>
<script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script>
<script>

View File

@@ -1,9 +1,9 @@
<div class="space-x-4 py-1 md:px-10 leading-6 font-semibold bg-gray-500 dark:bg-gray-700 text-white">
<div class="space-x-4 py-1 md:px-10 leading-6 font-semibold bg-gray-700">
<div class="container mx-auto">
<% if(locals.bots !== undefined) { %>
<ul id="botTabs" class="inline-flex flex-wrap">
<% bots.forEach(function (data){ %>
<li class="my-3 px-3 dark:text-white">
<li class="my-3 px-3">
<span data-bot="<%= data.system.name %>" class="rounded-md py-2 px-3 tabSelectWrapper">
<a class="tabSelect font-normal pointer hover:font-bold"
data-bot="<%= data.system.name %>">
@@ -16,7 +16,7 @@
</li>
<% }) %>
<% if(locals.isOperator === true && locals.instanceId !== undefined) { %>
<li class="my-3 px-3 dark:text-white">
<li class="my-3 px-3">
<span class="rounded-md py-2 px-3 border">
<a class="font-normal pointer hover:font-bold" href="/auth/helper">
Add Bot +

View File

@@ -1,4 +1,4 @@
<div class="py-3 flex items-center justify-around font-semibold text-white">
<div class="py-3 flex items-center justify-around font-semibold">
<div>
<a href="https://github.com/FoxxMD/context-mod">ContextMod Web</a> created by /u/FoxxMD
</div>

View File

@@ -1,10 +1,5 @@
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind.min.css"
integrity="sha512-wl80ucxCRpLkfaCnbM88y4AxnutbGk327762eM9E/rRTvY/ZGAHWMZrYUq66VQBYMIYDFpDdJAOGSLyIPHZ2IQ=="
crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind-dark.min.css"
integrity="sha512-WvyKyiVHgInX5UQt67447ExtRRZG/8GUijaq1MpqTNYp8wY4/EJOG5bI80sRp/5crDy4Z6bBUydZI2OFV3Vbtg=="
crossorigin="anonymous"/>
<link rel="stylesheet" href="/public/tailwind.min.css"/>
<script src="https://code.iconify.design/1/1.0.4/iconify.min.js"></script>
<link rel="stylesheet" href="/public/themeToggle.css">
<link rel="stylesheet" href="/public/app.css">

View File

@@ -1,11 +1,11 @@
<div class="space-x-4 p-6 md:px-10 md:py-6 leading-6 font-semibold bg-gray-800 text-white">
<div class="space-x-4 p-6 md:px-10 md:py-6 leading-6 font-semibold bg-gray-500 text-white">
<div class="container mx-auto">
<div class="flex items-center justify-between">
<div class="flex items-center flex-grow pr-4">
<% if(locals.instances !== undefined) { %>
<ul class="inline-flex flex-wrap">
<% instances.forEach(function (data) { %>
<li class="my-3 px-3 dark:text-white">
<li class="my-3 px-3">
<span data-instance="<%= data.friendly %>" class="has-tooltip instanceSelectWrapper rounded-md py-3 px-3">
<span class='tooltip rounded shadow-lg p-1 bg-gray-100 text-black' style="margin-top:3em">
<div class="stats">
@@ -34,20 +34,6 @@
<% } %>
</div>
<div class="flex items-center flex-end text-sm">
<span class="inline-block mr-4">
<label style="font-size:2.5px;">
<input class='toggle-checkbox' type='checkbox' id="themeToggle" checked></input>
<div class='toggle-slot'>
<div class='sun-icon-wrapper'>
<div class="iconify sun-icon" data-icon="feather-sun" data-inline="false"></div>
</div>
<div class='toggle-button'></div>
<div class='moon-icon-wrapper'>
<div class="iconify moon-icon" data-icon="feather-moon" data-inline="false"></div>
</div>
</div>
</label>
</span>
<a href="logout">Logout</a>
</div>
</div>

View File

@@ -1,10 +1,10 @@
<div class="space-x-4 pt-2 md:px-5 leading-6 font-semibold bg-gray-white dark:bg-gray-500 text-white">
<div class="space-x-4 pt-2 md:px-5 leading-6 font-semibold bg-gray-800">
<div class="container mx-auto">
<% if(locals.bots !== undefined) { %>
<% bots.forEach(function (botData){ %>
<ul data-bot="<%= botData.system.name %>" class="inline-flex flex-wrap subreddit nestedTabs">
<% botData.subreddits.forEach(function (data){ %>
<li class="my-3 pr-3 dark:text-white">
<li class="my-3 pr-3">
<span data-subreddit="<%= data.name %>" class="rounded-md py-2 px-3 tabSelectWrapper">
<a class="tabSelect font-normal pointer hover:font-bold"
data-subreddit="<%= data.name %>">

View File

@@ -1,32 +0,0 @@
<script>
document.querySelectorAll('.theme').forEach(el => {
el.addEventListener('click', e => {
e.preventDefault();
if (e.target.id === 'dark') {
document.body.classList.add('dark');
localStorage.setItem('ms-dark', 'yes');
} else {
document.body.classList.remove('dark');
localStorage.setItem('ms-dark', 'no');
}
document.querySelectorAll('.theme').forEach(el => {
el.classList.remove('font-bold', 'no-underline', 'pointer-events-none');
});
e.target.classList.add('font-bold', 'no-underline', 'pointer-events-none');
})
});
const themeToggle = document.querySelector("#themeToggle");
if(themeToggle !== null) {
themeToggle.checked = localStorage.getItem('ms-dark') !== 'no';
themeToggle.onchange = (e) => {
if (e.target.checked === true) {
document.body.classList.add('dark');
localStorage.setItem('ms-dark', 'yes');
} else {
document.body.classList.remove('dark');
localStorage.setItem('ms-dark', 'no');
}
}
}
</script>

View File

@@ -1,4 +1,4 @@
<div class="space-x-4 p-6 md:px-10 md:py-6 leading-6 font-semibold bg-gray-800 text-white">
<div class="space-x-4 p-6 md:px-10 md:py-6 leading-6 font-semibold bg-gray-500">
<div class="container mx-auto">
<div class="flex items-center justify-between">
<div class="flex items-center flex-grow pr-4">
@@ -7,20 +7,7 @@
<% } %>
</div>
<div class="flex items-center flex-end text-sm">
<span class="inline-block mr-4">
<label style="font-size:2.5px;">
<input class='toggle-checkbox' type='checkbox' id="themeToggle" checked></input>
<div class='toggle-slot'>
<div class='sun-icon-wrapper'>
<div class="iconify sun-icon" data-icon="feather-sun" data-inline="false"></div>
</div>
<div class='toggle-button'></div>
<div class='moon-icon-wrapper'>
<div class="iconify moon-icon" data-icon="feather-moon" data-inline="false"></div>
</div>
</div>
</label>
</span>
<a href="logout">Logout</a>
</div>
</div>

View File

@@ -1,21 +1,20 @@
<html>
<html lang="en">
<%- include('partials/head', {title: undefined}) %>
<body class="">
<script>localStorage.getItem('ms-dark') === 'no' ? document.body.classList.remove('dark') : document.body.classList.add('dark')</script>
<div class="min-w-screen min-h-screen bg-gray-100 bg-gray-100 dark:bg-gray-800 font-sans">
<body class="bg-gray-900 text-white">
<div class="min-w-screen min-h-screen font-sans">
<%- include('partials/header') %>
<%- include('partials/botsTab') %>
<%- include('partials/subredditsTab') %>
<div class="container mx-auto">
<%- include('partials/subredditsTab') %>
<div class="grid">
<div class="bg-white dark:bg-gray-500 dark:text-white">
<div class="">
<div class="pb-6 md:px-7">
<% bots.forEach(function (bot){ %>
<% bot.subreddits.forEach(function (data){ %>
<div class="sub <%= bot.system.running ? '' : 'offline' %>" data-subreddit="<%= data.name %>" data-bot="<%= bot.system.name %>">
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-3 gap-5">
<div class="bg-white shadow-md rounded my-3 dark:bg-gray-500 dark:text-white">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 dark:bg-gray-700 dark:text-white">
<div class="bg-white shadow-md rounded my-3 bg-gray-600 ">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 bg-gray-700 ">
<div class="flex items-center justify-between">
<h4>Overview</h4>
<% if (data.name === 'All') { %>
@@ -63,10 +62,7 @@
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
@@ -99,10 +95,7 @@
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
@@ -136,10 +129,7 @@
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
@@ -209,11 +199,8 @@
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
</label>
@@ -235,8 +222,8 @@
</div>
</div>
<% if (data.name === 'All') { %>
<div class="bg-white shadow-md rounded my-3 dark:bg-gray-500 dark:text-white">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 dark:bg-gray-700 dark:text-white">
<div class="bg-white shadow-md rounded my-3 bg-gray-600 ">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 bg-gray-700 ">
<h4>API</h4>
</div>
<div class="p-4">
@@ -250,9 +237,40 @@
<label>Api Usage</label>
<span><span id="apiLimit"><%= data.apiLimit %></span>/600 (~<span
id="apiAvg"><%= data.apiAvg %></span>req/s)</span>
<label>Depleted</label>
<label>
<span class="has-tooltip">
<span style="margin-top:55px" class='tooltip rounded shadow-lg p-1 bg-gray-100 text-black space-y-3 p-2 text-left'>
<p>Reddit restricts api usage, per account, to <b>600 requests every 10 minutes.</b></p>
<p><b>Depleted</b> is the estimated time until all 600 requests are used based on <b>Api Usage.</b></p>
<p>API usage is sustainable when <b>Depleted</b> is greater than <b>Limit Reset</b></p>
</span>
<span>
Depleted <svg xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
</label>
<span>in ~<span id="apiDepletion"><%= data.apiDepletion %></span></span>
<label>Limit Reset</label>
<label>
<span class="has-tooltip">
<span style="margin-top:35px" class='tooltip rounded shadow-lg p-1 bg-gray-100 text-black space-y-3 p-2 text-left'>
<p>Reddit restricts api usage, per account, to <b>600 requests every 10 minutes.</b></p>
<p><b>Limit Reset</b> is the amount of time remaining in the current 10 minute period until the limit is reset to 600.</p>
</span>
<span>
Limit Reset <svg xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
</label>
<span class="has-tooltip">
<span class='tooltip rounded shadow-lg p-1 bg-gray-100 text-black -mt-2'>
<span id="limitReset"><%= data.limitReset %></span>
@@ -264,8 +282,8 @@
</div>
<% } %>
<% if (data.name !== 'All') { %>
<div class="bg-white shadow-md rounded my-3 dark:bg-gray-500 dark:text-white">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 dark:bg-gray-700 dark:text-white">
<div class="bg-white shadow-md rounded my-3 bg-gray-600 ">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-700 ">
<h4>Config
<span>
<span class="has-tooltip">
@@ -316,8 +334,8 @@
</div>
</div>
<% } %>
<div class="bg-white shadow-md rounded my-3 dark:bg-gray-500 dark:text-white">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-300 dark:bg-gray-700 dark:text-white">
<div class="bg-white shadow-md rounded my-3 bg-gray-600 ">
<div class="space-x-4 px-4 p-2 leading-2 font-semibold bg-gray-700 ">
<h4>Usage</h4>
</div>
<div class="p-4">
@@ -440,10 +458,7 @@
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
@@ -580,10 +595,7 @@
class="h-4 w-4 inline-block cursor-help"
fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
<use xlink:href="public/questionsymbol.svg#q" />
</svg>
</span>
</span>
@@ -628,7 +640,6 @@
<%- include('partials/footer') %>
</div>
<%- include('partials/instanceTabJs') %>
<%- include('partials/themeJs') %>
<%- include('partials/logSettingsJs') %>
<script>
window.sort = 'desc';

View File

@@ -756,11 +756,11 @@ export const formatLogLineToHtml = (log: string | LogInfo) => {
stripPrefix: false,
sanitizeHtml: true,
})
.replace(/(\s*debug\s*):/i, '<span class="debug text-pink-400">$1</span>:')
.replace(/(\s*warn\s*):/i, '<span class="warn text-yellow-400">$1</span>:')
.replace(/(\s*info\s*):/i, '<span class="info text-blue-300">$1</span>:')
.replace(/(\s*error\s*):/i, '<span class="error text-red-400">$1</span>:')
.replace(/(\s*verbose\s*):/i, '<span class="error text-purple-400">$1</span>:')
.replace(/(\s*debug\s*):/i, '<span class="debug blue">$1</span>:')
.replace(/(\s*warn\s*):/i, '<span class="warn yellow">$1</span>:')
.replace(/(\s*info\s*):/i, '<span class="info green">$1</span>:')
.replace(/(\s*error\s*):/i, '<span class="error red">$1</span>:')
.replace(/(\s*verbose\s*):/i, '<span class="error purple">$1</span>:')
.replaceAll('\n', '<br />');
//.replace(HYPERLINK_REGEX, '<a target="_blank" href="$&">$&</a>');
return `<div class="logLine">${logContent}</div>`