mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: use monaco instead of codemirror on api page
This commit is contained in:
1 parent
efbc3c0162
commit
9c02ed4dd8
4 files changed
+204
-40
No files matched your search
@@ -7,14 +7,11 @@ import FriendlyErrorsPlugin from 'friendly-errors-webpack-plugin';
|
|||||||
import ExtractCssPlugin from 'mini-css-extract-plugin';
|
import ExtractCssPlugin from 'mini-css-extract-plugin';
|
||||||
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
|
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import SpeedMeasurePlugin from 'speed-measure-webpack-plugin';
|
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
import WebpackBar from 'webpackbar';
|
import WebpackBar from 'webpackbar';
|
||||||
import root from '../utils/root';
|
import root from '../utils/root';
|
||||||
|
|
||||||
const smp = new SpeedMeasurePlugin();
|
|
||||||
|
|
||||||
export default function (env: { production?: boolean, measure?: boolean } = {}) {
|
export default function (env: { production?: boolean, measure?: boolean } = {}) {
|
||||||
function esbuildLoader() {
|
function esbuildLoader() {
|
||||||
return {
|
return {
|
||||||
@@ -252,11 +249,18 @@ export default function (env: { production?: boolean, measure?: boolean } = {})
|
|||||||
id: 'vs/language/yaml/yamlWorker',
|
id: 'vs/language/yaml/yamlWorker',
|
||||||
entry: require.resolve('monaco-yaml/yaml.worker.js'),
|
entry: require.resolve('monaco-yaml/yaml.worker.js'),
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
label: 'graphql',
|
||||||
|
entry: require.resolve('monaco-graphql/esm/monaco.contribution.js'),
|
||||||
|
worker: {
|
||||||
|
id: 'vs/language/graphql/graphqlWorker',
|
||||||
|
entry: require.resolve('monaco-graphql/esm/graphql.worker.js'),
|
||||||
|
},
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
...env.measure ? [new BundleAnalyzerPlugin({ analyzerPort: 'auto' })] : [],
|
...env.measure ? [new BundleAnalyzerPlugin({ analyzerPort: 'auto' })] : [],
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return env.measure ? smp.wrap(config) : config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.39.10",
|
"version": "4.39.11",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "hydro.js",
|
"main": "hydro.js",
|
||||||
@@ -65,6 +65,7 @@
|
|||||||
"monaco-editor": "^0.33.0",
|
"monaco-editor": "^0.33.0",
|
||||||
"monaco-editor-nls": "^2.0.0",
|
"monaco-editor-nls": "^2.0.0",
|
||||||
"monaco-editor-webpack-plugin": "^7.0.1",
|
"monaco-editor-webpack-plugin": "^7.0.1",
|
||||||
|
"monaco-graphql": "^1.1.2",
|
||||||
"monaco-themes": "^0.4.2",
|
"monaco-themes": "^0.4.2",
|
||||||
"monaco-yaml": "^4.0.0",
|
"monaco-yaml": "^4.0.0",
|
||||||
"nanoid": "^4.0.0",
|
"nanoid": "^4.0.0",
|
||||||
@@ -91,7 +92,6 @@
|
|||||||
"redux-thunk": "^2.4.1",
|
"redux-thunk": "^2.4.1",
|
||||||
"rupture": "^0.7.1",
|
"rupture": "^0.7.1",
|
||||||
"slideout": "^1.0.1",
|
"slideout": "^1.0.1",
|
||||||
"speed-measure-webpack-plugin": "^1.5.0",
|
|
||||||
"sticky-kit": "^1.1.3",
|
"sticky-kit": "^1.1.3",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"stylus": "^0.59.0",
|
"stylus": "^0.59.0",
|
||||||
|
|||||||
@@ -1,50 +1,171 @@
|
|||||||
/* eslint-disable react/function-component-definition */
|
import 'graphiql/src/css/doc-explorer.css';
|
||||||
import 'graphiql/graphiql.css';
|
|
||||||
|
|
||||||
|
import type { GraphQLSchema } from 'graphql';
|
||||||
|
import { load as loadYaml } from 'js-yaml';
|
||||||
|
import type * as monaco from 'monaco-editor';
|
||||||
|
import type { SchemaConfig } from 'monaco-graphql/src/typings';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { NamedPage } from 'vj/misc/Page';
|
import { NamedPage } from 'vj/misc/Page';
|
||||||
import request from 'vj/utils/request';
|
import request from 'vj/utils/request';
|
||||||
|
|
||||||
const Logo = () => <span>Hydro API Console </span>;
|
|
||||||
const defaultQuery = `\
|
const defaultQuery = `\
|
||||||
query {
|
query Example(
|
||||||
user(id: 1) {
|
$name: String!
|
||||||
|
) {
|
||||||
|
user(uname: $name) {
|
||||||
|
_id
|
||||||
uname
|
uname
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
|
const variablesString = 'name: Hydro';
|
||||||
|
const resultsString = '{}';
|
||||||
|
const schemaSdlString = `\
|
||||||
|
"""
|
||||||
|
Loading schema...
|
||||||
|
"""`;
|
||||||
|
|
||||||
const page = new NamedPage('api', async () => {
|
const page = new NamedPage('api', async () => {
|
||||||
const [{ default: GraphiQL }, { buildSchema }, res] = await Promise.all([
|
const [{ DocExplorer }, { buildClientSchema, getIntrospectionQuery, printSchema }, { load }] = await Promise.all([
|
||||||
import('graphiql/esm/index.js'),
|
import('graphiql/esm/components/DocExplorer'),
|
||||||
import('graphql'),
|
import('graphql/utilities'),
|
||||||
request.get('/api?schema'),
|
import('vj/components/monaco/loader'),
|
||||||
]);
|
]);
|
||||||
// @ts-ignore
|
const { monaco } = await load(['graphql', 'json', 'yaml']);
|
||||||
GraphiQL.Logo = Logo;
|
const { initializeMode } = await import('monaco-graphql/esm/initializeMode');
|
||||||
const App = () => (
|
|
||||||
<GraphiQL
|
const variablesModel = monaco.editor.createModel(
|
||||||
schema={buildSchema(res.schema)}
|
variablesString,
|
||||||
defaultQuery={defaultQuery}
|
'yaml',
|
||||||
fetcher={async (graphQLParams) => {
|
monaco.Uri.file('/1/variables.yaml'),
|
||||||
const data = await fetch(
|
);
|
||||||
'',
|
const variablesEditor = monaco.editor.create(
|
||||||
{
|
document.getElementById('variables') as HTMLElement,
|
||||||
method: 'POST',
|
{
|
||||||
headers: {
|
model: variablesModel,
|
||||||
Accept: 'application/json',
|
language: 'yaml',
|
||||||
'Content-Type': 'application/json',
|
formatOnPaste: true,
|
||||||
},
|
formatOnType: true,
|
||||||
body: JSON.stringify(graphQLParams),
|
comments: {
|
||||||
credentials: 'same-origin',
|
insertSpace: true,
|
||||||
},
|
ignoreEmptyLines: true,
|
||||||
);
|
},
|
||||||
return data.json().catch(() => data.text());
|
},
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('graphiql')).render(<App />);
|
const operationModel = monaco.editor.createModel(
|
||||||
|
defaultQuery,
|
||||||
|
'graphql',
|
||||||
|
monaco.Uri.file('/1/operation.graphql'),
|
||||||
|
);
|
||||||
|
const operationEditor = monaco.editor.create(
|
||||||
|
document.getElementById('operation') as HTMLElement,
|
||||||
|
{
|
||||||
|
model: operationModel,
|
||||||
|
formatOnPaste: true,
|
||||||
|
formatOnType: true,
|
||||||
|
folding: true,
|
||||||
|
language: 'graphql',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const schemaModel = monaco.editor.createModel(
|
||||||
|
schemaSdlString,
|
||||||
|
'graphql',
|
||||||
|
monaco.Uri.file('/1/schema.graphqls'),
|
||||||
|
);
|
||||||
|
const schemaEditor = monaco.editor.create(
|
||||||
|
document.getElementById('schema-sdl') as HTMLElement,
|
||||||
|
{
|
||||||
|
model: schemaModel,
|
||||||
|
formatOnPaste: true,
|
||||||
|
formatOnType: true,
|
||||||
|
folding: true,
|
||||||
|
readOnly: true,
|
||||||
|
language: 'graphql',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultsModel = monaco.editor.createModel(
|
||||||
|
resultsString,
|
||||||
|
'json',
|
||||||
|
monaco.Uri.file('/1/results.json'),
|
||||||
|
);
|
||||||
|
const resultsEditor = monaco.editor.create(
|
||||||
|
document.getElementById('results') as HTMLElement,
|
||||||
|
{
|
||||||
|
model: resultsModel,
|
||||||
|
language: 'json',
|
||||||
|
wordWrap: 'on',
|
||||||
|
readOnly: true,
|
||||||
|
showFoldingControls: 'always',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const monacoGraphQLAPI = initializeMode({
|
||||||
|
formattingOptions: {
|
||||||
|
prettierConfig: {
|
||||||
|
printWidth: 120,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const toolbar = $('#toolbar')!;
|
||||||
|
toolbar.html();
|
||||||
|
const executeOpButton = $('<button id="execute-op">Run Operation ➤</button>');
|
||||||
|
toolbar.append(executeOpButton);
|
||||||
|
|
||||||
|
const operationUri = operationModel.uri.toString();
|
||||||
|
let schema: SchemaConfig;
|
||||||
|
let clientSchema: GraphQLSchema;
|
||||||
|
try {
|
||||||
|
const { data } = await request.post('/api?schema', {
|
||||||
|
query: getIntrospectionQuery(),
|
||||||
|
operationName: 'IntrospectionQuery',
|
||||||
|
});
|
||||||
|
clientSchema = buildClientSchema(data);
|
||||||
|
schema = {
|
||||||
|
introspectionJSON: data,
|
||||||
|
documentString: printSchema(clientSchema),
|
||||||
|
uri: monaco.Uri.parse('/api?schema').toString(),
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
schemaModel.setValue('"""\nFailed to load schema.\n"""');
|
||||||
|
}
|
||||||
|
monacoGraphQLAPI.setSchemaConfig([
|
||||||
|
{ ...schema, fileMatch: [operationUri, schemaModel.uri.toString()] },
|
||||||
|
]);
|
||||||
|
schemaEditor.setValue(schema.documentString || '');
|
||||||
|
|
||||||
|
const operationHandler = async () => {
|
||||||
|
try {
|
||||||
|
resultsEditor.setValue(JSON.stringify({ message: 'Executing...' }, null, 2));
|
||||||
|
const result = await request.post('/api?schema', {
|
||||||
|
query: operationEditor.getValue(),
|
||||||
|
variables: loadYaml(variablesEditor.getValue()),
|
||||||
|
});
|
||||||
|
resultsEditor.setValue(JSON.stringify(result, null, 2));
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof Error) {
|
||||||
|
resultsEditor.setValue(err.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
executeOpButton.on('click', operationHandler);
|
||||||
|
executeOpButton.on('touchend', operationHandler);
|
||||||
|
const opAction: monaco.editor.IActionDescriptor = {
|
||||||
|
id: 'graphql-run',
|
||||||
|
label: 'Run Operation',
|
||||||
|
contextMenuOrder: 0,
|
||||||
|
contextMenuGroupId: 'graphql',
|
||||||
|
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
|
||||||
|
run: operationHandler,
|
||||||
|
};
|
||||||
|
operationEditor.addAction(opAction);
|
||||||
|
variablesEditor.addAction(opAction);
|
||||||
|
resultsEditor.addAction(opAction);
|
||||||
|
|
||||||
|
createRoot(document.getElementById('docs')).render(<DocExplorer schema={clientSchema} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default page;
|
export default page;
|
||||||
@@ -1,4 +1,43 @@
|
|||||||
{% extends "layout/basic.html" %}
|
{% extends "layout/basic.html" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="graphiql" style="height:90vh;"></div>
|
<div style="height: 80vh">
|
||||||
|
<div id="toolbar" style="display: inline-flex"></div>
|
||||||
|
<div style="display: flex;align-items: stretch">
|
||||||
|
<div style="width: 30vw">
|
||||||
|
<div id="operation"></div>
|
||||||
|
<div id="variables"></div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 45vw">
|
||||||
|
<div id="results"></div>
|
||||||
|
<div id="schema-sdl"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="docs" class="graphiql-container"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
#operation {
|
||||||
|
height: 60vh;
|
||||||
|
min-height: 260px;
|
||||||
|
}
|
||||||
|
#variables {
|
||||||
|
height: 30vh;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
#results {
|
||||||
|
align-items: stretch;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
#schema-sdl {
|
||||||
|
align-items: stretch;
|
||||||
|
height: 30vh;
|
||||||
|
}
|
||||||
|
.graphiql-container .doc-explorer-contents {
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
#docs {
|
||||||
|
font-family: var(--code-font-family)
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in new issue
Block a user