]> git.localhorst.tv Git - alttp.git/commitdiff
show details in discord command log
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 11 Jul 2025 09:12:14 +0000 (11:12 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 11 Jul 2025 09:12:14 +0000 (11:12 +0200)
package-lock.json
package.json
resources/js/components/discord-bot/GuildProtocol.jsx
resources/js/components/discord-bot/GuildProtocolEntry.jsx [new file with mode: 0644]
resources/js/i18n/de.js
resources/js/i18n/en.js
resources/sass/common.scss
resources/sass/discord.scss

index b8998a22631720801544303692fffd745ba50e85..f8753493f5e381404a5e7da50ab855d08e639e3f 100644 (file)
@@ -39,6 +39,7 @@
             "devDependencies": {
                 "@babel/eslint-parser": "^7.22.11",
                 "@babel/preset-react": "^7.13.13",
+                "@codemirror/lang-json": "^6.0.2",
                 "@popperjs/core": "^2.10.2",
                 "@tailwindcss/forms": "^0.5.6",
                 "@testing-library/jest-dom": "^6.4.2",
                 "@lezer/javascript": "^1.0.0"
             }
         },
+        "node_modules/@codemirror/lang-json": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
+            "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@codemirror/language": "^6.0.0",
+                "@lezer/json": "^1.0.0"
+            }
+        },
         "node_modules/@codemirror/language": {
             "version": "6.11.1",
             "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz",
                 "@lezer/lr": "^1.3.0"
             }
         },
+        "node_modules/@lezer/json": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
+            "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@lezer/common": "^1.2.0",
+                "@lezer/highlight": "^1.0.0",
+                "@lezer/lr": "^1.0.0"
+            }
+        },
         "node_modules/@lezer/lr": {
             "version": "1.4.2",
             "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
index b51ad973eece9efcdb25d1f7dc3b4716d6eb649c..2f1696f2a3b102521a4f96d084f1a2f8b772bd9c 100644 (file)
@@ -9,6 +9,7 @@
     "devDependencies": {
         "@babel/eslint-parser": "^7.22.11",
         "@babel/preset-react": "^7.13.13",
+        "@codemirror/lang-json": "^6.0.2",
         "@popperjs/core": "^2.10.2",
         "@tailwindcss/forms": "^0.5.6",
         "@testing-library/jest-dom": "^6.4.2",
index fd65cbc1c5b7281aedd83249b14bf7a4aa37b6c6..e653367138d9e0b612ee915c8bd86851fc6ec449 100644 (file)
@@ -1,33 +1,11 @@
 import PropTypes from 'prop-types';
 import React from 'react';
-import { useTranslation } from 'react-i18next';
 
-import { getUserName } from '../../helpers/User';
+import GuildProtocolEntry from './GuildProtocolEntry';
 
 const GuildProtocol = ({ protocol }) => {
-       const { t } = useTranslation();
-
        return protocol.map((entry) =>
-               <div className="discord-bot-protocol border-top" key={entry.id}>
-                       <div className="d-flex justify-content-between">
-                               <span>{t(`discordBot.commandType.${entry.command}`)}</span>
-                               <span>{t(`discordBot.commandStatus.${entry.status}`)}</span>
-                       </div>
-                       <div className="d-flex justify-content-between">
-                               <span className="text-muted">
-                                       {entry.user
-                                               ? t('discordBot.commandTimeUser', { time: new Date(entry.created_at), user: getUserName(entry.user) })
-                                               : t('discordBot.commandTime', { time: new Date(entry.created_at) })
-                                       }
-                               </span>
-                               <span className="text-muted">
-                                       {entry.executed_at
-                                               ? t('discordBot.commandTime', { time: new Date(entry.executed_at) })
-                                               : t('discordBot.commandPending')
-                                       }
-                               </span>
-                       </div>
-               </div>
+               <GuildProtocolEntry entry={entry} key={entry.id} />
        );
 };
 
diff --git a/resources/js/components/discord-bot/GuildProtocolEntry.jsx b/resources/js/components/discord-bot/GuildProtocolEntry.jsx
new file mode 100644 (file)
index 0000000..dd8d52d
--- /dev/null
@@ -0,0 +1,105 @@
+import { json } from '@codemirror/lang-json';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import { githubDark } from '@uiw/codemirror-theme-github';
+import CodeMirror from '@uiw/react-codemirror';
+
+import { getUserName } from '../../helpers/User';
+
+const GuildProtocolEntry = ({ entry }) => {
+       const [showDetail, setShowDeatil] = React.useState(false);
+
+       const { t } = useTranslation();
+
+       const className = React.useMemo(() => {
+               const classNames = ['discord-bot-protocol', 'border-top'];
+               if (entry.status === 'exception') {
+                       classNames.push('has-error');
+               }
+               return classNames.join(' ');
+       }, [entry]);
+
+       const statusLine = React.useMemo(() => {
+               const info = {};
+               if (entry.status === 'exception') {
+                       if (entry.result && entry.result.type === 'Discord\\Http\\Exceptions\\NoPermissionsException') {
+                               info.message = t('discordBot.commandResult.permissionDenied');
+                       } else {
+                               info.message = entry.result.type;
+                       }
+               }
+               return t(`discordBot.commandStatus.${entry.status}`, info);
+       }, [entry, t]);
+
+       return <div className={className}>
+               <div className="d-flex justify-content-between">
+                       <span className="command-type">{t(`discordBot.commandType.${entry.command}`)}</span>
+                       {entry.parameters || entry.result ?
+                               <Button
+                                       className="command-status p-0"
+                                       onClick={() => setShowDeatil(d => !d)}
+                                       variant="link"
+                               >
+                                       {statusLine}
+                               </Button>
+                       :
+                               <span className="command-status">{statusLine}</span>
+                       }
+               </div>
+               <div className="d-flex justify-content-between">
+                       <span className="text-muted command-create-time">
+                               {entry.user
+                                       ? t('discordBot.commandTimeUser', { time: new Date(entry.created_at), user: getUserName(entry.user) })
+                                       : t('discordBot.commandTime', { time: new Date(entry.created_at) })
+                               }
+                       </span>
+                       <span className="text-muted command-execute-time">
+                               {entry.executed_at
+                                       ? t('discordBot.commandTime', { time: new Date(entry.executed_at) })
+                                       : t('discordBot.commandPending')
+                               }
+                       </span>
+               </div>
+               <div className={`command-detail ${showDetail ? '' : 'd-none'}`}>
+                       {entry.parameters ? <figure>
+                               <caption>{t('discordBot.commandParameters')}</caption>
+                               <CodeMirror
+                                       extensions={[json()]}
+                                       readOnly
+                                       theme={githubDark}
+                                       value={JSON.stringify(entry.parameters, null, 2)}
+                               />
+                       </figure> : null}
+                       {entry.result ? <figure>
+                               <caption>{t('discordBot.commandResult.heading')}</caption>
+                               <CodeMirror
+                                       extensions={[json()]}
+                                       readOnly
+                                       theme={githubDark}
+                                       value={JSON.stringify(entry.result, null, 2)}
+                               />
+                       </figure> : null}
+               </div>
+       </div>;
+};
+
+GuildProtocolEntry.propTypes = {
+       entry: PropTypes.shape({
+               command: PropTypes.string,
+               created_at: PropTypes.string,
+               executed_at: PropTypes.string,
+               id: PropTypes.number,
+               parameters: PropTypes.shape({
+               }),
+               result: PropTypes.shape({
+                       type: PropTypes.string,
+               }),
+               status: PropTypes.string,
+               user: PropTypes.shape({
+               }),
+       }).isRequired,
+};
+
+export default GuildProtocolEntry;
index 8bd22485b3064c4014156d4d80f5f9495aef3d20..be5da23843b25ff5df729448cd4bdce439bb9c05 100644 (file)
@@ -143,10 +143,15 @@ export default {
                        addUser: 'User abonnieren',
                        channel: 'Kanal',
                        channelControls: 'Kanal-Steuerung',
+                       commandParameters: 'Parameter',
                        commandPending: 'Steht aus',
+                       commandResult: {
+                               heading: 'Ergebnis',
+                               permissionDenied: 'Zugriff verweigert',
+                       },
                        commandStatus: {
                                done: 'Abgeschlossen',
-                               exception: 'Fehler',
+                               exception: 'Fehler: {{ message }}',
                                executing: 'Ausführen',
                                hold: 'Pausiert',
                                pending: 'Ausstehend',
index 9b4b06d4b028933a8345051a5a51bcd095c2a5ca..de6c2232961ab48883160afa4e5222e25c12a44e 100644 (file)
@@ -143,10 +143,15 @@ export default {
                        addUser: 'Subscribe to user',
                        channel: 'Channel',
                        channelControls: 'Channel controls',
+                       commandParameters: 'Parameters',
                        commandPending: 'Pending execution',
+                       commandResult: {
+                               heading: 'Result',
+                               permissionDenied: 'Permission denied',
+                       },
                        commandStatus: {
                                done: 'Done',
-                               exception: 'Error',
+                               exception: 'Error: {{ message }}',
                                executing: 'Executing',
                                hold: 'Hold',
                                pending: 'Pending',
index f81daa321f202c6b8a2ad57de522272a2833b051..bbb4f0f246e67fb1d88958fd9cf869ea36b90ba2 100644 (file)
@@ -30,6 +30,12 @@ h1 {
        }
 }
 
+pre.code {
+       background: $dark;
+       color: $light;
+       padding: .5ex 1ex;
+}
+
 @keyframes loading-pulse {
        from {
                box-shadow: 0 0 0 2em #aaa;
index c66b740dc45e44fbfe8cd3f020a63aa432bc6b1f..ae813c8af7ac84b2c37ec72c47ce739a4fa43224 100644 (file)
@@ -5,6 +5,18 @@
        }
 }
 
+.discord-bot-protocol {
+       .command-status {
+               color: inherit;
+               text-decoration: none;
+       }
+       &.has-error {
+               .command-status {
+                       color: $warning;
+               }
+       }
+}
+
 .guild-box {
        padding: 0;
        color: inherit;