Skip to content

Commit

Permalink
Relay WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyberboss committed Oct 1, 2024
1 parent 927d75c commit 3a98470
Show file tree
Hide file tree
Showing 8 changed files with 542 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.graphql.ts auto eol=lf
17 changes: 14 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "tgstation-server-webpanel",
"private": true,
"version": "7.0.0",
"tgs_api_version": "10.10.0",
"homepage": "https://tgstation.github.io/tgstation-server-webpanel",
"repository": {
"type": "git",
Expand All @@ -24,12 +25,13 @@
"scripts": {
"dev": "concurrently --kill-others \"npm:dev-server\" \"npm:storybook\"",
"dev-server": "vite",
"build": "tsc -b && vite build",
"build": "relay-compiler --validate && tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"chromatic": "npx chromatic"
"chromatic": "npx chromatic",
"relay": "relay-compiler"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.6.0",
Expand All @@ -45,10 +47,14 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"concurrently": "^9.0.1",
"graphql": "15.x",
"graphql-sse": "^2.5.3",
"lucide-react": "^0.446.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-intl": "^6.7.0",
"react-relay": "^18.0.0",
"relay-runtime": "^18.0.0",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7"
},
Expand All @@ -66,20 +72,25 @@
"@types/node": "^22.7.3",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-relay": "^16.0.6",
"@types/relay-runtime": "^17.0.4",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20",
"babel-plugin-relay": "^18.0.0",
"chromatic": "^11.10.4",
"eslint": "^9.9.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"eslint-plugin-storybook": "^0.9.0",
"globals": "^15.9.0",
"postcss": "^8.4.47",
"relay-compiler": "^18.0.0",
"storybook": "^8.3.4",
"tailwindcss": "^3.4.13",
"typescript": "^5.5.3",
"typescript-eslint": "^8.0.1",
"vite": "^5.4.1"
"vite": "^5.4.1",
"vite-plugin-relay": "^2.1.0"
},
"packageManager": "[email protected]",
"eslintConfig": {
Expand Down
11 changes: 11 additions & 0 deletions relay.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"src": "./src",
"language": "typescript",
"schema": "./src/schema.graphql",
"exclude": [
"**/node_modules/**",
"**/__mocks__/**",
"**/__generated__/**"
],
"eagerEsModules": true
}
92 changes: 92 additions & 0 deletions src/RelayEnvironment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import Pkg from "./../package.json";

import {
Environment,
Network,
RecordSource,
Store,
Observable,
FetchFunction,
SubscribeFunction,
GraphQLResponse,
} from "relay-runtime";
import { createClient, Sink } from "graphql-sse";
import { ExecutionResult } from "graphql";

const CreateRelayEnvironment = (
serverUrl: string,
bearerProvider: () => string | null
) => {
const graphQLEndpoint = `${serverUrl}/api/graphql`;

const createAuthHeader = () => {
const bearer = bearerProvider();
return bearer ? `Bearer ${bearer}` : "";
};

const fetchFn: FetchFunction = async (request, variables) => {
const resp = await fetch(graphQLEndpoint, {
method: "POST",
headers: {
Accept: "application/graphql-response+json; charset=utf-8, application/json; charset=utf-8",
"Content-Type": "application/json",
Api: `Tgstation.Server.Api/${Pkg.tgs_api_version}`,
Authorization:
request.name === "Login" ? "" : createAuthHeader(), // login should always be unauthed
},
body: JSON.stringify({
query: request.text, // <-- The GraphQL document composed by Relay
variables,
}),
});

return await resp.json();
};

// We only want to setup subscriptions if we are on the client.
const subscriptionsClient = createClient({
url: graphQLEndpoint,
headers: (): Record<string, string> => {
return {
Api: `Tgstation.Server.Api/${Pkg.tgs_api_version}`,
Authorization: createAuthHeader(),
};
},
});

const subscribeFn: SubscribeFunction = (operation, variables) => {
const gqlSseRelaySinkAdapter = <Data, Extensions>(
relaySink: Sink<GraphQLResponse>
): Sink<ExecutionResult<Data, Extensions>> => {
return {
error: (error: unknown) => relaySink.error(error),
complete: () => relaySink.complete(),
next: (value: ExecutionResult<Data, Extensions>) => {

Check failure on line 64 in src/RelayEnvironment.ts

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

'value' is defined but never used
throw new Error("TODO");
},
};
};

return Observable.create((sink) => {
if (!operation.text) {
return sink.error(new Error("Operation text cannot be empty"));
}
return subscriptionsClient.subscribe(
{
operationName: operation.name,
query: operation.text,
variables,
},
gqlSseRelaySinkAdapter(sink)
);
});
};

console.log("Creating relay environment...");
return new Environment({
network: Network.create(fetchFn, subscribeFn),
store: new Store(new RecordSource()),
});
};

export default CreateRelayEnvironment;
14 changes: 12 additions & 2 deletions src/components/core/Meta/Meta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import Loading from "@/components/utils/Loading/Loading";
import { useIntl } from "react-intl";

import Pkg from "../../../../package.json";
import { useEffect } from "react";
import { useContext, useEffect, useState } from "react";
import { RelayEnvironmentProvider } from "react-relay";
import CreateRelayEnvironment from "@/RelayEnvironment";
import ConfigContext from "@/context/config/Context";

const Layout = () => {
const version = Pkg.version;
Expand All @@ -12,9 +15,16 @@ const Layout = () => {
useEffect(() => {
document.title = intl.formatMessage({ id: "title" }, { version });
});

const config = useContext(ConfigContext);

const [relayEnviroment] = useState(CreateRelayEnvironment(config.ApiPath));

return (
<>
<Loading noIntl message="asdf" />
<RelayEnvironmentProvider environment={relayEnviroment}>
<Loading noIntl message="asdf" />
</RelayEnvironmentProvider>
</>
);
};
Expand Down
4 changes: 4 additions & 0 deletions src/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Replace this with your own GraphQL schema file!
type Query {
field: String
}
11 changes: 6 additions & 5 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import path from "path"
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import relay from "vite-plugin-relay";
import path from "path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
plugins: [relay, react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
});
Loading

0 comments on commit 3a98470

Please sign in to comment.