Skip to content

Commit 4ee57c4

Browse files
committed
Organise things a bit better
1 parent b9ca095 commit 4ee57c4

12 files changed

Lines changed: 122 additions & 64 deletions

File tree

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
"typescript": "^5.8.3"
1212
},
1313
"dependencies": {
14+
"@codemirror/commands": "^6.8.1",
1415
"@codemirror/language": "^6.11.0",
1516
"@codemirror/state": "^6.5.2",
1617
"@codemirror/theme-one-dark": "^6.1.2",
18+
"@codemirror/view": "^6.36.6",
1719
"@solid-primitives/deep": "^0.3.2",
1820
"@solidjs/router": "^0.15.3",
1921
"@tabler/icons-solidjs": "^3.31.0",

frontend/src/client/index.ts

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
import { AUTH_LOG_IN, AUTH_LOG_OUT, GUILDS } from "./routes";
1+
import { AUTH_LOG_IN, AUTH_LOG_OUT, GUILD_CONFIG, GUILDS } from "./routes";
22

3-
type HttpMethod = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE" | "PATCH";
3+
type HTTPMethod = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE" | "PATCH";
4+
5+
function extractMessage(body: unknown) {
6+
if (typeof body === "string")
7+
return body;
8+
9+
if (typeof body === "object" && body !== null && "error" in body)
10+
return body.error;
11+
12+
return "No message";
13+
}
14+
15+
export class RESTError extends Error {
16+
body: unknown;
17+
18+
constructor(status: number, body: unknown) {
19+
super(`${status} - ${extractMessage(body)}`);
20+
this.name = "RESTError";
21+
this.body = body;
22+
}
23+
}
424

525
export interface LogInResponse {
626
token: string;
@@ -20,9 +40,11 @@ export interface GuildResponse {
2040
ownerID: string;
2141
}
2242

23-
async function requestJSON<T>(route: string, method: HttpMethod, token?: string, body?: any): Promise<T | ErrorResponse> {
43+
async function request<T>(route: string, method: HTTPMethod, token?: string, body?: any): Promise<T> {
2444
const headers = new Headers;
25-
headers.set("Content-Type", "application/json");
45+
46+
if (body != null)
47+
headers.set("Content-Type", "application/json");
2648

2749
if (token !== undefined)
2850
headers.set("Authorization", token);
@@ -33,22 +55,30 @@ async function requestJSON<T>(route: string, method: HttpMethod, token?: string,
3355
headers,
3456
});
3557

36-
const text = await response.text();
37-
38-
if (text.length === 0)
58+
if (response.status === 204)
3959
return null as T;
4060

41-
return JSON.parse(text);
61+
const isJson = response.headers.get("Content-Type") === "application/json";
62+
const responseBody = isJson ? await response.json() : await response.text();
63+
64+
if (!response.ok)
65+
throw new RESTError(response.status, responseBody);
66+
67+
return responseBody;
4268
}
4369

4470
export function logIn(code: string) {
45-
return requestJSON<LogInResponse>(AUTH_LOG_IN, "POST", undefined, { code });
71+
return request<LogInResponse>(AUTH_LOG_IN, "POST", undefined, { code });
4672
}
4773

4874
export function logOut(token: string) {
49-
return requestJSON<null>(AUTH_LOG_OUT, "GET", token);
75+
return request<null>(AUTH_LOG_OUT, "GET", token);
5076
}
5177

5278
export function getGuilds(token: string) {
53-
return requestJSON<GuildResponse[]>(GUILDS, "GET", token);
79+
return request<GuildResponse[]>(GUILDS, "GET", token);
80+
}
81+
82+
export async function getGuildConfig(token: string, guildID: string, config: string) {
83+
return request<string>(GUILD_CONFIG(guildID, config), "GET", token);
5484
}

frontend/src/client/routes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { buildURI } from "../common/uri";
2+
13
export const AUTH_LOG_IN = "/api/v1/auth/log-in";
24
export const AUTH_LOG_OUT = "/api/v1/auth/log-out";
35
export const GUILDS = "/api/v1/guilds";
6+
export const GUILD_CONFIG = (guildID: string, key: string) => buildURI`/api/v1/guilds/${guildID}/config/${key}`;

frontend/src/codemirror/toml.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

frontend/src/component/common/CodeMirror.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ export function CodeMirror(props: CodeMirrorProps) {
3232
}, { defer: true }));
3333
});
3434

35-
return <div ref={ref}></div>;
35+
return <div ref={ref} />;
3636
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { createResource } from "solid-js";
2+
import { baseExtensions } from ".";
3+
import { getGuildConfig } from "../../client";
4+
import { account } from "../../state/account";
5+
import { useGuild } from "../../state/guilds";
6+
import { CodeMirror } from "../common/CodeMirror";
7+
8+
export function ConfigEditor(props: { guildID: string; configKey: string; }) {
9+
const guild = () => useGuild(props.guildID);
10+
11+
const [resource] = createResource(() => guild(), () => {
12+
if (guild() !== undefined)
13+
return getGuildConfig(account()!.token, guild()!.id, "moderation");
14+
else
15+
return undefined;
16+
});
17+
18+
return <CodeMirror value={resource() ?? ""} extensions={baseExtensions} />;
19+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { indentLess, insertTab } from "@codemirror/commands";
2+
import { indentNodeProp, LRLanguage } from "@codemirror/language";
3+
import { oneDark } from "@codemirror/theme-one-dark";
4+
import { EditorView, keymap } from "@codemirror/view";
5+
import { basicSetup } from "codemirror";
6+
import { parser } from "lezer-toml";
7+
8+
const parserWithMetadata = parser.configure({
9+
props: [
10+
indentNodeProp.add({
11+
Array: context => context.column(context.node.from) + context.unit
12+
}),
13+
]
14+
});
15+
16+
export const baseExtensions = [
17+
basicSetup,
18+
oneDark,
19+
LRLanguage.define({
20+
parser: parserWithMetadata,
21+
}),
22+
keymap.of([{
23+
key: "Tab",
24+
run: insertTab,
25+
shift: indentLess,
26+
}]),
27+
EditorView.theme({
28+
"&.cm-focused": {
29+
outline: "none"
30+
}
31+
})
32+
];

frontend/src/helper/auth.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ export function handleLoginCallback() {
2424
history.replaceState(null, "", "/");
2525

2626
requestLogIn(code).then(response => {
27-
if ("error" in response)
28-
return; // TODO handle errors
27+
// TODO handle errors
2928

3029
setAccount({
3130
token: response.token,

frontend/src/route/guild.tsx

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,13 @@
1-
import { oneDark } from "@codemirror/theme-one-dark";
2-
import { basicSetup } from "codemirror";
3-
import { tomlHighlighting as tomlLanguage } from "../codemirror/toml";
4-
import { CodeMirror } from "../component/common/CodeMirror";
1+
import { useParams } from "@solidjs/router";
2+
import { ConfigEditor } from "../component/config/ConfigEditor";
53
import { LoginGate } from "../component/LoginGate";
64

75
export const Guild = () => <LoginGate><GuildComponent /></LoginGate>;
86

97
export function GuildComponent() {
10-
// const guildID = () => useParams().guildID!;
11-
const config = `
12-
[groups.moderator]
13-
users = ["706152404072267788"]
8+
const guildID = () => useParams().guildID!;
149

15-
[prefix_commands]
16-
prefix = "?"
17-
reply = true
18-
19-
[default_permissions]
20-
groups_command = true
21-
help_command = true
22-
`;
23-
const extensions = [basicSetup, oneDark, tomlLanguage];
2410
return (
25-
<div>
26-
<CodeMirror value={config} extensions={extensions} />
27-
</div>
11+
<div><ConfigEditor guildID={guildID()} configKey="core" /></div>
2812
);
2913
}

frontend/src/route/home.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ function GuildsComponent() {
2121
if (guildList === undefined)
2222
return;
2323

24-
if ("error" in guildList)
25-
return;
26-
2724
return (
2825
<For each={guildList}>
2926
{guild => <GuildCard {...guild} />}

0 commit comments

Comments
 (0)