feat: graphql introspection, timestamps, custom scalar skaffolding
This commit is contained in:
parent
4397a310fe
commit
297eadc59b
10
codegen.yml
10
codegen.yml
|
@ -14,11 +14,19 @@ generates:
|
|||
plugins:
|
||||
- typescript
|
||||
|
||||
src/graphql/introspection.json:
|
||||
plugins:
|
||||
- introspection:
|
||||
minify: true
|
||||
|
||||
src/:
|
||||
preset: near-operation-file
|
||||
presetConfig:
|
||||
extension: .generated.tsx
|
||||
baseTypesPath: graphql/types.generated.ts
|
||||
plugins:
|
||||
- typescript-operations
|
||||
- typescript-operations:
|
||||
strictScalars: true
|
||||
scalars:
|
||||
Date: number
|
||||
- typed-document-node
|
||||
|
|
415
package-lock.json
generated
415
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -88,10 +88,12 @@
|
|||
"textversionjs": "^1.1.3",
|
||||
"ts-node": "^10.7.0",
|
||||
"tunnel": "^0.0.6",
|
||||
"urql": "^2.2.0"
|
||||
"urql": "^2.2.0",
|
||||
"urql-custom-scalars-exchange": "^0.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^2.6.2",
|
||||
"@graphql-codegen/introspection": "^2.1.1",
|
||||
"@graphql-codegen/near-operation-file-preset": "^2.2.9",
|
||||
"@graphql-codegen/schema-ast": "^2.4.1",
|
||||
"@graphql-codegen/typed-document-node": "^2.2.8",
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
export interface DashboardItem {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
contents: any;
|
||||
timestamp: string;
|
||||
creator: string;
|
||||
extra: any;
|
||||
}
|
1
src/graphql/introspection.json
Normal file
1
src/graphql/introspection.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -7,7 +7,7 @@ import { AppProps } from "next/app";
|
|||
import Router from "next/router";
|
||||
import NProgress from "nprogress";
|
||||
|
||||
import { graphqlEndpoint } from "../web/urql";
|
||||
import { getUrqlClientOptions } from "../web/urql";
|
||||
|
||||
Router.events.on("routeChangeStart", (as, { shallow }) => {
|
||||
if (!shallow) {
|
||||
|
@ -25,9 +25,6 @@ function MyApp({ Component, pageProps }: AppProps) {
|
|||
);
|
||||
}
|
||||
|
||||
export default withUrqlClient(
|
||||
() => ({
|
||||
url: graphqlEndpoint,
|
||||
}),
|
||||
{ ssr: false }
|
||||
)(MyApp);
|
||||
export default withUrqlClient((ssr) => getUrqlClientOptions(ssr), {
|
||||
ssr: false,
|
||||
})(MyApp);
|
||||
|
|
|
@ -2,21 +2,21 @@ import * as Types from '../../graphql/types.generated';
|
|||
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
import { QuestionFragmentDoc } from '../search/queries.generated';
|
||||
export type DashboardFragment = { __typename?: 'Dashboard', id: string, title: string, description: string, creator: string, questions: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: any, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> };
|
||||
export type DashboardFragment = { __typename?: 'Dashboard', id: string, title: string, description: string, creator: string, questions: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: number, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> };
|
||||
|
||||
export type DashboardByIdQueryVariables = Types.Exact<{
|
||||
id: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type DashboardByIdQuery = { __typename?: 'Query', result: { __typename?: 'Dashboard', id: string, title: string, description: string, creator: string, questions: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: any, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> } };
|
||||
export type DashboardByIdQuery = { __typename?: 'Query', result: { __typename?: 'Dashboard', id: string, title: string, description: string, creator: string, questions: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: number, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> } };
|
||||
|
||||
export type CreateDashboardMutationVariables = Types.Exact<{
|
||||
input: Types.CreateDashboardInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateDashboardMutation = { __typename?: 'Mutation', result: { __typename?: 'CreateDashboardResult', dashboard: { __typename?: 'Dashboard', id: string, title: string, description: string, creator: string, questions: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: any, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> } } };
|
||||
export type CreateDashboardMutation = { __typename?: 'Mutation', result: { __typename?: 'CreateDashboardResult', dashboard: { __typename?: 'Dashboard', id: string, title: string, description: string, creator: string, questions: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: number, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> } } };
|
||||
|
||||
export const DashboardFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Dashboard"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Dashboard"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"creator"}},{"kind":"Field","name":{"kind":"Name","value":"questions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Question"}}]}}]}},...QuestionFragmentDoc.definitions]} as unknown as DocumentNode<DashboardFragment, unknown>;
|
||||
export const DashboardByIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardById"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"result"},"name":{"kind":"Name","value":"dashboard"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Dashboard"}}]}}]}},...DashboardFragmentDoc.definitions]} as unknown as DocumentNode<DashboardByIdQuery, DashboardByIdQueryVariables>;
|
||||
|
|
|
@ -105,7 +105,7 @@ const getCurrencySymbolIfNeeded = ({
|
|||
|
||||
const showFirstQualityIndicator = ({
|
||||
numforecasts,
|
||||
timestamp,
|
||||
lastUpdated,
|
||||
showTimeStamp,
|
||||
qualityindicators,
|
||||
}) => {
|
||||
|
@ -124,7 +124,7 @@ const showFirstQualityIndicator = ({
|
|||
<circle cx="4" cy="4" r="4" fill="rgb(29, 78, 216)" />
|
||||
</svg>
|
||||
{`Last updated: ${
|
||||
timestamp && !!timestamp.slice ? timestamp.slice(0, 10) : "unknown"
|
||||
lastUpdated ? lastUpdated.toISOString().slice(0, 10) : "unknown"
|
||||
}`}
|
||||
</span>
|
||||
);
|
||||
|
@ -135,13 +135,13 @@ const showFirstQualityIndicator = ({
|
|||
|
||||
const displayQualityIndicators: React.FC<{
|
||||
numforecasts: number;
|
||||
timestamp: number;
|
||||
lastUpdated: Date;
|
||||
showTimeStamp: boolean;
|
||||
qualityindicators: any;
|
||||
platform: string; // id string - e.g. "goodjudgment", not "Good Judgment"
|
||||
}> = ({
|
||||
numforecasts,
|
||||
timestamp,
|
||||
lastUpdated,
|
||||
showTimeStamp,
|
||||
qualityindicators,
|
||||
platform,
|
||||
|
@ -151,7 +151,7 @@ const displayQualityIndicators: React.FC<{
|
|||
<div className="text-sm">
|
||||
{showFirstQualityIndicator({
|
||||
numforecasts,
|
||||
timestamp,
|
||||
lastUpdated,
|
||||
showTimeStamp,
|
||||
qualityindicators,
|
||||
})}
|
||||
|
@ -238,7 +238,7 @@ interface Props {
|
|||
platformLabel: string;
|
||||
numforecasts: any;
|
||||
qualityindicators: any;
|
||||
timestamp: any;
|
||||
lastUpdated: Date;
|
||||
showTimeStamp: boolean;
|
||||
expandFooterToFullWidth: boolean;
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ export const QuestionFooter: React.FC<Props> = ({
|
|||
platformLabel,
|
||||
numforecasts,
|
||||
qualityindicators,
|
||||
timestamp,
|
||||
lastUpdated,
|
||||
showTimeStamp,
|
||||
expandFooterToFullWidth,
|
||||
}) => {
|
||||
|
@ -288,7 +288,7 @@ export const QuestionFooter: React.FC<Props> = ({
|
|||
>
|
||||
{displayQualityIndicators({
|
||||
numforecasts,
|
||||
timestamp,
|
||||
lastUpdated,
|
||||
showTimeStamp,
|
||||
qualityindicators,
|
||||
platform,
|
||||
|
|
|
@ -254,13 +254,14 @@ const CopyText: React.FC<{ text: string; displayText: string }> = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
const LastUpdated: React.FC<{ timestamp: string }> = ({ timestamp }) => (
|
||||
const LastUpdated: React.FC<{ timestamp: Date }> = ({ timestamp }) => (
|
||||
<div className="flex items-center">
|
||||
<svg className="mt-1" height="10" width="16">
|
||||
<circle cx="4" cy="4" r="4" fill="rgb(29, 78, 216)" />
|
||||
</svg>
|
||||
<span className="text-gray-600">
|
||||
Last updated: {timestamp ? timestamp.slice(0, 10) : "unknown"}
|
||||
Last updated:{" "}
|
||||
{timestamp ? timestamp.toISOString().slice(0, 10) : "unknown"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
@ -290,6 +291,7 @@ export const DisplayQuestion: React.FC<Props> = ({
|
|||
expandFooterToFullWidth,
|
||||
showIdToggle,
|
||||
}) => {
|
||||
const lastUpdated = new Date(timestamp * 1000);
|
||||
const displayTimestampAtBottom =
|
||||
checkIfDisplayTimeStampAtBottom(qualityIndicators);
|
||||
|
||||
|
@ -331,7 +333,7 @@ export const DisplayQuestion: React.FC<Props> = ({
|
|||
showTimeStamp && !displayTimestampAtBottom ? "sm:block" : ""
|
||||
}`}
|
||||
>
|
||||
<LastUpdated timestamp={timestamp} />
|
||||
<LastUpdated timestamp={lastUpdated} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -343,7 +345,7 @@ export const DisplayQuestion: React.FC<Props> = ({
|
|||
showTimeStamp && !displayTimestampAtBottom ? "sm:block" : ""
|
||||
} ml-6`}
|
||||
>
|
||||
<LastUpdated timestamp={timestamp} />
|
||||
<LastUpdated timestamp={lastUpdated} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -368,7 +370,7 @@ export const DisplayQuestion: React.FC<Props> = ({
|
|||
} self-center`}
|
||||
>
|
||||
{/* This one is exclusively for mobile*/}
|
||||
<LastUpdated timestamp={timestamp} />
|
||||
<LastUpdated timestamp={lastUpdated} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<QuestionFooter
|
||||
|
@ -377,7 +379,7 @@ export const DisplayQuestion: React.FC<Props> = ({
|
|||
platformLabel={platform.label}
|
||||
numforecasts={qualityIndicators.numForecasts}
|
||||
qualityindicators={qualityIndicators}
|
||||
timestamp={timestamp}
|
||||
lastUpdated={lastUpdated}
|
||||
showTimeStamp={showTimeStamp && displayTimestampAtBottom}
|
||||
expandFooterToFullWidth={expandFooterToFullWidth}
|
||||
/>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import * as Types from '../../graphql/types.generated';
|
||||
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
export type QuestionFragment = { __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: any, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } };
|
||||
export type QuestionFragment = { __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: number, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } };
|
||||
|
||||
export type FrontpageQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FrontpageQuery = { __typename?: 'Query', result: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: any, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> };
|
||||
export type FrontpageQuery = { __typename?: 'Query', result: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: number, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> };
|
||||
|
||||
export type SearchQueryVariables = Types.Exact<{
|
||||
input: Types.SearchInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type SearchQuery = { __typename?: 'Query', result: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: any, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> };
|
||||
export type SearchQuery = { __typename?: 'Query', result: Array<{ __typename?: 'Question', id: string, url: string, title: string, description: string, timestamp: number, visualization?: string | null, options: Array<{ __typename?: 'ProbabilityOption', name?: string | null, probability?: number | null }>, platform: { __typename?: 'Platform', id: string, label: string }, qualityIndicators: { __typename?: 'QualityIndicators', stars: number, numForecasts?: number | null } }> };
|
||||
|
||||
export const QuestionFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Question"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Question"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"probability"}}]}},{"kind":"Field","name":{"kind":"Name","value":"platform"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"qualityIndicators"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stars"}},{"kind":"Field","name":{"kind":"Name","value":"numForecasts"}}]}},{"kind":"Field","name":{"kind":"Name","value":"visualization"}}]}}]} as unknown as DocumentNode<QuestionFragment, unknown>;
|
||||
export const FrontpageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Frontpage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"result"},"name":{"kind":"Name","value":"frontpage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Question"}}]}}]}},...QuestionFragmentDoc.definitions]} as unknown as DocumentNode<FrontpageQuery, FrontpageQueryVariables>;
|
||||
|
|
|
@ -1,19 +1,40 @@
|
|||
import { initUrqlClient } from "next-urql";
|
||||
import { initUrqlClient, SSRExchange } from "next-urql";
|
||||
import { cacheExchange, dedupExchange, fetchExchange, ssrExchange } from "urql";
|
||||
import customScalarsExchange from "urql-custom-scalars-exchange";
|
||||
|
||||
import schema from "../graphql/introspection.json";
|
||||
import { getBasePath } from "./utils";
|
||||
|
||||
export const graphqlEndpoint = `${getBasePath()}/api/graphql`;
|
||||
|
||||
const scalarsExchange = customScalarsExchange({
|
||||
// Types don't match for some reason.
|
||||
// Related:
|
||||
// - https://github.com/apollographql/apollo-tooling/issues/1491
|
||||
// - https://spectrum.chat/urql/help/schema-property-kind-is-missing-in-type~29c8f416-068c-485a-adf1-935686b99d05
|
||||
schema: schema as any,
|
||||
scalars: {
|
||||
/* not compatible with next.js serialization limitations, unfortunately */
|
||||
// Date(value: number) {
|
||||
// return new Date(value * 1000);
|
||||
// },
|
||||
},
|
||||
});
|
||||
|
||||
export const getUrqlClientOptions = (ssr: SSRExchange) => ({
|
||||
url: graphqlEndpoint,
|
||||
exchanges: [
|
||||
dedupExchange,
|
||||
scalarsExchange,
|
||||
cacheExchange,
|
||||
ssr,
|
||||
fetchExchange,
|
||||
],
|
||||
});
|
||||
|
||||
// for getServerSideProps/getStaticProps only
|
||||
export const ssrUrql = () => {
|
||||
const ssrCache = ssrExchange({ isClient: false });
|
||||
const client = initUrqlClient(
|
||||
{
|
||||
url: graphqlEndpoint,
|
||||
exchanges: [dedupExchange, cacheExchange, ssrCache, fetchExchange],
|
||||
},
|
||||
false
|
||||
);
|
||||
const client = initUrqlClient(getUrqlClientOptions(ssrCache), false);
|
||||
return [ssrCache, client] as const;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user