mirror of
https://github.com/FoxxMD/context-mod.git
synced 2026-04-19 03:00:07 -04:00
Config interaction greatly improved
* Replace json view with monaco-editor with schema loaded based on url param * Add route for unauthenticated config editing * Auto-load subreddit config when "view" is clicked from subreddit view
This commit is contained in:
11
package-lock.json
generated
11
package-lock.json
generated
@@ -37,6 +37,7 @@
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^6.0.0",
|
||||
"monaco-editor": "^0.27.0",
|
||||
"mustache": "^4.2.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"normalize-url": "^6.1.0",
|
||||
@@ -2602,6 +2603,11 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.27.0.tgz",
|
||||
"integrity": "sha512-UhwP78Wb8w0ZSYoKXQNTV/0CHObp6NS3nCt51QfKE6sKyBo5PBsvuDOHoI2ooBakc6uIwByRLHVeT7+yXQe2fQ=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -6182,6 +6188,11 @@
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
},
|
||||
"monaco-editor": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.27.0.tgz",
|
||||
"integrity": "sha512-UhwP78Wb8w0ZSYoKXQNTV/0CHObp6NS3nCt51QfKE6sKyBo5PBsvuDOHoI2ooBakc6uIwByRLHVeT7+yXQe2fQ=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^6.0.0",
|
||||
"monaco-editor": "^0.27.0",
|
||||
"mustache": "^4.2.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"normalize-url": "^6.1.0",
|
||||
|
||||
@@ -52,6 +52,8 @@ app.use(bodyParser.urlencoded({extended: false}));
|
||||
app.set('views', `${__dirname}/../assets/views`);
|
||||
app.set('view engine', 'ejs');
|
||||
app.use('/public', express.static(`${__dirname}/../assets/public`));
|
||||
app.use('/monaco', express.static(`${__dirname}/../../../node_modules/monaco-editor/`));
|
||||
app.use('/schemas', express.static(`${__dirname}/../../Schema/`));
|
||||
|
||||
const proxy = httpProxy.createProxyServer({
|
||||
ws: true,
|
||||
@@ -234,6 +236,14 @@ const webClient = async (options: OperatorConfig) => {
|
||||
}
|
||||
}
|
||||
|
||||
const ensureAuthenticatedApi = async (req: express.Request, res: express.Response, next: Function) => {
|
||||
if (req.isAuthenticated()) {
|
||||
next();
|
||||
} else {
|
||||
return res.status(401).send('You must be logged in to access this route');
|
||||
}
|
||||
}
|
||||
|
||||
app.getAsync('/login', async (req, res, next) => {
|
||||
if (redirectUri === undefined) {
|
||||
return res.render('error', {error: `No <b>redirectUri</b> was specified through environmental variables or program argument. This must be provided in order to use the web interface.`});
|
||||
@@ -788,7 +798,13 @@ const webClient = async (options: OperatorConfig) => {
|
||||
});
|
||||
});
|
||||
|
||||
app.getAsync('/config', [ensureAuthenticated, defaultSession, instanceWithPermissions, botWithPermissions, createUserToken], async (req: express.Request, res: express.Response) => {
|
||||
app.getAsync('/config', async (req: express.Request, res: express.Response) => {
|
||||
res.render('config', {
|
||||
title: `Configuration Editor`
|
||||
});
|
||||
});
|
||||
|
||||
app.getAsync('/config/content', [ensureAuthenticatedApi, defaultSession, instanceWithPermissions, botWithPermissions, createUserToken], async (req: express.Request, res: express.Response) => {
|
||||
const {subreddit} = req.query as any;
|
||||
const resp = await got.get(`${(req.instance as CMInstance).normalUrl}/config`, {
|
||||
headers: {
|
||||
@@ -800,13 +816,7 @@ const webClient = async (options: OperatorConfig) => {
|
||||
}
|
||||
}).text();
|
||||
|
||||
const [obj, jsonErr, yamlErr] = parseFromJsonOrYamlToObject(resp);
|
||||
const bot = req.instance as CMInstance;
|
||||
res.render('config', {
|
||||
config: prettyPrintJson.toHtml(obj, {quoteKeys: true, indent: 2}),
|
||||
operatorDisplay:bot.operators.join(', '),
|
||||
title: `Configuration for ${subreddit}`
|
||||
});
|
||||
return res.send(resp);
|
||||
});
|
||||
|
||||
app.getAsync('/logs/settings/update',[ensureAuthenticated], async (req: express.Request, res: express.Response) => {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/* adapted from https://cdn.jsdelivr.net/npm/pretty-print-json@1.0/dist/pretty-print-json.css */
|
||||
.json-key { color: brown; }
|
||||
.json-string { color: olive; }
|
||||
.json-number { color: navy; }
|
||||
.json-boolean { color: teal; }
|
||||
.json-null { color: dimgray; }
|
||||
.json-mark { color: black; }
|
||||
a.json-link { color: purple; transition: all 400ms; }
|
||||
a.json-link:visited { color: slategray; }
|
||||
a.json-link:hover { color: blueviolet; }
|
||||
a.json-link:active { color: slategray; }
|
||||
.dark .json-key { color: indianred; }
|
||||
.dark .json-string { color: darkkhaki; }
|
||||
.dark .json-number { color: deepskyblue; }
|
||||
.dark .json-boolean { color: mediumseagreen; }
|
||||
.dark .json-null { color: darkorange; }
|
||||
.dark .json-mark { color: silver; }
|
||||
.dark a.json-link { color: mediumorchid; }
|
||||
.dark a.json-link:visited { color: slategray; }
|
||||
.dark a.json-link:hover { color: violet; }
|
||||
.dark a.json-link:active { color: silver; }
|
||||
@@ -9,9 +9,7 @@
|
||||
<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">
|
||||
<link rel="stylesheet" href="/public/json.css">
|
||||
<title><%= title %></title>
|
||||
<!--<title><%# `CM for /u/${botName}`%></title>-->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
@@ -23,12 +21,42 @@
|
||||
<%- include('partials/title') %>
|
||||
<div class="container mx-auto">
|
||||
<div class="grid">
|
||||
<div class="bg-white dark:bg-gray-700 dark:text-white">
|
||||
<div class="p-6 md:px-10 md:py-6 space-y-3">
|
||||
<div>Note: Comments have been removed</div>
|
||||
<pre style="user-select: text;"><%- config %></pre>
|
||||
</div>
|
||||
<div class="dark:text-white mb-3 pl-2">
|
||||
<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'>
|
||||
<div>Copy + paste your configuration here to get:</div>
|
||||
<ul class="list-inside list-disc">
|
||||
<li>
|
||||
formatting (right click for menu)
|
||||
</li>
|
||||
<li>
|
||||
JSON syntax assist (red squiggly, hover for info)
|
||||
</li>
|
||||
<li>
|
||||
annotated properties (hover for info)
|
||||
</li>
|
||||
<li id="schemaTypeList"></li>
|
||||
</ul>
|
||||
<div>When done editing hit Ctrl+A (Command+A on macOS) to select all text, then copy + paste back into your wiki/file</div>
|
||||
</span>
|
||||
<span class="cursor-help">
|
||||
How To Use
|
||||
<span>
|
||||
<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">
|
||||
<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>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<div id="error" class="font-semibold"></div>
|
||||
</div>
|
||||
<div style="min-height: 80vh" id="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
@@ -62,5 +90,72 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="/monaco/dev/vs/loader.js"></script>
|
||||
<script>
|
||||
require.config({ paths: { vs: 'monaco/dev/vs' } });
|
||||
|
||||
const preamble = [
|
||||
'// Copy + paste your configuration here to get',
|
||||
'// formatting, JSON syntax, annotated properties and'
|
||||
];
|
||||
|
||||
var searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
let schemaType;
|
||||
if(searchParams.get('schema') === 'operator') {
|
||||
schemaType = 'OperatorConfig.json';
|
||||
preamble.push('// automatic validation of your OPERATOR configuration');
|
||||
document.querySelector('#schemaTypeList').innerHTML = 'automatic validation of your OPERATOR configuration (yellow squiggly)';
|
||||
} else {
|
||||
schemaType = 'App.json';
|
||||
preamble.push('// automatic validation of your SUBREDDIT configuration');
|
||||
document.querySelector('#schemaTypeList').innerHTML = 'automatic validation of your SUBREDDIT configuration (yellow squiggly)'
|
||||
}
|
||||
|
||||
const schemaUri = `${document.location.origin}/schemas/${schemaType}`;
|
||||
|
||||
require(['vs/editor/editor.main'], function () {
|
||||
const modelUri = monaco.Uri.parse("a://b/foo.json");
|
||||
fetch(schemaUri).then((res) => {
|
||||
res.json().then((schemaData) => {
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||
validate: true,
|
||||
allowComments: true,
|
||||
trailingCommas: "ignore",
|
||||
schemas: [{
|
||||
uri: schemaUri,
|
||||
fileMatch: [modelUri.toString()],
|
||||
schema: schemaData
|
||||
}]
|
||||
});
|
||||
if(searchParams.get('subreddit') !== null) {
|
||||
fetch(`${document.location.origin}/config/content${document.location.search}`).then((resp) => {
|
||||
if(!resp.ok) {
|
||||
resp.text().then(data => {
|
||||
document.querySelector('#error').innerHTML = `Error occurred while fetching configuration => ${data}`
|
||||
});
|
||||
} else {
|
||||
resp.text().then(data => {
|
||||
var model = monaco.editor.createModel(data, "json", modelUri);
|
||||
var editor = monaco.editor.create(document.getElementById('editor'), {
|
||||
model,
|
||||
theme: 'vs-dark'
|
||||
});
|
||||
editor;
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
var model = monaco.editor.createModel(preamble.join('\r\n'), "json", modelUri);
|
||||
var editor = monaco.editor.create(document.getElementById('editor'), {
|
||||
model,
|
||||
theme: 'vs-dark'
|
||||
});
|
||||
editor;
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -310,7 +310,7 @@
|
||||
<span>
|
||||
<a style="display: inline"
|
||||
href="<%= data.wikiHref %>"><%= data.wikiLocation %></a> | <a style="display: inline" target="_blank"
|
||||
href="/config?instance=<%= instanceId %>&bot=<%= bot.botName %>&subreddit=<%= data.name %>">View</a>
|
||||
href="/config?instance=<%= instanceId %>&bot=<%= bot.system.name %>&subreddit=<%= data.name %>">View</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user