refactor: rename forecast -> question (see #40)
This commit is contained in:
parent
2ee82cdd15
commit
6543a729f3
|
@ -13,7 +13,7 @@
|
||||||
# React
|
# React
|
||||||
|
|
||||||
- create one file per one component (tiny helper components in the same file are fine)
|
- create one file per one component (tiny helper components in the same file are fine)
|
||||||
- name file identically to the component it describes (e.g. `const DisplayForecasts: React.FC<Props> = ...` in `DisplayForecasts.ts`)
|
- name file identically to the component it describes (e.g. `const DisplayQuestions: React.FC<Props> = ...` in `DisplayQuestions.ts`)
|
||||||
- use named export instead of default export for all React components
|
- use named export instead of default export for all React components
|
||||||
- it's better for refactoring
|
- it's better for refactoring
|
||||||
- and it plays well with `React.FC` typing
|
- and it plays well with `React.FC` typing
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Pool, PoolClient } from "pg";
|
import { Pool, PoolClient } from "pg";
|
||||||
|
|
||||||
import { Forecast } from "../platforms";
|
import { Question } from "../platforms";
|
||||||
import { hash } from "../utils/hash";
|
import { hash } from "../utils/hash";
|
||||||
import { measureTime } from "../utils/measureTime";
|
import { measureTime } from "../utils/measureTime";
|
||||||
import { roughSizeOfObject } from "../utils/roughSize";
|
import { roughSizeOfObject } from "../utils/roughSize";
|
||||||
|
|
||||||
const forecastTableNames = ["questions", "history"];
|
const questionTableNames = ["questions", "history"];
|
||||||
|
|
||||||
const allTableNames = [...forecastTableNames, "dashboards", "frontpage"];
|
const allTableNames = [...questionTableNames, "dashboards", "frontpage"];
|
||||||
|
|
||||||
/* Postgres database connection code */
|
/* Postgres database connection code */
|
||||||
const databaseURL = process.env.DIGITALOCEAN_POSTGRES;
|
const databaseURL = process.env.DIGITALOCEAN_POSTGRES;
|
||||||
|
@ -51,11 +51,11 @@ export async function pgBulkInsert({
|
||||||
tableName,
|
tableName,
|
||||||
client,
|
client,
|
||||||
}: {
|
}: {
|
||||||
data: Forecast[];
|
data: Question[];
|
||||||
tableName: string;
|
tableName: string;
|
||||||
client: PoolClient;
|
client: PoolClient;
|
||||||
}) {
|
}) {
|
||||||
if (!forecastTableNames.includes(tableName)) {
|
if (!questionTableNames.includes(tableName)) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`Table ${tableName} not in whitelist; stopping to avoid tricky sql injections`
|
`Table ${tableName} not in whitelist; stopping to avoid tricky sql injections`
|
||||||
);
|
);
|
||||||
|
@ -171,11 +171,11 @@ export async function pgUpsert({
|
||||||
tableName,
|
tableName,
|
||||||
replacePlatform,
|
replacePlatform,
|
||||||
}: {
|
}: {
|
||||||
contents: Forecast[];
|
contents: Question[];
|
||||||
tableName: string;
|
tableName: string;
|
||||||
replacePlatform?: string;
|
replacePlatform?: string;
|
||||||
}) {
|
}) {
|
||||||
if (!forecastTableNames.includes(tableName)) {
|
if (!questionTableNames.includes(tableName)) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`Table ${tableName} not in whitelist; stopping to avoid tricky sql injections`
|
`Table ${tableName} not in whitelist; stopping to avoid tricky sql injections`
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { pgRead, pool } from "./database/pg-wrapper";
|
import { pgRead, pool } from "./database/pg-wrapper";
|
||||||
import { Forecast } from "./platforms";
|
import { Question } from "./platforms";
|
||||||
|
|
||||||
export async function getFrontpage(): Promise<Forecast[]> {
|
export async function getFrontpage(): Promise<Question[]> {
|
||||||
const res = await pool.query(
|
const res = await pool.query(
|
||||||
"SELECT frontpage_sliced FROM frontpage ORDER BY id DESC LIMIT 1"
|
"SELECT frontpage_sliced FROM frontpage ORDER BY id DESC LIMIT 1"
|
||||||
);
|
);
|
||||||
|
@ -9,7 +9,7 @@ export async function getFrontpage(): Promise<Forecast[]> {
|
||||||
return res.rows[0].frontpage_sliced;
|
return res.rows[0].frontpage_sliced;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getFrontpageFull(): Promise<Forecast[]> {
|
export async function getFrontpageFull(): Promise<Question[]> {
|
||||||
const res = await pool.query(
|
const res = await pool.query(
|
||||||
"SELECT frontpage_full FROM frontpage ORDER BY id DESC LIMIT 1"
|
"SELECT frontpage_full FROM frontpage ORDER BY id DESC LIMIT 1"
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import axios from "axios";
|
||||||
import https from "https";
|
import https from "https";
|
||||||
|
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
const platformName = "betfair";
|
const platformName = "betfair";
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ async function whipIntoShape(data) {
|
||||||
async function processPredictions(data) {
|
async function processPredictions(data) {
|
||||||
let predictions = await whipIntoShape(data);
|
let predictions = await whipIntoShape(data);
|
||||||
// console.log(JSON.stringify(predictions, null, 4))
|
// console.log(JSON.stringify(predictions, null, 4))
|
||||||
let results: Forecast[] = predictions.map((prediction) => {
|
let results: Question[] = predictions.map((prediction) => {
|
||||||
/* if(Math.floor(Math.random() * 10) % 20 ==0){
|
/* if(Math.floor(Math.random() * 10) % 20 ==0){
|
||||||
console.log(JSON.stringify(prediction, null, 4))
|
console.log(JSON.stringify(prediction, null, 4))
|
||||||
} */
|
} */
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
const platformName = "fantasyscotus";
|
const platformName = "fantasyscotus";
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ async function processData(data) {
|
||||||
let historicalPercentageCorrect = data.stats.pcnt_correct;
|
let historicalPercentageCorrect = data.stats.pcnt_correct;
|
||||||
let historicalProbabilityCorrect =
|
let historicalProbabilityCorrect =
|
||||||
Number(historicalPercentageCorrect.replace("%", "")) / 100;
|
Number(historicalPercentageCorrect.replace("%", "")) / 100;
|
||||||
let results: Forecast[] = [];
|
let results: Question[] = [];
|
||||||
for (let event of events) {
|
for (let event of events) {
|
||||||
if (event.accuracy == "") {
|
if (event.accuracy == "") {
|
||||||
let id = `${platformName}-${event.id}`;
|
let id = `${platformName}-${event.id}`;
|
||||||
|
@ -75,7 +75,7 @@ async function processData(data) {
|
||||||
let predictionData = await getPredictionsData(event.docket_url);
|
let predictionData = await getPredictionsData(event.docket_url);
|
||||||
let pAffirm = predictionData.proportionAffirm;
|
let pAffirm = predictionData.proportionAffirm;
|
||||||
//let trackRecord = event.prediction.includes("Affirm") ? historicalProbabilityCorrect : 1-historicalProbabilityCorrect
|
//let trackRecord = event.prediction.includes("Affirm") ? historicalProbabilityCorrect : 1-historicalProbabilityCorrect
|
||||||
let eventObject: Forecast = {
|
let eventObject: Question = {
|
||||||
id: id,
|
id: id,
|
||||||
title: `In ${event.short_name}, the SCOTUS will affirm the lower court's decision`,
|
title: `In ${event.short_name}, the SCOTUS will affirm the lower court's decision`,
|
||||||
url: `https://fantasyscotus.net/user-predictions${event.docket_url}`,
|
url: `https://fantasyscotus.net/user-predictions${event.docket_url}`,
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { smarkets } from "./smarkets";
|
||||||
import { wildeford } from "./wildeford";
|
import { wildeford } from "./wildeford";
|
||||||
import { xrisk } from "./xrisk";
|
import { xrisk } from "./xrisk";
|
||||||
|
|
||||||
export interface Forecast {
|
export interface Question {
|
||||||
id: string;
|
id: string;
|
||||||
// "fantasyscotus-580"
|
// "fantasyscotus-580"
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ export interface Forecast {
|
||||||
extra?: any;
|
extra?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetcher should return null if platform failed to fetch forecasts for some reason
|
// fetcher should return null if platform failed to fetch questions for some reason
|
||||||
export type PlatformFetcher = () => Promise<Forecast[] | null>;
|
export type PlatformFetcher = () => Promise<Question[] | null>;
|
||||||
|
|
||||||
export interface Platform {
|
export interface Platform {
|
||||||
name: string; // short name for ids and `platform` db column, e.g. "xrisk"
|
name: string; // short name for ids and `platform` db column, e.g. "xrisk"
|
||||||
|
@ -76,7 +76,7 @@ export interface Platform {
|
||||||
// draft for the future callback-based streaming/chunking API:
|
// draft for the future callback-based streaming/chunking API:
|
||||||
// interface FetchOptions {
|
// interface FetchOptions {
|
||||||
// since?: string; // some kind of cursor, Date object or opaque string?
|
// since?: string; // some kind of cursor, Date object or opaque string?
|
||||||
// save: (forecasts: Forecast[]) => Promise<void>;
|
// save: (questions: Question[]) => Promise<void>;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// export type PlatformFetcher = (options: FetchOptions) => Promise<void>;
|
// export type PlatformFetcher = (options: FetchOptions) => Promise<void>;
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/* Imports */
|
/* Imports */
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { Tabletojson } from "tabletojson";
|
|
||||||
|
|
||||||
import { applyIfSecretExists } from "../utils/getSecrets";
|
import { applyIfSecretExists } from "../utils/getSecrets";
|
||||||
import { measureTime } from "../utils/measureTime";
|
import { measureTime } from "../utils/measureTime";
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import toMarkdown from "../utils/toMarkdown";
|
import toMarkdown from "../utils/toMarkdown";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
const platformName = "infer";
|
const platformName = "infer";
|
||||||
|
@ -78,12 +77,12 @@ async function fetchStats(questionUrl, cookie) {
|
||||||
let comments_count = firstEmbeddedJson.question.comments_count;
|
let comments_count = firstEmbeddedJson.question.comments_count;
|
||||||
let numforecasters = firstEmbeddedJson.question.predictors_count;
|
let numforecasters = firstEmbeddedJson.question.predictors_count;
|
||||||
let numforecasts = firstEmbeddedJson.question.prediction_sets_count;
|
let numforecasts = firstEmbeddedJson.question.prediction_sets_count;
|
||||||
let forecastType = firstEmbeddedJson.question.type;
|
let questionType = firstEmbeddedJson.question.type;
|
||||||
if (
|
if (
|
||||||
forecastType.includes("Binary") ||
|
questionType.includes("Binary") ||
|
||||||
forecastType.includes("NonExclusiveOpinionPoolQuestion") ||
|
questionType.includes("NonExclusiveOpinionPoolQuestion") ||
|
||||||
forecastType.includes("Forecast::Question") ||
|
questionType.includes("Forecast::Question") ||
|
||||||
!forecastType.includes("Forecast::MultiTimePeriodQuestion")
|
!questionType.includes("Forecast::MultiTimePeriodQuestion")
|
||||||
) {
|
) {
|
||||||
options = firstEmbeddedJson.question.answers.map((answer) => ({
|
options = firstEmbeddedJson.question.answers.map((answer) => ({
|
||||||
name: answer.name,
|
name: answer.name,
|
||||||
|
@ -148,7 +147,7 @@ function sleep(ms) {
|
||||||
async function infer_inner(cookie: string) {
|
async function infer_inner(cookie: string) {
|
||||||
let i = 1;
|
let i = 1;
|
||||||
let response = await fetchPage(i, cookie);
|
let response = await fetchPage(i, cookie);
|
||||||
let results: Forecast[] = [];
|
let results: Question[] = [];
|
||||||
|
|
||||||
await measureTime(async () => {
|
await measureTime(async () => {
|
||||||
// console.log("Downloading... This might take a couple of minutes. Results will be shown.")
|
// console.log("Downloading... This might take a couple of minutes. Results will be shown.")
|
||||||
|
@ -179,7 +178,7 @@ async function infer_inner(cookie: string) {
|
||||||
let questionNumRegex = new RegExp("questions/([0-9]+)");
|
let questionNumRegex = new RegExp("questions/([0-9]+)");
|
||||||
let questionNum = url.match(questionNumRegex)[1]; //.split("questions/")[1].split("-")[0];
|
let questionNum = url.match(questionNumRegex)[1]; //.split("questions/")[1].split("-")[0];
|
||||||
let id = `${platformName}-${questionNum}`;
|
let id = `${platformName}-${questionNum}`;
|
||||||
let question: Forecast = {
|
let question: Question = {
|
||||||
id: id,
|
id: id,
|
||||||
title: title,
|
title: title,
|
||||||
description: moreinfo.description,
|
description: moreinfo.description,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
const platformName = "manifold";
|
const platformName = "manifold";
|
||||||
|
@ -23,7 +23,7 @@ async function fetchData() {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showStatistics(results: Forecast[]) {
|
function showStatistics(results: Question[]) {
|
||||||
console.log(`Num unresolved markets: ${results.length}`);
|
console.log(`Num unresolved markets: ${results.length}`);
|
||||||
let sum = (arr) => arr.reduce((tally, a) => tally + a, 0);
|
let sum = (arr) => arr.reduce((tally, a) => tally + a, 0);
|
||||||
let num2StarsOrMore = results.filter(
|
let num2StarsOrMore = results.filter(
|
||||||
|
@ -44,7 +44,7 @@ function showStatistics(results: Forecast[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processPredictions(predictions) {
|
async function processPredictions(predictions) {
|
||||||
let results: Forecast[] = await predictions.map((prediction) => {
|
let results: Question[] = await predictions.map((prediction) => {
|
||||||
let id = `${platformName}-${prediction.id}`; // oops, doesn't match platform name
|
let id = `${platformName}-${prediction.id}`; // oops, doesn't match platform name
|
||||||
let probability = prediction.probability;
|
let probability = prediction.probability;
|
||||||
let options = [
|
let options = [
|
||||||
|
@ -59,7 +59,7 @@ async function processPredictions(predictions) {
|
||||||
type: "PROBABILITY",
|
type: "PROBABILITY",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const result: Forecast = {
|
const result: Question = {
|
||||||
id: id,
|
id: id,
|
||||||
title: prediction.question,
|
title: prediction.question,
|
||||||
url: prediction.url,
|
url: prediction.url,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
const platformName = "polymarket";
|
const platformName = "polymarket";
|
||||||
|
@ -68,7 +68,7 @@ export const polymarket: Platform = {
|
||||||
label: "PolyMarket",
|
label: "PolyMarket",
|
||||||
color: "#00314e",
|
color: "#00314e",
|
||||||
async fetcher() {
|
async fetcher() {
|
||||||
let results: Forecast[] = [];
|
let results: Question[] = [];
|
||||||
let webpageEndpointData = await fetchAllContractInfo();
|
let webpageEndpointData = await fetchAllContractInfo();
|
||||||
for (let marketInfo of webpageEndpointData) {
|
for (let marketInfo of webpageEndpointData) {
|
||||||
let address = marketInfo.marketMakerAddress;
|
let address = marketInfo.marketMakerAddress;
|
||||||
|
@ -102,7 +102,7 @@ export const polymarket: Platform = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: Forecast = {
|
let result: Question = {
|
||||||
id: id,
|
id: id,
|
||||||
title: marketInfo.question,
|
title: marketInfo.question,
|
||||||
url: "https://polymarket.com/market/" + marketInfo.slug,
|
url: "https://polymarket.com/market/" + marketInfo.slug,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { JSDOM } from "jsdom";
|
||||||
|
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import toMarkdown from "../utils/toMarkdown";
|
import toMarkdown from "../utils/toMarkdown";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
const platformName = "rootclaim";
|
const platformName = "rootclaim";
|
||||||
const jsonEndpoint =
|
const jsonEndpoint =
|
||||||
|
@ -50,7 +50,7 @@ export const rootclaim: Platform = {
|
||||||
color: "#0d1624",
|
color: "#0d1624",
|
||||||
async fetcher() {
|
async fetcher() {
|
||||||
const claims = await fetchAllRootclaims();
|
const claims = await fetchAllRootclaims();
|
||||||
const results: Forecast[] = [];
|
const results: Question[] = [];
|
||||||
|
|
||||||
for (const claim of claims) {
|
for (const claim of claims) {
|
||||||
const id = `${platformName}-${claim.slug.toLowerCase()}`;
|
const id = `${platformName}-${claim.slug.toLowerCase()}`;
|
||||||
|
@ -71,7 +71,7 @@ export const rootclaim: Platform = {
|
||||||
|
|
||||||
const description = await fetchDescription(url, claim.isclaim);
|
const description = await fetchDescription(url, claim.isclaim);
|
||||||
|
|
||||||
let obj: Forecast = {
|
let obj: Question = {
|
||||||
id,
|
id,
|
||||||
title: toMarkdown(claim.question).replace("\n", ""),
|
title: toMarkdown(claim.question).replace("\n", ""),
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { calculateStars } from "../utils/stars";
|
import { calculateStars } from "../utils/stars";
|
||||||
import { Forecast, Platform } from "./";
|
import { Platform, Question } from "./";
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
const platformName = "smarkets";
|
const platformName = "smarkets";
|
||||||
|
@ -159,7 +159,7 @@ export const smarkets: Platform = {
|
||||||
name = name+ (contractName=="Yes"?'':` (${contracts["contracts"][0].name})`)
|
name = name+ (contractName=="Yes"?'':` (${contracts["contracts"][0].name})`)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
let result: Forecast = {
|
let result: Question = {
|
||||||
id: id,
|
id: id,
|
||||||
title: name,
|
title: name,
|
||||||
url: "https://smarkets.com/event/" + market.event_id + market.slug,
|
url: "https://smarkets.com/event/" + market.event_id + market.slug,
|
||||||
|
|
|
@ -8,14 +8,14 @@ import { pgRead } from "../../database/pg-wrapper";
|
||||||
/* Utilities */
|
/* Utilities */
|
||||||
|
|
||||||
/* Support functions */
|
/* Support functions */
|
||||||
let getQualityIndicators = (forecast) =>
|
const getQualityIndicators = (question) =>
|
||||||
Object.entries(forecast.qualityindicators)
|
Object.entries(question.qualityindicators)
|
||||||
.map((entry) => `${entry[0]}: ${entry[1]}`)
|
.map((entry) => `${entry[0]}: ${entry[1]}`)
|
||||||
.join("; ");
|
.join("; ");
|
||||||
|
|
||||||
/* Body */
|
/* Body */
|
||||||
|
|
||||||
let main = async () => {
|
const main = async () => {
|
||||||
let highQualityPlatforms = [
|
let highQualityPlatforms = [
|
||||||
"CSET-foretell",
|
"CSET-foretell",
|
||||||
"Foretold",
|
"Foretold",
|
||||||
|
@ -24,21 +24,21 @@ let main = async () => {
|
||||||
"PredictIt",
|
"PredictIt",
|
||||||
"Rootclaim",
|
"Rootclaim",
|
||||||
];
|
];
|
||||||
let json = await pgRead({ tableName: "questions" });
|
const json = await pgRead({ tableName: "questions" });
|
||||||
console.log(json.length);
|
console.log(json.length);
|
||||||
//let uniquePlatforms = [...new Set(json.map(forecast => forecast.platform))]
|
//let uniquePlatforms = [...new Set(json.map(forecast => forecast.platform))]
|
||||||
//console.log(uniquePlatforms)
|
//console.log(uniquePlatforms)
|
||||||
|
|
||||||
let forecastsFromGoodPlatforms = json.filter((forecast) =>
|
const questionsFromGoodPlatforms = json.filter((question) =>
|
||||||
highQualityPlatforms.includes(forecast.platform)
|
highQualityPlatforms.includes(question.platform)
|
||||||
);
|
);
|
||||||
let tsv =
|
const tsv =
|
||||||
"index\ttitle\turl\tqualityindicators\n" +
|
"index\ttitle\turl\tqualityindicators\n" +
|
||||||
forecastsFromGoodPlatforms
|
questionsFromGoodPlatforms
|
||||||
.map((forecast, index) => {
|
.map((question, index) => {
|
||||||
let row = `${index}\t${forecast.title}\t${
|
let row = `${index}\t${question.title}\t${
|
||||||
forecast.url
|
question.url
|
||||||
}\t${getQualityIndicators(forecast)}`;
|
}\t${getQualityIndicators(question)}`;
|
||||||
console.log(row);
|
console.log(row);
|
||||||
return row;
|
return row;
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { pgRead } from "../../database/pg-wrapper";
|
||||||
/* Utilities */
|
/* Utilities */
|
||||||
|
|
||||||
/* Support functions */
|
/* Support functions */
|
||||||
let getQualityIndicators = (forecast) =>
|
let getQualityIndicators = (question) =>
|
||||||
Object.entries(forecast.qualityindicators)
|
Object.entries(question.qualityindicators)
|
||||||
.map((entry) => `${entry[0]}: ${entry[1]}`)
|
.map((entry) => `${entry[0]}: ${entry[1]}`)
|
||||||
.join("; ");
|
.join("; ");
|
||||||
|
|
||||||
|
@ -28,22 +28,22 @@ let main = async () => {
|
||||||
let highQualityPlatforms = ["Metaculus"]; // ['CSET-foretell', 'Foretold', 'Good Judgment Open', 'Metaculus', 'PredictIt', 'Rootclaim']
|
let highQualityPlatforms = ["Metaculus"]; // ['CSET-foretell', 'Foretold', 'Good Judgment Open', 'Metaculus', 'PredictIt', 'Rootclaim']
|
||||||
let json = await pgRead({ tableName: "questions" });
|
let json = await pgRead({ tableName: "questions" });
|
||||||
console.log(json.length);
|
console.log(json.length);
|
||||||
//let uniquePlatforms = [...new Set(json.map(forecast => forecast.platform))]
|
//let uniquePlatforms = [...new Set(json.map(question => question.platform))]
|
||||||
//console.log(uniquePlatforms)
|
//console.log(uniquePlatforms)
|
||||||
|
|
||||||
let forecastsFromGoodPlatforms = json.filter((forecast) =>
|
let questionsFromGoodPlatforms = json.filter((question) =>
|
||||||
highQualityPlatforms.includes(forecast.platform)
|
highQualityPlatforms.includes(question.platform)
|
||||||
);
|
);
|
||||||
let forecastsFromGoodPlatformsShuffled = shuffleArray(
|
let questionsFromGoodPlatformsShuffled = shuffleArray(
|
||||||
forecastsFromGoodPlatforms
|
questionsFromGoodPlatforms
|
||||||
);
|
);
|
||||||
let tsv =
|
let tsv =
|
||||||
"index\ttitle\turl\tqualityindicators\n" +
|
"index\ttitle\turl\tqualityindicators\n" +
|
||||||
forecastsFromGoodPlatforms
|
questionsFromGoodPlatforms
|
||||||
.map((forecast, index) => {
|
.map((question, index) => {
|
||||||
let row = `${index}\t${forecast.title}\t${
|
let row = `${index}\t${question.title}\t${
|
||||||
forecast.url
|
question.url
|
||||||
}\t${getQualityIndicators(forecast)}`;
|
}\t${getQualityIndicators(question)}`;
|
||||||
console.log(row);
|
console.log(row);
|
||||||
return row;
|
return row;
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { displayForecastsWrapperForCapture } from "../web/display/displayForecastsWrappers";
|
import { displayQuestionsWrapperForCapture } from "../web/display/displayQuestionsWrappers";
|
||||||
import { Layout } from "../web/display/Layout";
|
import { Layout } from "../web/display/Layout";
|
||||||
import { Props } from "../web/search/anySearchPage";
|
import { Props } from "../web/search/anySearchPage";
|
||||||
import CommonDisplay from "../web/search/CommonDisplay";
|
import CommonDisplay from "../web/search/CommonDisplay";
|
||||||
|
@ -18,7 +18,7 @@ const CapturePage: NextPage<Props> = (props) => {
|
||||||
hasAdvancedOptions={false}
|
hasAdvancedOptions={false}
|
||||||
placeholder={"Get best title match..."}
|
placeholder={"Get best title match..."}
|
||||||
displaySeeMoreHint={false}
|
displaySeeMoreHint={false}
|
||||||
displayForecastsWrapper={displayForecastsWrapperForCapture}
|
displayQuestionsWrapper={displayQuestionsWrapperForCapture}
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,13 +2,13 @@ import { GetServerSideProps, NextPage } from "next";
|
||||||
import Error from "next/error";
|
import Error from "next/error";
|
||||||
|
|
||||||
import { DashboardItem } from "../../../backend/dashboards";
|
import { DashboardItem } from "../../../backend/dashboards";
|
||||||
import { DisplayForecasts } from "../../../web/display/DisplayForecasts";
|
import { DisplayQuestions } from "../../../web/display/DisplayQuestions";
|
||||||
import { FrontendForecast } from "../../../web/platforms";
|
import { FrontendQuestion } from "../../../web/platforms";
|
||||||
import { getDashboardForecastsByDashboardId } from "../../../web/worker/getDashboardForecasts";
|
|
||||||
import { reqToBasePath } from "../../../web/utils";
|
import { reqToBasePath } from "../../../web/utils";
|
||||||
|
import { getDashboardQuestionsByDashboardId } from "../../../web/worker/getDashboardQuestions";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
dashboardForecasts: FrontendForecast[];
|
dashboardQuestions: FrontendQuestion[];
|
||||||
dashboardItem: DashboardItem;
|
dashboardItem: DashboardItem;
|
||||||
numCols?: number;
|
numCols?: number;
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
const dashboardId = context.query.id as string;
|
const dashboardId = context.query.id as string;
|
||||||
const numCols = Number(context.query.numCols);
|
const numCols = Number(context.query.numCols);
|
||||||
|
|
||||||
const { dashboardItem, dashboardForecasts } =
|
const { dashboardItem, dashboardQuestions } =
|
||||||
await getDashboardForecastsByDashboardId({
|
await getDashboardQuestionsByDashboardId({
|
||||||
dashboardId,
|
dashboardId,
|
||||||
basePath: reqToBasePath(context.req), // required on server side to find the API endpoint
|
basePath: reqToBasePath(context.req), // required on server side to find the API endpoint
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
dashboardForecasts,
|
dashboardQuestions,
|
||||||
dashboardItem,
|
dashboardItem,
|
||||||
numCols: !numCols ? null : numCols < 5 ? numCols : 4,
|
numCols: !numCols ? null : numCols < 5 ? numCols : 4,
|
||||||
},
|
},
|
||||||
|
@ -39,7 +39,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
const EmbedDashboardPage: NextPage<Props> = ({
|
const EmbedDashboardPage: NextPage<Props> = ({
|
||||||
dashboardForecasts,
|
dashboardQuestions,
|
||||||
dashboardItem,
|
dashboardItem,
|
||||||
numCols,
|
numCols,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -57,9 +57,9 @@ const EmbedDashboardPage: NextPage<Props> = ({
|
||||||
numCols || 3
|
numCols || 3
|
||||||
} gap-4 mb-6`}
|
} gap-4 mb-6`}
|
||||||
>
|
>
|
||||||
<DisplayForecasts
|
<DisplayQuestions
|
||||||
results={dashboardForecasts}
|
results={dashboardQuestions}
|
||||||
numDisplay={dashboardForecasts.length}
|
numDisplay={dashboardQuestions.length}
|
||||||
showIdToggle={false}
|
showIdToggle={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,16 +3,16 @@ import Error from "next/error";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import { DashboardItem } from "../../../backend/dashboards";
|
import { DashboardItem } from "../../../backend/dashboards";
|
||||||
import { DisplayForecasts } from "../../../web/display/DisplayForecasts";
|
import { DisplayQuestions } from "../../../web/display/DisplayQuestions";
|
||||||
import { InfoBox } from "../../../web/display/InfoBox";
|
import { InfoBox } from "../../../web/display/InfoBox";
|
||||||
import { Layout } from "../../../web/display/Layout";
|
import { Layout } from "../../../web/display/Layout";
|
||||||
import { LineHeader } from "../../../web/display/LineHeader";
|
import { LineHeader } from "../../../web/display/LineHeader";
|
||||||
import { FrontendForecast } from "../../../web/platforms";
|
import { FrontendQuestion } from "../../../web/platforms";
|
||||||
import { reqToBasePath } from "../../../web/utils";
|
import { reqToBasePath } from "../../../web/utils";
|
||||||
import { getDashboardForecastsByDashboardId } from "../../../web/worker/getDashboardForecasts";
|
import { getDashboardQuestionsByDashboardId } from "../../../web/worker/getDashboardQuestions";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
dashboardForecasts: FrontendForecast[];
|
dashboardQuestions: FrontendQuestion[];
|
||||||
dashboardItem: DashboardItem;
|
dashboardItem: DashboardItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
) => {
|
) => {
|
||||||
const dashboardId = context.query.id as string;
|
const dashboardId = context.query.id as string;
|
||||||
|
|
||||||
const { dashboardForecasts, dashboardItem } =
|
const { dashboardQuestions, dashboardItem } =
|
||||||
await getDashboardForecastsByDashboardId({
|
await getDashboardQuestionsByDashboardId({
|
||||||
dashboardId,
|
dashboardId,
|
||||||
basePath: reqToBasePath(context.req), // required on server side to find the API endpoint
|
basePath: reqToBasePath(context.req), // required on server side to find the API endpoint
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
dashboardForecasts,
|
dashboardQuestions,
|
||||||
dashboardItem,
|
dashboardItem,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -78,7 +78,7 @@ const DashboardMetadata: React.FC<{ dashboardItem: DashboardItem }> = ({
|
||||||
|
|
||||||
/* Body */
|
/* Body */
|
||||||
const ViewDashboardPage: NextPage<Props> = ({
|
const ViewDashboardPage: NextPage<Props> = ({
|
||||||
dashboardForecasts,
|
dashboardQuestions,
|
||||||
dashboardItem,
|
dashboardItem,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
|
@ -91,9 +91,9 @@ const ViewDashboardPage: NextPage<Props> = ({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
<DisplayForecasts
|
<DisplayQuestions
|
||||||
results={dashboardForecasts}
|
results={dashboardQuestions}
|
||||||
numDisplay={dashboardForecasts.length}
|
numDisplay={dashboardQuestions.length}
|
||||||
showIdToggle={false}
|
showIdToggle={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { displayForecastsWrapperForSearch } from "../web/display/displayForecastsWrappers";
|
import { displayQuestionsWrapperForSearch } from "../web/display/displayQuestionsWrappers";
|
||||||
import { Layout } from "../web/display/Layout";
|
import { Layout } from "../web/display/Layout";
|
||||||
import { Props } from "../web/search/anySearchPage";
|
import { Props } from "../web/search/anySearchPage";
|
||||||
import CommonDisplay from "../web/search/CommonDisplay";
|
import CommonDisplay from "../web/search/CommonDisplay";
|
||||||
|
@ -18,7 +18,7 @@ const IndexPage: NextPage<Props> = (props) => {
|
||||||
hasAdvancedOptions={true}
|
hasAdvancedOptions={true}
|
||||||
placeholder={"Find forecasts about..."}
|
placeholder={"Find forecasts about..."}
|
||||||
displaySeeMoreHint={true}
|
displaySeeMoreHint={true}
|
||||||
displayForecastsWrapper={displayForecastsWrapperForSearch}
|
displayQuestionsWrapper={displayQuestionsWrapperForSearch}
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,12 +4,12 @@ import { GetServerSideProps, NextPage } from "next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { platforms } from "../backend/platforms";
|
import { platforms } from "../backend/platforms";
|
||||||
import { DisplayForecast } from "../web/display/DisplayForecast";
|
import { DisplayQuestion } from "../web/display/DisplayQuestion";
|
||||||
import { FrontendForecast } from "../web/platforms";
|
import { FrontendQuestion } from "../web/platforms";
|
||||||
import searchAccordingToQueryData from "../web/worker/searchAccordingToQueryData";
|
import searchAccordingToQueryData from "../web/worker/searchAccordingToQueryData";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
results: FrontendForecast[];
|
results: FrontendQuestion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps<Props> = async (
|
export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
|
@ -25,7 +25,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
...urlQuery,
|
...urlQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
let results: FrontendForecast[] = [];
|
let results: FrontendQuestion[] = [];
|
||||||
if (initialQueryParameters.query != "") {
|
if (initialQueryParameters.query != "") {
|
||||||
results = await searchAccordingToQueryData(initialQueryParameters, 1);
|
results = await searchAccordingToQueryData(initialQueryParameters, 1);
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ const SecretEmbedPage: NextPage<Props> = ({ results }) => {
|
||||||
<div>
|
<div>
|
||||||
<div id="secretEmbed">
|
<div id="secretEmbed">
|
||||||
{result ? (
|
{result ? (
|
||||||
<DisplayForecast
|
<DisplayQuestion
|
||||||
forecast={result}
|
question={result}
|
||||||
showTimeStamp={true}
|
showTimeStamp={true}
|
||||||
expandFooterToFullWidth={true}
|
expandFooterToFullWidth={true}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { FrontendForecast } from "../platforms";
|
|
||||||
import { DisplayForecast } from "./DisplayForecast";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
results: FrontendForecast[];
|
|
||||||
numDisplay: number;
|
|
||||||
showIdToggle: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DisplayForecasts: React.FC<Props> = ({
|
|
||||||
results,
|
|
||||||
numDisplay,
|
|
||||||
showIdToggle,
|
|
||||||
}) => {
|
|
||||||
if (!results) {
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{results.slice(0, numDisplay).map((result) => (
|
|
||||||
/*let displayWithMetaculusCapture =
|
|
||||||
fuseSearchResult.item.platform == "Metaculus"
|
|
||||||
? metaculusEmbed(fuseSearchResult.item)
|
|
||||||
: displayForecast({ ...fuseSearchResult.item });
|
|
||||||
*/
|
|
||||||
<DisplayForecast
|
|
||||||
key={result.id}
|
|
||||||
forecast={result}
|
|
||||||
showTimeStamp={false}
|
|
||||||
expandFooterToFullWidth={false}
|
|
||||||
showIdToggle={showIdToggle}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -2,16 +2,16 @@ import domtoimage from "dom-to-image"; // https://github.com/tsayen/dom-to-image
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { CopyToClipboard } from "react-copy-to-clipboard";
|
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||||
|
|
||||||
import { FrontendForecast } from "../platforms";
|
import { FrontendQuestion } from "../platforms";
|
||||||
import { uploadToImgur } from "../worker/uploadToImgur";
|
import { uploadToImgur } from "../worker/uploadToImgur";
|
||||||
import { DisplayForecast } from "./DisplayForecast";
|
import { DisplayQuestion } from "./DisplayQuestion";
|
||||||
|
|
||||||
function displayOneForecastInner(result: FrontendForecast, containerRef) {
|
function displayOneQuestionInner(result: FrontendQuestion, containerRef) {
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef}>
|
<div ref={containerRef}>
|
||||||
{result ? (
|
{result ? (
|
||||||
<DisplayForecast
|
<DisplayQuestion
|
||||||
forecast={result}
|
question={result}
|
||||||
showTimeStamp={true}
|
showTimeStamp={true}
|
||||||
expandFooterToFullWidth={true}
|
expandFooterToFullWidth={true}
|
||||||
/>
|
/>
|
||||||
|
@ -168,10 +168,10 @@ let generateMetaculusSource = (result, hasDisplayBeenCaptured) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
result: FrontendForecast;
|
result: FrontendQuestion;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DisplayOneForecastForCapture: React.FC<Props> = ({ result }) => {
|
export const DisplayOneQuestionForCapture: React.FC<Props> = ({ result }) => {
|
||||||
const [hasDisplayBeenCaptured, setHasDisplayBeenCaptured] = useState(false);
|
const [hasDisplayBeenCaptured, setHasDisplayBeenCaptured] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -226,7 +226,7 @@ export const DisplayOneForecastForCapture: React.FC<Props> = ({ result }) => {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-center">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-center">
|
||||||
<div className="flex col-span-1 items-center justify-center">
|
<div className="flex col-span-1 items-center justify-center">
|
||||||
{displayOneForecastInner(result, containerRef)}
|
{displayOneQuestionInner(result, containerRef)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex col-span-1 items-center justify-center">
|
<div className="flex col-span-1 items-center justify-center">
|
||||||
{generateCaptureButton(result, onCaptureButtonClick)}
|
{generateCaptureButton(result, onCaptureButtonClick)}
|
|
@ -243,7 +243,7 @@ interface Props {
|
||||||
expandFooterToFullWidth: boolean;
|
expandFooterToFullWidth: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ForecastFooter: React.FC<Props> = ({
|
export const QuestionFooter: React.FC<Props> = ({
|
||||||
stars,
|
stars,
|
||||||
platform,
|
platform,
|
||||||
platformLabel,
|
platformLabel,
|
|
@ -1,9 +1,9 @@
|
||||||
import { FaRegClipboard } from "react-icons/fa";
|
import { FaRegClipboard } from "react-icons/fa";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
import { FrontendForecast } from "../../platforms";
|
import { FrontendQuestion } from "../../platforms";
|
||||||
import { Card } from "../Card";
|
import { Card } from "../Card";
|
||||||
import { ForecastFooter } from "./ForecastFooter";
|
import { QuestionFooter } from "./QuestionFooter";
|
||||||
|
|
||||||
const truncateText = (length: number, text: string): string => {
|
const truncateText = (length: number, text: string): string => {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
|
@ -268,14 +268,14 @@ const LastUpdated: React.FC<{ timestamp: string }> = ({ timestamp }) => (
|
||||||
// Main component
|
// Main component
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
forecast: FrontendForecast;
|
question: FrontendQuestion;
|
||||||
showTimeStamp: boolean;
|
showTimeStamp: boolean;
|
||||||
expandFooterToFullWidth: boolean;
|
expandFooterToFullWidth: boolean;
|
||||||
showIdToggle?: boolean;
|
showIdToggle?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DisplayForecast: React.FC<Props> = ({
|
export const DisplayQuestion: React.FC<Props> = ({
|
||||||
forecast: {
|
question: {
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
url,
|
url,
|
||||||
|
@ -372,7 +372,7 @@ export const DisplayForecast: React.FC<Props> = ({
|
||||||
<LastUpdated timestamp={timestamp} />
|
<LastUpdated timestamp={timestamp} />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<ForecastFooter
|
<QuestionFooter
|
||||||
stars={qualityindicators.stars}
|
stars={qualityindicators.stars}
|
||||||
platform={platform}
|
platform={platform}
|
||||||
platformLabel={platformLabel || platform} // author || platformLabel,
|
platformLabel={platformLabel || platform} // author || platformLabel,
|
33
src/web/display/DisplayQuestions.tsx
Normal file
33
src/web/display/DisplayQuestions.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { FrontendQuestion } from "../platforms";
|
||||||
|
import { DisplayQuestion } from "./DisplayQuestion";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
results: FrontendQuestion[];
|
||||||
|
numDisplay: number;
|
||||||
|
showIdToggle: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DisplayQuestions: React.FC<Props> = ({
|
||||||
|
results,
|
||||||
|
numDisplay,
|
||||||
|
showIdToggle,
|
||||||
|
}) => {
|
||||||
|
if (!results) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{results.slice(0, numDisplay).map((result) => (
|
||||||
|
<DisplayQuestion
|
||||||
|
key={result.id}
|
||||||
|
question={result}
|
||||||
|
showTimeStamp={false}
|
||||||
|
expandFooterToFullWidth={false}
|
||||||
|
showIdToggle={showIdToggle}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,14 +1,14 @@
|
||||||
import { DisplayForecasts } from "./DisplayForecasts";
|
import { DisplayOneQuestionForCapture } from "./DisplayOneQuestionForCapture";
|
||||||
import { DisplayOneForecastForCapture } from "./DisplayOneForecastForCapture";
|
import { DisplayQuestions } from "./DisplayQuestions";
|
||||||
|
|
||||||
export function displayForecastsWrapperForSearch({
|
export function displayQuestionsWrapperForSearch({
|
||||||
results,
|
results,
|
||||||
numDisplay,
|
numDisplay,
|
||||||
showIdToggle,
|
showIdToggle,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
<DisplayForecasts
|
<DisplayQuestions
|
||||||
results={results || []}
|
results={results || []}
|
||||||
numDisplay={numDisplay}
|
numDisplay={numDisplay}
|
||||||
showIdToggle={showIdToggle}
|
showIdToggle={showIdToggle}
|
||||||
|
@ -17,13 +17,13 @@ export function displayForecastsWrapperForSearch({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function displayForecastsWrapperForCapture({
|
export function displayQuestionsWrapperForCapture({
|
||||||
results,
|
results,
|
||||||
whichResultToDisplayAndCapture,
|
whichResultToDisplayAndCapture,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 w-full justify-center">
|
<div className="grid grid-cols-1 w-full justify-center">
|
||||||
<DisplayOneForecastForCapture
|
<DisplayOneQuestionForCapture
|
||||||
result={results[whichResultToDisplayAndCapture]}
|
result={results[whichResultToDisplayAndCapture]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
|
@ -1,20 +1,20 @@
|
||||||
import { Forecast, PlatformConfig } from "../backend/platforms";
|
import { PlatformConfig, Question } from "../backend/platforms";
|
||||||
|
|
||||||
export type FrontendForecast = Forecast & {
|
export type FrontendQuestion = Question & {
|
||||||
platformLabel: string;
|
platformLabel: string;
|
||||||
visualization?: any;
|
visualization?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ok on client side
|
// ok on client side
|
||||||
export const addLabelsToForecasts = (
|
export const addLabelsToQuestions = (
|
||||||
forecasts: Forecast[],
|
questions: Question[],
|
||||||
platformsConfig: PlatformConfig[]
|
platformsConfig: PlatformConfig[]
|
||||||
): FrontendForecast[] => {
|
): FrontendQuestion[] => {
|
||||||
const platformNameToLabel = Object.fromEntries(
|
const platformNameToLabel = Object.fromEntries(
|
||||||
platformsConfig.map((platform) => [platform.name, platform.label])
|
platformsConfig.map((platform) => [platform.name, platform.label])
|
||||||
);
|
);
|
||||||
|
|
||||||
return forecasts.map((result) => ({
|
return questions.map((result) => ({
|
||||||
...result,
|
...result,
|
||||||
platformLabel: platformNameToLabel[result.platform] || result.platform,
|
platformLabel: platformNameToLabel[result.platform] || result.platform,
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { MultiSelectPlatform } from "../display/MultiSelectPlatform";
|
||||||
import { QueryForm } from "../display/QueryForm";
|
import { QueryForm } from "../display/QueryForm";
|
||||||
import { SliderElement } from "../display/SliderElement";
|
import { SliderElement } from "../display/SliderElement";
|
||||||
import { useNoInitialEffect } from "../hooks";
|
import { useNoInitialEffect } from "../hooks";
|
||||||
import { FrontendForecast } from "../platforms";
|
import { FrontendQuestion } from "../platforms";
|
||||||
import searchAccordingToQueryData from "../worker/searchAccordingToQueryData";
|
import searchAccordingToQueryData from "../worker/searchAccordingToQueryData";
|
||||||
import { Props as AnySearchPageProps, QueryParameters } from "./anySearchPage";
|
import { Props as AnySearchPageProps, QueryParameters } from "./anySearchPage";
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ interface Props extends AnySearchPageProps {
|
||||||
hasAdvancedOptions: boolean;
|
hasAdvancedOptions: boolean;
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
displaySeeMoreHint: boolean;
|
displaySeeMoreHint: boolean;
|
||||||
displayForecastsWrapper: (opts: {
|
displayQuestionsWrapper: (opts: {
|
||||||
results: FrontendForecast[];
|
results: FrontendQuestion[];
|
||||||
numDisplay: number;
|
numDisplay: number;
|
||||||
whichResultToDisplayAndCapture: number;
|
whichResultToDisplayAndCapture: number;
|
||||||
showIdToggle: boolean;
|
showIdToggle: boolean;
|
||||||
|
@ -38,7 +38,7 @@ const CommonDisplay: React.FC<Props> = ({
|
||||||
hasAdvancedOptions,
|
hasAdvancedOptions,
|
||||||
placeholder,
|
placeholder,
|
||||||
displaySeeMoreHint,
|
displaySeeMoreHint,
|
||||||
displayForecastsWrapper,
|
displayQuestionsWrapper,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
/* States */
|
/* States */
|
||||||
|
@ -68,7 +68,7 @@ const CommonDisplay: React.FC<Props> = ({
|
||||||
|
|
||||||
const filterManually = (
|
const filterManually = (
|
||||||
queryData: QueryParameters,
|
queryData: QueryParameters,
|
||||||
results: FrontendForecast[]
|
results: FrontendQuestion[]
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
queryData.forecastingPlatforms &&
|
queryData.forecastingPlatforms &&
|
||||||
|
@ -99,13 +99,13 @@ const CommonDisplay: React.FC<Props> = ({
|
||||||
setResults(results);
|
setResults(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
// I don't want the function which display forecasts (displayForecasts) to change with a change in queryParameters. But I want it to have access to the queryParameters, and in particular access to queryParameters.numDisplay. Hence why this function lives inside Home.
|
// I don't want the component which display questions (DisplayQuestions) to change with a change in queryParameters. But I want it to have access to the queryParameters, and in particular access to queryParameters.numDisplay. Hence why this function lives inside Home.
|
||||||
const getInfoToDisplayForecastsFunction = () => {
|
const getInfoToDisplayQuestionsFunction = () => {
|
||||||
const numDisplayRounded =
|
const numDisplayRounded =
|
||||||
numDisplay % 3 != 0
|
numDisplay % 3 != 0
|
||||||
? numDisplay + (3 - (Math.round(numDisplay) % 3))
|
? numDisplay + (3 - (Math.round(numDisplay) % 3))
|
||||||
: numDisplay;
|
: numDisplay;
|
||||||
return displayForecastsWrapper({
|
return displayQuestionsWrapper({
|
||||||
results,
|
results,
|
||||||
numDisplay: numDisplayRounded,
|
numDisplay: numDisplayRounded,
|
||||||
whichResultToDisplayAndCapture,
|
whichResultToDisplayAndCapture,
|
||||||
|
@ -307,7 +307,7 @@ const CommonDisplay: React.FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div>{getInfoToDisplayForecastsFunction()}</div>
|
<div>{getInfoToDisplayQuestionsFunction()}</div>
|
||||||
|
|
||||||
{displaySeeMoreHint &&
|
{displaySeeMoreHint &&
|
||||||
(!results || (results.length != 0 && numDisplay < results.length)) ? (
|
(!results || (results.length != 0 && numDisplay < results.length)) ? (
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { GetServerSideProps } from "next";
|
||||||
|
|
||||||
import { getFrontpage } from "../../backend/frontpage";
|
import { getFrontpage } from "../../backend/frontpage";
|
||||||
import { getPlatformsConfig, PlatformConfig, platforms } from "../../backend/platforms";
|
import { getPlatformsConfig, PlatformConfig, platforms } from "../../backend/platforms";
|
||||||
import { addLabelsToForecasts, FrontendForecast } from "../platforms";
|
import { addLabelsToQuestions, FrontendQuestion } from "../platforms";
|
||||||
import searchAccordingToQueryData from "../worker/searchAccordingToQueryData";
|
import searchAccordingToQueryData from "../worker/searchAccordingToQueryData";
|
||||||
|
|
||||||
/* Common code for / and /capture */
|
/* Common code for / and /capture */
|
||||||
|
@ -15,8 +15,8 @@ export interface QueryParameters {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
defaultResults: FrontendForecast[];
|
defaultResults: FrontendQuestion[];
|
||||||
initialResults: FrontendForecast[];
|
initialResults: FrontendQuestion[];
|
||||||
initialQueryParameters: QueryParameters;
|
initialQueryParameters: QueryParameters;
|
||||||
defaultQueryParameters: QueryParameters;
|
defaultQueryParameters: QueryParameters;
|
||||||
initialNumDisplay: number;
|
initialNumDisplay: number;
|
||||||
|
@ -61,7 +61,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
const defaultNumDisplay = 21;
|
const defaultNumDisplay = 21;
|
||||||
const initialNumDisplay = Number(urlQuery.numDisplay) || defaultNumDisplay;
|
const initialNumDisplay = Number(urlQuery.numDisplay) || defaultNumDisplay;
|
||||||
|
|
||||||
const defaultResults = addLabelsToForecasts(
|
const defaultResults = addLabelsToQuestions(
|
||||||
await getFrontpage(),
|
await getFrontpage(),
|
||||||
platformsConfig
|
platformsConfig
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { DashboardItem } from "../../backend/dashboards";
|
import { DashboardItem } from "../../backend/dashboards";
|
||||||
import { Forecast, getPlatformsConfig } from "../../backend/platforms";
|
import { getPlatformsConfig, Question } from "../../backend/platforms";
|
||||||
import { addLabelsToForecasts, FrontendForecast } from "../platforms";
|
import { addLabelsToQuestions, FrontendQuestion } from "../platforms";
|
||||||
|
|
||||||
export async function getDashboardForecastsByDashboardId({
|
export async function getDashboardQuestionsByDashboardId({
|
||||||
dashboardId,
|
dashboardId,
|
||||||
basePath,
|
basePath,
|
||||||
}: {
|
}: {
|
||||||
dashboardId: string;
|
dashboardId: string;
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
dashboardForecasts: FrontendForecast[];
|
dashboardQuestions: FrontendQuestion[];
|
||||||
dashboardItem: DashboardItem;
|
dashboardItem: DashboardItem;
|
||||||
}> {
|
}> {
|
||||||
console.log("getDashboardForecastsByDashboardId: ");
|
console.log("getDashboardQuestionsByDashboardId: ");
|
||||||
if (typeof window === undefined && !basePath) {
|
if (typeof window === undefined && !basePath) {
|
||||||
throw new Error("`basePath` option is required on server side");
|
throw new Error("`basePath` option is required on server side");
|
||||||
}
|
}
|
||||||
|
|
||||||
let dashboardForecasts: Forecast[] = [];
|
let dashboardQuestions: Question[] = [];
|
||||||
let dashboardItem: DashboardItem | null = null;
|
let dashboardItem: DashboardItem | null = null;
|
||||||
try {
|
try {
|
||||||
let { data } = await axios({
|
let { data } = await axios({
|
||||||
|
@ -31,18 +31,18 @@ export async function getDashboardForecastsByDashboardId({
|
||||||
});
|
});
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
dashboardForecasts = data.dashboardContents;
|
dashboardQuestions = data.dashboardContents;
|
||||||
dashboardItem = data.dashboardItem as DashboardItem;
|
dashboardItem = data.dashboardItem as DashboardItem;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
const labeledDashboardForecasts = addLabelsToForecasts(
|
const labeledDashboardQuestions = addLabelsToQuestions(
|
||||||
dashboardForecasts,
|
dashboardQuestions,
|
||||||
getPlatformsConfig({ withGuesstimate: false })
|
getPlatformsConfig({ withGuesstimate: false })
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dashboardForecasts: labeledDashboardForecasts,
|
dashboardQuestions: labeledDashboardQuestions,
|
||||||
dashboardItem,
|
dashboardItem,
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { FrontendForecast } from "../platforms";
|
import { FrontendQuestion } from "../platforms";
|
||||||
import { QueryParameters } from "../search/anySearchPage";
|
import { QueryParameters } from "../search/anySearchPage";
|
||||||
import searchGuesstimate from "./searchGuesstimate";
|
import searchGuesstimate from "./searchGuesstimate";
|
||||||
import searchWithAlgolia from "./searchWithAlgolia";
|
import searchWithAlgolia from "./searchWithAlgolia";
|
||||||
|
@ -6,8 +6,8 @@ import searchWithAlgolia from "./searchWithAlgolia";
|
||||||
export default async function searchAccordingToQueryData(
|
export default async function searchAccordingToQueryData(
|
||||||
queryData: QueryParameters,
|
queryData: QueryParameters,
|
||||||
limit: number
|
limit: number
|
||||||
): Promise<FrontendForecast[]> {
|
): Promise<FrontendQuestion[]> {
|
||||||
let results: FrontendForecast[] = [];
|
let results: FrontendQuestion[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// defs
|
// defs
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Imports */
|
/* Imports */
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { FrontendForecast } from "../platforms";
|
import { FrontendQuestion } from "../platforms";
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
let urlEndPoint =
|
let urlEndPoint =
|
||||||
|
@ -11,7 +11,7 @@ let urlEndPoint =
|
||||||
|
|
||||||
export default async function searchGuesstimate(
|
export default async function searchGuesstimate(
|
||||||
query
|
query
|
||||||
): Promise<FrontendForecast[]> {
|
): Promise<FrontendQuestion[]> {
|
||||||
let response = await axios({
|
let response = await axios({
|
||||||
url: urlEndPoint,
|
url: urlEndPoint,
|
||||||
// credentials: "omit",
|
// credentials: "omit",
|
||||||
|
@ -31,7 +31,7 @@ export default async function searchGuesstimate(
|
||||||
});
|
});
|
||||||
|
|
||||||
const models: any[] = response.data.hits;
|
const models: any[] = response.data.hits;
|
||||||
const mappedModels: FrontendForecast[] = models.map((model, index) => {
|
const mappedModels: FrontendQuestion[] = models.map((model, index) => {
|
||||||
let description = model.description
|
let description = model.description
|
||||||
? model.description.replace(/\n/g, " ").replace(/ /g, " ")
|
? model.description.replace(/\n/g, " ").replace(/ /g, " ")
|
||||||
: "";
|
: "";
|
||||||
|
@ -57,7 +57,7 @@ export default async function searchGuesstimate(
|
||||||
|
|
||||||
// filter for duplicates. Surprisingly common.
|
// filter for duplicates. Surprisingly common.
|
||||||
let uniqueTitles = [];
|
let uniqueTitles = [];
|
||||||
let uniqueModels: FrontendForecast[] = [];
|
let uniqueModels: FrontendQuestion[] = [];
|
||||||
for (let model of mappedModels) {
|
for (let model of mappedModels) {
|
||||||
if (!uniqueTitles.includes(model.title) && !model.title.includes("copy")) {
|
if (!uniqueTitles.includes(model.title) && !model.title.includes("copy")) {
|
||||||
uniqueModels.push(model);
|
uniqueModels.push(model);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import algoliasearch from "algoliasearch";
|
import algoliasearch from "algoliasearch";
|
||||||
|
|
||||||
import { FrontendForecast } from "../platforms";
|
import { FrontendQuestion } from "../platforms";
|
||||||
|
|
||||||
const client = algoliasearch(
|
const client = algoliasearch(
|
||||||
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
|
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
|
||||||
|
@ -82,8 +82,8 @@ export default async function searchWithAlgolia({
|
||||||
starsThreshold,
|
starsThreshold,
|
||||||
filterByPlatforms,
|
filterByPlatforms,
|
||||||
forecastsThreshold,
|
forecastsThreshold,
|
||||||
}): Promise<FrontendForecast[]> {
|
}): Promise<FrontendQuestion[]> {
|
||||||
let response = await index.search<FrontendForecast>(queryString, {
|
let response = await index.search<FrontendQuestion>(queryString, {
|
||||||
hitsPerPage,
|
hitsPerPage,
|
||||||
filters: buildFilter({
|
filters: buildFilter({
|
||||||
starsThreshold,
|
starsThreshold,
|
||||||
|
@ -93,7 +93,7 @@ export default async function searchWithAlgolia({
|
||||||
//facetFilters: buildFacetFilter({filterByPlatforms}),
|
//facetFilters: buildFacetFilter({filterByPlatforms}),
|
||||||
getRankingInfo: true,
|
getRankingInfo: true,
|
||||||
});
|
});
|
||||||
let results: FrontendForecast[] = response.hits;
|
let results: FrontendQuestion[] = response.hits;
|
||||||
|
|
||||||
let recursionError = ["metaforecast", "metaforecasts", "metaforecasting"];
|
let recursionError = ["metaforecast", "metaforecasts", "metaforecasting"];
|
||||||
if (
|
if (
|
||||||
|
|
Loading…
Reference in New Issue
Block a user