diff --git a/frontend/__tests__/utils/url-handler.spec.ts b/frontend/__tests__/controllers/url-handler.spec.ts similarity index 99% rename from frontend/__tests__/utils/url-handler.spec.ts rename to frontend/__tests__/controllers/url-handler.spec.ts index 0c77df0da9c2..b6bf72d5bcb6 100644 --- a/frontend/__tests__/utils/url-handler.spec.ts +++ b/frontend/__tests__/controllers/url-handler.spec.ts @@ -6,9 +6,9 @@ import * as Notifications from "../../src/ts/stores/notifications"; import * as TestLogic from "../../src/ts/test/test-logic"; import * as TestState from "../../src/ts/test/test-state"; import * as Misc from "../../src/ts/utils/misc"; -import { loadTestSettingsFromUrl } from "../../src/ts/utils/url-handler"; import { FunboxName } from "@monkeytype/schemas/configs"; import { CustomTextSettings } from "@monkeytype/schemas/results"; +import { loadTestSettingsFromUrl } from "../../src/ts/controllers/url-handler"; //mock modules to avoid dependencies vi.mock("../../src/ts/test/test-logic", () => ({ diff --git a/frontend/__tests__/root/config.spec.ts b/frontend/__tests__/root/config.spec.ts index d946db05dd33..f6e0c46126ba 100644 --- a/frontend/__tests__/root/config.spec.ts +++ b/frontend/__tests__/root/config.spec.ts @@ -1,6 +1,7 @@ import { describe, it, expect, beforeEach, afterAll, vi } from "vitest"; import * as Config from "../../src/ts/config"; import * as Misc from "../../src/ts/utils/misc"; +import * as Env from "../../src/ts/utils/env"; import { ConfigKey, Config as ConfigType, @@ -14,7 +15,7 @@ import * as Notifications from "../../src/ts/stores/notifications"; const { replaceConfig, getConfig } = Config.__testing; describe("Config", () => { - const isDevEnvironmentMock = vi.spyOn(Misc, "isDevEnvironment"); + const isDevEnvironmentMock = vi.spyOn(Env, "isDevEnvironment"); beforeEach(() => { isDevEnvironmentMock.mockClear(); replaceConfig({}); diff --git a/frontend/__tests__/utils/misc.spec.ts b/frontend/__tests__/utils/misc.spec.ts index 669371c46147..84f6c10d258a 100644 --- a/frontend/__tests__/utils/misc.spec.ts +++ b/frontend/__tests__/utils/misc.spec.ts @@ -1,6 +1,5 @@ import { describe, it, expect, vi } from "vitest"; import { - getErrorMessage, isObject, escapeHTML, promiseWithResolvers, @@ -10,6 +9,7 @@ import { removeLanguageSize, } from "../../src/ts/utils/strings"; import { Language } from "@monkeytype/schemas/languages"; +import { getErrorMessage } from "../../src/ts/utils/error"; describe("misc.ts", () => { describe("getLanguageDisplayString", () => { diff --git a/frontend/package.json b/frontend/package.json index d1362797941c..7bd5c4ea1bef 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -48,7 +48,7 @@ "chart.js": "3.7.1", "chartjs-adapter-date-fns": "3.0.0", "chartjs-plugin-annotation": "2.2.1", - "chartjs-plugin-trendline": "1.0.2", + "chartjs-plugin-trendline": "3.2.0", "clsx": "2.1.1", "color-blend": "4.0.0", "damerau-levenshtein": "1.0.8", diff --git a/frontend/scripts/import-tree.ts b/frontend/scripts/import-tree.ts index bfced5702b35..6ad90054044e 100644 --- a/frontend/scripts/import-tree.ts +++ b/frontend/scripts/import-tree.ts @@ -282,3 +282,57 @@ for (const entry of entryPoints) { printTree(entry, new Set([entry]), "", true, true); if (entryPoints.length > 1) console.log(); } + +// --- Summary --- + +let totalDirect = 0; +let totalTransitive = 0; +const uniqueDirect = new Set(); +const uniqueTransitive = new Set(); +let maxDirect = 0; +let maxDirectFile = ""; +let maxTransitive = 0; +let maxTransitiveFile = ""; +let maxDepthSeen = 0; +let maxDepthFile = ""; + +for (const entry of entryPoints) { + const info = cache.get(entry); + if (!info) continue; + totalDirect += info.directImports.length; + totalTransitive += info.totalReachable; + for (const dep of info.directImports) { + uniqueDirect.add(dep); + } + for (const dep of getAllReachable(entry, new Set())) { + uniqueTransitive.add(dep); + } + if (info.directImports.length > maxDirect) { + maxDirect = info.directImports.length; + maxDirectFile = entry; + } + if (info.totalReachable > maxTransitive) { + maxTransitive = info.totalReachable; + maxTransitiveFile = entry; + } + if (info.maxDepth > maxDepthSeen) { + maxDepthSeen = info.maxDepth; + maxDepthFile = entry; + } +} + +console.log(`${c.dim}───────────────────────────${c.reset}`); +console.log(`Target: ${c.bold}${displayPath(resolved)}${c.reset}`); +console.log(`Total direct: ${c.bold}${totalDirect}${c.reset}`); +console.log(`Total transitive: ${c.bold}${totalTransitive}${c.reset}`); +console.log(`Unique direct: ${c.bold}${uniqueDirect.size}${c.reset}`); +console.log(`Unique transitive: ${c.bold}${uniqueTransitive.size}${c.reset}`); +console.log( + `Max direct: ${c.bold}${maxDirect}${c.reset} ${c.dim}(${displayPath(maxDirectFile)})${c.reset}`, +); +console.log( + `Max transitive: ${c.bold}${maxTransitive}${c.reset} ${c.dim}(${displayPath(maxTransitiveFile)})${c.reset}`, +); +console.log( + `Max depth: ${c.bold}${maxDepthSeen}${c.reset} ${c.dim}(${displayPath(maxDepthFile)})${c.reset}`, +); diff --git a/frontend/src/html/pages/test-result.html b/frontend/src/html/pages/test-result.html index f40f5a3a80f8..469f6617104c 100644 --- a/frontend/src/html/pages/test-result.html +++ b/frontend/src/html/pages/test-result.html @@ -107,7 +107,6 @@ class="textButton hidden" aria-label="Report quote" data-balloon-pos="up" - style="display: inline-block" > @@ -116,7 +115,6 @@ class="textButton hidden" aria-label="Favorite quote" data-balloon-pos="up" - style="display: inline-block" > diff --git a/frontend/src/ts/auth.tsx b/frontend/src/ts/auth.tsx index ccc5faedc6bd..e0dcd87ee26f 100644 --- a/frontend/src/ts/auth.tsx +++ b/frontend/src/ts/auth.tsx @@ -32,7 +32,7 @@ import { showErrorNotification, showSuccessNotification, } from "./stores/notifications"; -import { createErrorMessage } from "./utils/misc"; +import { createErrorMessage } from "./utils/error"; export const gmailProvider = new GoogleAuthProvider(); export const githubProvider = new GithubAuthProvider(); diff --git a/frontend/src/ts/commandline/commandline-metadata.ts b/frontend/src/ts/commandline/commandline-metadata.ts index fe3cfa710276..da716eb100ae 100644 --- a/frontend/src/ts/commandline/commandline-metadata.ts +++ b/frontend/src/ts/commandline/commandline-metadata.ts @@ -8,12 +8,12 @@ import * as ManualRestart from "../test/manual-restart-tracker"; import { areUnsortedArraysEqual } from "../utils/arrays"; import Config from "../config"; import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; -import { Validation } from "../elements/input-validation"; import { getActivePage } from "../signals/core"; import { Fonts } from "../constants/fonts"; import { KnownFontName } from "@monkeytype/schemas/fonts"; import * as UI from "../ui"; import { typedKeys } from "../utils/misc"; +import { Validation } from "../types/validation"; type ConfigKeysWithoutCommands = | "minWpmCustomSpeed" diff --git a/frontend/src/ts/commandline/commandline.ts b/frontend/src/ts/commandline/commandline.ts index 224c1999e5b0..75b94fb1f316 100644 --- a/frontend/src/ts/commandline/commandline.ts +++ b/frontend/src/ts/commandline/commandline.ts @@ -18,10 +18,7 @@ import { areSortedArraysEqual, areUnsortedArraysEqual } from "../utils/arrays"; import { parseIntOptional } from "../utils/numbers"; import { debounce } from "throttle-debounce"; import { intersect } from "@monkeytype/util/arrays"; -import { - createInputEventHandler, - ValidationResult, -} from "../elements/input-validation"; +import { createInputEventHandler } from "../elements/input-validation"; import { isInputElementFocused } from "../input/input-element"; import { qs } from "../utils/dom"; import { ConfigKey } from "@monkeytype/schemas/configs"; @@ -32,6 +29,7 @@ import { hideModalAndClearChain as storeClearChain, isModalOpen, } from "../stores/modals"; +import { ValidationResult } from "../types/validation"; type CommandlineMode = "search" | "input"; type InputModeParams = { @@ -125,7 +123,7 @@ export function show( if (exists) { showLoaderBar(); subgroupOverride = await CommandlineLists.getList( - overrideStringOrGroup, + overrideStringOrGroup as CommandlineLists.ListsObjectKeys, ); hideLoaderBar(); } else { diff --git a/frontend/src/ts/commandline/lists.ts b/frontend/src/ts/commandline/lists.ts index c4ebc260c5fc..6466518c6765 100644 --- a/frontend/src/ts/commandline/lists.ts +++ b/frontend/src/ts/commandline/lists.ts @@ -17,7 +17,7 @@ import LoadChallengeCommands, { } from "./lists/load-challenge"; import Config, { applyConfigFromJson, setConfig } from "../config"; -import * as Misc from "../utils/misc"; +import * as getErrorMessage from "../utils/error"; import * as JSONData from "../utils/json-data"; import { randomizeTheme } from "../controllers/theme-controller"; import * as CustomTextPopup from "../modals/custom-text"; @@ -47,7 +47,10 @@ challengesPromise }) .catch((e: unknown) => { console.error( - Misc.createErrorMessage(e, "Failed to update challenges commands"), + getErrorMessage.createErrorMessage( + e, + "Failed to update challenges commands", + ), ); }); diff --git a/frontend/src/ts/commandline/lists/themes.ts b/frontend/src/ts/commandline/lists/themes.ts index 8bafb873677c..ec4d4d296008 100644 --- a/frontend/src/ts/commandline/lists/themes.ts +++ b/frontend/src/ts/commandline/lists/themes.ts @@ -5,7 +5,7 @@ import { Command, CommandsSubgroup } from "../types"; import { ThemesList, ThemeWithName } from "../../constants/themes"; import { not } from "@monkeytype/util/predicates"; import * as ConfigEvent from "../../observables/config-event"; -import * as Misc from "../../utils/misc"; +import * as getErrorMessage from "../../utils/error"; const isFavorite = (theme: ThemeWithName): boolean => Config.favThemes.includes(theme.name); @@ -83,7 +83,10 @@ ConfigEvent.subscribe(({ key }) => { update(ThemesList); } catch (e: unknown) { console.error( - Misc.createErrorMessage(e, "Failed to update themes commands"), + getErrorMessage.createErrorMessage( + e, + "Failed to update themes commands", + ), ); } } diff --git a/frontend/src/ts/commandline/types.ts b/frontend/src/ts/commandline/types.ts index 0a96eac36ce2..8fd01a9741a1 100644 --- a/frontend/src/ts/commandline/types.ts +++ b/frontend/src/ts/commandline/types.ts @@ -1,6 +1,6 @@ import { Config } from "@monkeytype/schemas/configs"; import AnimatedModal from "../utils/animated-modal"; -import { Validation } from "../elements/input-validation"; +import { Validation } from "../types/validation"; // this file is needed becauase otherwise it would produce a circular dependency diff --git a/frontend/src/ts/components/common/AsyncContent.tsx b/frontend/src/ts/components/common/AsyncContent.tsx index fcc50d0d756e..49da2e478ce7 100644 --- a/frontend/src/ts/components/common/AsyncContent.tsx +++ b/frontend/src/ts/components/common/AsyncContent.tsx @@ -10,7 +10,8 @@ import { } from "solid-js"; import { showErrorNotification } from "../../stores/notifications"; -import { createErrorMessage, typedKeys } from "../../utils/misc"; +import { createErrorMessage } from "../../utils/error"; +import { typedKeys } from "../../utils/misc"; import { Conditional } from "./Conditional"; import { LoadingCircle } from "./LoadingCircle"; diff --git a/frontend/src/ts/components/common/ChartJs.tsx b/frontend/src/ts/components/common/ChartJs.tsx index 3cdf5bdf2a06..966fd0134459 100644 --- a/frontend/src/ts/components/common/ChartJs.tsx +++ b/frontend/src/ts/components/common/ChartJs.tsx @@ -1,17 +1,20 @@ import { + CartesianScaleOptions, Chart, ChartData, ChartOptions, ChartType, DefaultDataPoint, + ScaleChartOptions, } from "chart.js"; +import chartTrendline from "chartjs-plugin-trendline"; import { createEffect, JSXElement, onCleanup, onMount } from "solid-js"; -import { ChartWithUpdateColors } from "../../controllers/chart-controller"; -import { createDebouncedEffectOn } from "../../hooks/effects"; +import { Theme } from "../../constants/themes"; import { useRefWithUtils } from "../../hooks/useRefWithUtils"; import { getTheme } from "../../signals/theme"; +Chart.register(chartTrendline); type ChartJSProps< T extends ChartType = ChartType, TData = DefaultDataPoint, @@ -28,15 +31,15 @@ export function ChartJs>( // Refs are assigned by SolidJS via the ref attribute const [canvasRef, canvasEl] = useRefWithUtils(); - let chart: ChartWithUpdateColors | undefined; + let chart: Chart | undefined; onMount(() => { const canvas = canvasEl(); if (canvas === undefined) return; - chart = new ChartWithUpdateColors(canvas.native, { + chart = new Chart(canvas.native, { type: props.type, data: props.data, - options: props.options, + options: addColorsToOptions(props.options as ChartOptions, getTheme), }); props.onChartInit?.(chart); @@ -48,20 +51,41 @@ export function ChartJs>( chart.config.type = props.type; chart.data = props.data; if (props.options) { - chart.options = props.options; + chart.options = addColorsToOptions(props.options, getTheme); } chart.update(); }); - createDebouncedEffectOn( - 125, - getTheme, - (theme) => void chart?.updateColors(theme), - ); - onCleanup(() => { chart?.destroy(); }); return ; } + +function addColorsToOptions( + options: ChartOptions, + theme: () => Theme, +): ChartOptions { + //axis colors + const chartScaleOptions = options as ScaleChartOptions; + Object.keys(chartScaleOptions.scales).forEach((scaleID) => { + const axis = chartScaleOptions.scales[scaleID] as CartesianScaleOptions; + axis.ticks = { + ...axis.ticks, + color: theme().sub, + }; + axis.title = { + ...axis.title, + color: theme().sub, + }; + axis.grid = { + ...axis.grid, + color: theme().subAlt, + tickColor: theme().subAlt, + borderColor: theme().subAlt, + }; + }); + + return options; +} diff --git a/frontend/src/ts/components/core/FavIcon.tsx b/frontend/src/ts/components/core/FavIcon.tsx index 69f061836b05..2c8392b9bf6f 100644 --- a/frontend/src/ts/components/core/FavIcon.tsx +++ b/frontend/src/ts/components/core/FavIcon.tsx @@ -2,7 +2,7 @@ import { Link } from "@solidjs/meta"; import { createMemo, JSXElement } from "solid-js"; import { Theme } from "../../constants/themes"; -import { isDevEnvironment } from "../../utils/misc"; +import { isDevEnvironment } from "../../utils/env"; export function FavIcon(props: { theme: Theme }): JSXElement { const icon = createMemo(() => { diff --git a/frontend/src/ts/components/layout/footer/ThemeIndicator.tsx b/frontend/src/ts/components/layout/footer/ThemeIndicator.tsx index 84ea93946ec0..ae2c81abffeb 100644 --- a/frontend/src/ts/components/layout/footer/ThemeIndicator.tsx +++ b/frontend/src/ts/components/layout/footer/ThemeIndicator.tsx @@ -1,9 +1,12 @@ import { JSXElement, Show } from "solid-js"; -import * as Commandline from "../../../commandline/commandline"; import Config, { setConfig } from "../../../config"; import { isAuthenticated } from "../../../firebase"; -import { getThemeIndicator } from "../../../signals/core"; +import { + getThemeIndicator, + setCommandlineSubgroup, +} from "../../../signals/core"; +import { showModal } from "../../../stores/modals"; import { showNoticeNotification } from "../../../stores/notifications"; import { getSnapshot } from "../../../stores/snapshot"; import { Fa } from "../../common/Fa"; @@ -23,9 +26,8 @@ export function ThemeIndicator(): JSXElement { setConfig("customTheme", true); } else { const subgroup = Config.customTheme ? "customTheme" : "themes"; - Commandline.show({ - subgroupOverride: subgroup, - }); + setCommandlineSubgroup(subgroup); + showModal("Commandline"); } }; diff --git a/frontend/src/ts/components/layout/footer/VersionButton.tsx b/frontend/src/ts/components/layout/footer/VersionButton.tsx index f8d4aeded4c4..58cabe9a6256 100644 --- a/frontend/src/ts/components/layout/footer/VersionButton.tsx +++ b/frontend/src/ts/components/layout/footer/VersionButton.tsx @@ -5,7 +5,7 @@ import { envConfig } from "virtual:env-config"; import { lastSeenServerCompatibility } from "../../../ape/adapters/ts-rest-adapter"; import { getVersion } from "../../../signals/core"; import { showModal } from "../../../stores/modals"; -import { isDevEnvironment } from "../../../utils/misc"; +import { isDevEnvironment } from "../../../utils/env"; import { Fa } from "../../common/Fa"; export function VersionButton(): JSXElement { diff --git a/frontend/src/ts/components/layout/header/Logo.tsx b/frontend/src/ts/components/layout/header/Logo.tsx index f8a7c106443b..f5af622a9425 100644 --- a/frontend/src/ts/components/layout/header/Logo.tsx +++ b/frontend/src/ts/components/layout/header/Logo.tsx @@ -1,9 +1,12 @@ import { JSXElement } from "solid-js"; -import { getActivePage, getFocus } from "../../../signals/core"; -import { restart } from "../../../test/test-logic"; +import { + dispatchRestartTest, + getActivePage, + getFocus, +} from "../../../signals/core"; import { cn } from "../../../utils/cn"; -import { isDevEnvironment } from "../../../utils/misc"; +import { isDevEnvironment } from "../../../utils/env"; export function Logo(): JSXElement { return ( @@ -18,7 +21,7 @@ export function Logo(): JSXElement { }} data-ui-element="logo" onClick={() => { - if (getActivePage() === "test") restart(); + if (getActivePage() === "test") dispatchRestartTest(); }} > { - if (getActivePage() === "test") restart(); + if (getActivePage() === "test") dispatchRestartTest(); }} />