Compare commits

...

1 Commits

Author SHA1 Message Date
Zephyr Lykos
178664ed83
refactor: migrate toolchain, part 1
- Switched to pnpm
- Updated to typescript 4.9.5
- JSX transforms switched to react-jsx
- Use swc for typescript transforms
- Remove deprecated dependencies
- Cleanup unused types
- Some ESM fixes
- PostCSS config now lives in package.json
- Bump support target

TODO:
- switch to vite or plain esbuild
- jest to vitest / uvu
- jquery to cash-dom
- pure ESM (lodash-es, etc.)
- drop prettier & husky (lint-staged is okay)
- drop wasm cli & xterm.js
- update bootstrap
2023-07-10 19:58:18 +08:00
119 changed files with 11873 additions and 10148 deletions

View File

@ -21,7 +21,7 @@ WORKDIR /app
COPY package.json yarn.lock ./ COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile RUN yarn install --frozen-lockfile
COPY postcss.config.js tsconfig.build.json tsconfig.json webpack.config.ts ./ COPY tsconfig.build.json tsconfig.json webpack.config.ts ./
COPY tools/*Plugin.ts ./tools/ COPY tools/*Plugin.ts ./tools/
COPY resources ./resources COPY resources ./resources

View File

@ -6,6 +6,7 @@
"type": "git", "type": "git",
"url": "https://github.com/bs-community/blessing-skin-server" "url": "https://github.com/bs-community/blessing-skin-server"
}, },
"type": "module",
"author": "printempw", "author": "printempw",
"license": "MIT", "license": "MIT",
"private": true, "private": true,
@ -21,92 +22,86 @@
"prepare": "husky install" "prepare": "husky install"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.0.0", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.0.0", "@emotion/styled": "^11.11.0",
"@fortawesome/fontawesome-free": "^6.3.0", "@fortawesome/fontawesome-free": "^6.4.0",
"@hot-loader/react-dom": "^17.0.0", "@hot-loader/react-dom": "^17.0.2",
"@tweenjs/tween.js": "^18.5.0", "@tweenjs/tween.js": "^21.0.0",
"admin-lte": "^3.2.0", "admin-lte": "^3.2.0",
"blessing-skin-shell": "^0.3.4", "blessing-skin-shell": "^0.3.4",
"bootstrap": "^4.6.1", "bootstrap": "^4.6.2",
"cac": "6.6.1", "cac": "6.7.14",
"cli-spinners": "^2.5.0", "cli-spinners": "^2.9.0",
"clsx": "^1.1.1", "clsx": "^1.2.1",
"echarts": "^5.1.2", "echarts": "^5.4.2",
"events": "^3.2.0", "immer": "^10.0.2",
"immer": "^7.0.4", "jquery": "^3.7.0",
"jquery": "^3.6.0",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"nanoid": "^3.1.9", "nanoid": "^4.0.2",
"prompts": "^2.4.0", "prompts": "^2.4.2",
"react": "^17.0.1", "react": "^17.0.2",
"react-autosuggest": "^10.0.2", "react-autosuggest": "^10.1.0",
"react-dom": "^17.0.1", "react-dom": "^17.0.2",
"react-draggable": "^4.4.2", "react-draggable": "^4.4.5",
"react-hot-loader": "^4.12.21", "react-hot-loader": "^4.13.1",
"react-loading-skeleton": "^2.1.1", "react-loading-skeleton": "^3.3.1",
"react-use": "^17.4.0", "react-use": "^17.4.0",
"reaptcha": "^1.7.2", "reaptcha": "^1.12.1",
"rxjs": "^6.5.5", "rxjs": "^7.8.1",
"skinview-utils": "^0.5.5", "skinview-utils": "^0.7.0",
"skinview3d": "^3.0.0-alpha.1", "skinview3d": "3.0.0-alpha.1",
"spectre.css": "^0.5.8", "spectre.css": "^0.5.9",
"use-immer": "^0.4.2", "use-immer": "^0.9.0",
"xterm": "^4.6.0", "xterm": "^5.2.1",
"xterm-addon-fit": "^0.4.0" "xterm-addon-fit": "^0.7.0"
}, },
"devDependencies": { "devDependencies": {
"@gplane/tsconfig": "^4.2.0", "@gplane/tsconfig": "^5.0.0",
"@testing-library/jest-dom": "^5.11.10", "@swc/register": "^0.1.10",
"@testing-library/react": "^11.2.6", "@testing-library/jest-dom": "^5.16.5",
"@types/bootstrap": "^4.3.3", "@testing-library/react": "^12.1.5",
"@types/css-minimizer-webpack-plugin": "^1.1.0", "@types/bootstrap": "^5.2.6",
"@types/jest": "^26.0.23", "@types/jest": "^29.5.2",
"@types/jquery": "^3.5.13", "@types/jquery": "^3.5.16",
"@types/js-yaml": "^3.12.4", "@types/js-yaml": "^4.0.5",
"@types/lodash.debounce": "^4.0.6", "@types/lodash.debounce": "^4.0.7",
"@types/mini-css-extract-plugin": "^1.2.1", "@types/prompts": "^2.4.4",
"@types/prompts": "^2.0.9", "@types/react": "17",
"@types/react": "^16.9.35", "@types/react-autosuggest": "^10.1.6",
"@types/react-autosuggest": "^9.3.14", "@types/react-dom": "^17.0.20",
"@types/react-dom": "^16.9.8", "@types/testing-library__jest-dom": "^5.14.7",
"@types/tween.js": "^18.5.0", "@typescript-eslint/eslint-plugin": "^5.61.0",
"@types/webpack-dev-server": "^3.11.0", "@typescript-eslint/parser": "^5.61.0",
"@typescript-eslint/eslint-plugin": "^3.6.0", "autoprefixer": "^10.4.14",
"@typescript-eslint/parser": "^3.6.0", "css-loader": "^6.8.1",
"autoprefixer": "^10.2.6", "css-minimizer-webpack-plugin": "^5.0.1",
"css-loader": "^5.2.6", "eslint": "^8.44.0",
"css-minimizer-webpack-plugin": "^3.0.1",
"eslint": "^7.4.0",
"eslint-formatter-beauty": "^3.0.0", "eslint-formatter-beauty": "^3.0.0",
"eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-react-hooks": "^4.6.0",
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.5.3",
"husky": "^7.0.4", "husky": "^8.0.3",
"jest": "^27.0.4", "jest": "^29.6.1",
"jest-extended": "^0.11.5", "jest-environment-jsdom": "^29.6.1",
"js-yaml": "^3.13.1", "jest-extended": "^4.0.0",
"mini-css-extract-plugin": "^1.6.0", "js-yaml": "^4.1.0",
"postcss": "^8.3.0", "mini-css-extract-plugin": "^2.7.6",
"postcss-loader": "^5.3.0", "postcss": "^8.4.25",
"prettier": "^2.3.0", "postcss-loader": "^7.3.3",
"prettier": "^2.8.8",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"style-loader": "^2.0.0", "style-loader": "^3.3.3",
"ts-jest": "^27.0.2", "ts-jest": "^29.1.1",
"ts-loader": "^9.2.2", "ts-loader": "^9.4.4",
"ts-node": "^10.0.0", "typescript": "^4.9.5",
"typescript": "^4.3.2", "webpack": "^5.88.1",
"webpack": "^5.38.1", "webpack-cli": "^5.1.4",
"webpack-cli": "^4.7.0", "webpack-dev-server": "^4.15.1"
"webpack-dev-server": "^3.11.2"
},
"resolutions": {
"kleur": "^4.1.3"
}, },
"browserslist": [ "browserslist": [
"> 1%", "Chrome >= 87",
"not dead", "Firefox >= 84",
"not ie 11", "iOS >= 12.5",
"Chrome > 52" "not dead"
], ],
"prettier": { "prettier": {
"printWidth": 80, "printWidth": 80,
@ -115,17 +110,13 @@
"trailingComma": "all", "trailingComma": "all",
"tabWidth": 2 "tabWidth": 2
}, },
"postcss": {
"autoprefixer": {}
},
"jest": { "jest": {
"preset": "ts-jest", "preset": "ts-jest",
"resetMocks": true, "resetMocks": true,
"testEnvironment": "jsdom", "testEnvironment": "jsdom",
"moduleFileExtensions": [
"js",
"ts",
"tsx",
"json",
"node"
],
"moduleNameMapper": { "moduleNameMapper": {
"\\.css$": "<rootDir>/resources/assets/tests/__mocks__/style.ts", "\\.css$": "<rootDir>/resources/assets/tests/__mocks__/style.ts",
"\\.(png|webp)$": "<rootDir>/resources/assets/tests/__mocks__/file.ts", "\\.(png|webp)$": "<rootDir>/resources/assets/tests/__mocks__/file.ts",

11664
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
module.exports = {
plugins: [
require('autoprefixer'),
],
}

View File

@ -1,5 +1,3 @@
import React from 'react'
type AlertType = 'success' | 'info' | 'warning' | 'danger' type AlertType = 'success' | 'info' | 'warning' | 'danger'
const icons = new Map<AlertType, string>([ const icons = new Map<AlertType, string>([

View File

@ -1,5 +1,3 @@
import React from 'react'
interface Props { interface Props {
title?: string title?: string
onClick: React.MouseEventHandler<HTMLAnchorElement> onClick: React.MouseEventHandler<HTMLAnchorElement>

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
interface Props { interface Props {

View File

@ -1,5 +1,5 @@
/** @jsxImportSource @emotion/react */ /** @jsxImportSource @emotion/react */
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import Autosuggest from 'react-autosuggest' import Autosuggest from 'react-autosuggest'
import { css } from '@emotion/react' import { css } from '@emotion/react'
import { emit } from '@/scripts/event' import { emit } from '@/scripts/event'

View File

@ -1,5 +1,3 @@
import React from 'react'
const Loading = () => ( const Loading = () => (
<div className="container text-center" title="Loading..."> <div className="container text-center" title="Loading...">
<i className="fas fa-sync fa-spin"></i> <i className="fas fa-sync fa-spin"></i>

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import $ from 'jquery' import $ from 'jquery'
import 'bootstrap' import 'bootstrap'
import { t } from '../scripts/i18n' import { t } from '../scripts/i18n'
@ -66,9 +66,14 @@ const Modal: React.FC<ModalOptions & Props> = (props) => {
return return
} }
const onHidden = () => props.onClose?.() const onClose =
props.onClose ||
(() => {
/* noop */
})
const onHidden = () => onClose()
const el = $(ref.current!) const el = $(ref.current as HTMLElement)
el.on('hidden.bs.modal', onHidden) el.on('hidden.bs.modal', onHidden)
return () => { return () => {
@ -92,28 +97,27 @@ const Modal: React.FC<ModalOptions & Props> = (props) => {
} }
props.onConfirm?.({ value }) props.onConfirm?.({ value })
$(ref.current!).modal('hide') $(ref.current as HTMLElement).modal('hide')
// The "hidden.bs.modal" event can't be trigged automatically when testing. // The "hidden.bs.modal" event can't be trigged automatically when testing.
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
$(ref.current!).trigger('hidden.bs.modal') $(ref.current as HTMLElement).trigger('hidden.bs.modal')
} }
} }
const dismiss = () => { const dismiss = () => {
props.onDismiss?.() props.onDismiss?.()
$(ref.current!).modal('hide') $(ref.current as HTMLElement).modal('hide')
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
$(ref.current!).trigger('hidden.bs.modal') $(ref.current as HTMLElement).trigger('hidden.bs.modal')
} }
} }
useEffect(() => { useEffect(() => {
if (show) { if (show) {
setTimeout(() => $(ref.current!).modal('show'), 50) setTimeout(() => $(ref.current as HTMLElement).modal('show'), 50)
} }
}, [show]) }, [show])

View File

@ -1,4 +1,3 @@
import React from 'react'
import ModalContent from './ModalContent' import ModalContent from './ModalContent'
import ModalInput from './ModalInput' import ModalInput from './ModalInput'
import type { Props as ContentProps } from './ModalContent' import type { Props as ContentProps } from './ModalContent'

View File

@ -1,5 +1,3 @@
import React from 'react'
export interface Props { export interface Props {
text?: string text?: string
dangerousHTML?: string dangerousHTML?: string

View File

@ -1,5 +1,3 @@
import React from 'react'
export interface Props { export interface Props {
flexFooter?: boolean flexFooter?: boolean
okButtonText?: string okButtonText?: string

View File

@ -1,5 +1,3 @@
import React from 'react'
export interface Props { export interface Props {
title?: string title?: string
} }

View File

@ -1,4 +1,4 @@
import React, { HTMLAttributes } from 'react' import type { HTMLAttributes } from 'react'
export interface Props { export interface Props {
inputType?: string inputType?: string

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import PaginationItem from './PaginationItem' import PaginationItem from './PaginationItem'

View File

@ -1,5 +1,3 @@
import React from 'react'
interface Props { interface Props {
disabled?: boolean disabled?: boolean
active?: boolean active?: boolean

View File

@ -1,5 +1,5 @@
/** @jsxImportSource @emotion/react */ /** @jsxImportSource @emotion/react */
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { css } from '@emotion/react' import { css } from '@emotion/react'
export type ToastType = 'success' | 'info' | 'warning' | 'error' export type ToastType = 'success' | 'info' | 'warning' | 'error'

View File

@ -1,5 +1,5 @@
/** @jsxImportSource @emotion/react */ /** @jsxImportSource @emotion/react */
import React, { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import { useMeasure } from 'react-use' import { useMeasure } from 'react-use'
import { css } from '@emotion/react' import { css } from '@emotion/react'
import styled from '@emotion/styled' import styled from '@emotion/styled'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
const ViewerSkeleton: React.FC = () => ( const ViewerSkeleton: React.FC = () => (

View File

@ -30,8 +30,7 @@ if (route) {
</React.Suspense> </React.Suspense>
</React.StrictMode> </React.StrictMode>
) )
const c = const c = document.querySelector(route.el)
typeof route.el === 'string' ? document.querySelector(route.el) : route.el
ReactDOM.render(<Root />, c) ReactDOM.render(<Root />, c)
} }
} }

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { Terminal } from 'xterm' import { Terminal } from 'xterm'
@ -57,10 +57,8 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
const terminal = new Terminal() const terminal = new Terminal()
const fitAddon = new FitAddon() const fitAddon = new FitAddon()
terminal.loadAddon(fitAddon) terminal.loadAddon(fitAddon)
terminal.setOption( terminal.options.fontFamily =
'fontFamily', 'Monaco, Consolas, "Roboto Mono", "Noto Sans", "Droid Sans Mono"'
'Monaco, Consolas, "Roboto Mono", "Noto Sans", "Droid Sans Mono"',
)
terminal.open(el) terminal.open(el)
fitAddon.fit() fitAddon.fit()
@ -83,6 +81,7 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
if (stack?.includes('outputHelp')) { if (stack?.includes('outputHelp')) {
terminal.writeln(data.replace(/\n/g, '\r\n')) terminal.writeln(data.replace(/\n/g, '\r\n'))
} else { } else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
originalLogger(data, ...args) originalLogger(data, ...args)
} }
} }

View File

@ -22,7 +22,7 @@ export default async function pacman(stdio: Stdio, args: string[]) {
const { options } = program.parse(['', ''].concat(args), { run: false }) const { options } = program.parse(['', ''].concat(args), { run: false })
const opts: Options = options const opts: Options = options
/* istanbul ignore else */
if (opts.sync) { if (opts.sync) {
await install(opts.sync, stdio) await install(opts.sync, stdio)
} else if (opts.remove) { } else if (opts.remove) {

View File

@ -1,7 +1,6 @@
import type { Stdio } from 'blessing-skin-shell' import type { Stdio } from 'blessing-skin-shell'
import * as event from '../event' import * as event from '../event'
/* istanbul ignore next */
export function hackStdin() { export function hackStdin() {
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
return process.stdin return process.stdin
@ -24,7 +23,6 @@ export function hackStdin() {
} as NodeJS.ReadStream & { _off(): void } } as NodeJS.ReadStream & { _off(): void }
} }
/* istanbul ignore next */
export function hackStdout(stdio: Stdio) { export function hackStdout(stdio: Stdio) {
return { return {
write(msg: string) { write(msg: string) {

View File

@ -1,4 +1,3 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom' import * as ReactDOM from 'react-dom'
import DarkModeButton from '@/components/DarkModeButton' import DarkModeButton from '@/components/DarkModeButton'

View File

@ -1,4 +1,3 @@
import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import EmailVerification from '@/views/widgets/EmailVerification' import EmailVerification from '@/views/widgets/EmailVerification'

View File

@ -1,6 +1,6 @@
export function getExtraData(): Record<string, any> { export function getExtraData(): Record<string, any> {
const jsonElement = document.querySelector('#blessing-extra') const jsonElement = document.querySelector('#blessing-extra')
/* istanbul ignore next */
if (jsonElement) { if (jsonElement) {
return JSON.parse(jsonElement.textContent ?? '{}') return JSON.parse(jsonElement.textContent ?? '{}')
} else { } else {

View File

@ -2,7 +2,7 @@ import { getExtraData } from './extra'
export function scrollHander() { export function scrollHander() {
const header = document.querySelector('.navbar') const header = document.querySelector('.navbar')
/* istanbul ignore else */
if (header) { if (header) {
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
if (window.scrollY >= (window.innerHeight * 2) / 3) { if (window.scrollY >= (window.innerHeight * 2) / 3) {
@ -14,7 +14,6 @@ export function scrollHander() {
} }
} }
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') { if (process.env.NODE_ENV !== 'test') {
const { transparent_navbar } = getExtraData() as { const { transparent_navbar } = getExtraData() as {
transparent_navbar: boolean transparent_navbar: boolean

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import * as fetch from '../net' import * as fetch from '../net'
import { Texture, TextureType } from '../types' import { type Texture, TextureType } from '../types'
export default function useTexture() { export default function useTexture() {
const [tid, setTid] = useState(0) const [tid, setTid] = useState(0)

View File

@ -8,7 +8,6 @@ export function t(key: string, parameters = Object.create(null)): string {
let result = '' let result = ''
for (const segment of segments) { for (const segment of segments) {
/* istanbul ignore next */
const middle = temp?.[segment] const middle = temp?.[segment]
if (!middle) { if (!middle) {
return key return key
@ -20,9 +19,11 @@ export function t(key: string, parameters = Object.create(null)): string {
} }
} }
/* eslint-disable @typescript-eslint/no-unsafe-argument */
Object.keys(parameters).forEach( Object.keys(parameters).forEach(
(slot) => (result = result.replace(`:${slot}`, parameters[slot])), (slot) => (result = result.replace(`:${slot}`, parameters[slot])),
) )
/* eslint-enable @typescript-eslint/no-unsafe-argument */
return result return result
} }

View File

@ -18,5 +18,5 @@ export async function logout() {
} }
const button = document.querySelector('#logout-button') const button = document.querySelector('#logout-button')
/* istanbul ignore next */
button?.addEventListener('click', logout) button?.addEventListener('click', logout)

View File

@ -1,6 +1,5 @@
import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import Modal, { ModalOptions, ModalResult } from '../components/Modal' import Modal, { type ModalOptions, type ModalResult } from '../components/Modal'
export function showModal(options: ModalOptions = {}): Promise<ModalResult> { export function showModal(options: ModalOptions = {}): Promise<ModalResult> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -80,7 +80,7 @@ export async function walkFetch(request: Request): Promise<any> {
message = `${message}<br><details>${trace}</details>` message = `${message}<br><details>${trace}</details>`
} }
throw new HTTPError(message || body, cloned) throw new HTTPError(message || (body as string), cloned)
} catch (error: any) { } catch (error: any) {
emit('fetchError', error) emit('fetchError', error)
await showModal({ await showModal({
@ -95,7 +95,10 @@ export async function walkFetch(request: Request): Promise<any> {
} }
} }
export function get<T = any>(url: string, params = empty): Promise<T> { export function get<T = any>(
url: string,
params: Record<string, any> = empty,
): Promise<T> {
emit('beforeFetch', { emit('beforeFetch', {
method: 'GET', method: 'GET',
url, url,

View File

@ -1,4 +1,3 @@
import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import NotificationsList from '@/views/widgets/NotificationsList' import NotificationsList from '@/views/widgets/NotificationsList'

View File

@ -3,7 +3,6 @@ import { Toast } from './toast'
export const toast = new Toast() export const toast = new Toast()
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
afterEach(() => { afterEach(() => {
toast.clear() toast.clear()

View File

@ -1,5 +1,3 @@
import React from 'react'
export default [ export default [
{ {
path: 'user', path: 'user',

View File

@ -1,6 +1,5 @@
import { loadSkinToCanvas } from 'skinview-utils' import { loadSkinToCanvas } from 'skinview-utils'
/* istanbul ignore next */
function checkPixel( function checkPixel(
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
x: number, x: number,
@ -15,7 +14,6 @@ function checkPixel(
) )
} }
/* istanbul ignore next */
export function isAlex(texture: string): Promise<boolean> { export function isAlex(texture: string): Promise<boolean> {
return new Promise((resolve) => { return new Promise((resolve) => {
const image = new Image() const image = new Image()

View File

@ -1,8 +1,9 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import * as emitter from './event' import * as emitter from './event'
import ToastBox, { ToastType } from '../components/Toast' import ToastBox from '../components/Toast'
import type { ToastType } from '../components/Toast'
type QueueElement = { id: string; type: ToastType; message: string } type QueueElement = { id: string; type: ToastType; message: string }
type ToastQueue = QueueElement[] type ToastQueue = QueueElement[]

View File

@ -38,9 +38,13 @@ export function registerNavbarPicker(
const navbar = document.querySelector<HTMLElement>('.wrapper > nav') const navbar = document.querySelector<HTMLElement>('.wrapper > nav')
const picker = document.querySelector<HTMLDivElement>('#navbar-color-picker') const picker = document.querySelector<HTMLDivElement>('#navbar-color-picker')
/* istanbul ignore next */
if (navbar && picker) { if (navbar && picker) {
registerNavbarPicker(navbar, picker, blessing.extra.navbar || 'white') registerNavbarPicker(
navbar,
picker,
(blessing.extra.navbar as string) || 'white',
)
} }
export function registerSidebarPicker( export function registerSidebarPicker(
@ -73,11 +77,10 @@ const darkPicker = document.querySelector<HTMLDivElement>(
const lightPicker = document.querySelector<HTMLDivElement>( const lightPicker = document.querySelector<HTMLDivElement>(
'#sidebar-light-picker', '#sidebar-light-picker',
) )
/* istanbul ignore next */
if (sidebar && darkPicker && lightPicker) { if (sidebar && darkPicker && lightPicker) {
registerSidebarPicker( registerSidebarPicker(
sidebar, sidebar,
{ dark: darkPicker, light: lightPicker }, { dark: darkPicker, light: lightPicker },
blessing.extra.sidebar || 'dark-primary', (blessing.extra.sidebar as string) || 'dark-primary',
) )
} }

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import { showModal } from '@/scripts/notify' import { showModal } from '@/scripts/notify'
import type { Player } from '@/scripts/types' import type { Player } from '@/scripts/types'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton' import Skeleton from 'react-loading-skeleton'
import { Box } from './styles' import { Box } from './styles'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton' import Skeleton from 'react-loading-skeleton'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import { TextureType } from '@/scripts/types' import { TextureType } from '@/scripts/types'
import Modal from '@/components/Modal' import Modal from '@/components/Modal'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { Player } from '@/scripts/types' import type { Player } from '@/scripts/types'
import ButtonEdit from '@/components/ButtonEdit' import ButtonEdit from '@/components/ButtonEdit'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useLayoutEffect } from 'react' import { useState, useEffect, useLayoutEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer' import { useImmer } from 'use-immer'
import useIsLargeScreen from '@/scripts/hooks/useIsLargeScreen' import useIsLargeScreen from '@/scripts/hooks/useIsLargeScreen'
@ -47,6 +47,7 @@ const PlayersManagement: React.FC = () => {
useEffect(() => { useEffect(() => {
getPlayers() getPlayers()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [page]) }, [page])
const handleModeChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleModeChange = (event: React.ChangeEvent<HTMLInputElement>) => {

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { Plugin } from './types' import type { Plugin } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer' import { useImmer } from 'use-immer'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { Plugin } from './types' import type { Plugin } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useMemo } from 'react' import { useState, useEffect, useMemo } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import { enableMapSet } from 'immer' import { enableMapSet } from 'immer'
import { useImmer } from 'use-immer' import { useImmer } from 'use-immer'

View File

@ -1,8 +1,7 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { Texture } from '@/scripts/types' import type { Texture } from '@/scripts/types'
import { Report, Status } from './types' import { type Report, Status } from './types'
const Card = styled.div` const Card = styled.div`
width: 240px; width: 240px;

View File

@ -3,7 +3,7 @@ import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer' import { useImmer } from 'use-immer'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { Paginator, Texture, TextureType } from '@/scripts/types' import { type Paginator, type Texture, TextureType } from '@/scripts/types'
import { toast, showModal } from '@/scripts/notify' import { toast, showModal } from '@/scripts/notify'
import Loading from '@/components/Loading' import Loading from '@/components/Loading'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
@ -37,6 +37,7 @@ const ReportsManagement: React.FC = () => {
useEffect(() => { useEffect(() => {
getReports() getReports()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [page]) }, [page])
const handleQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled' import styled from '@emotion/styled'
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { Line } from './types' import type { Line } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer' import { useImmer } from 'use-immer'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,4 @@
import { post, ResponseBody } from '../../scripts/net' import { post, type ResponseBody } from '../../scripts/net'
import { showModal } from '../../scripts/notify' import { showModal } from '../../scripts/notify'
import { t } from '../../scripts/i18n' import { t } from '../../scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { User } from '@/scripts/types' import type { User } from '@/scripts/types'
import { Box, Icon, InfoTable } from './styles' import { Box, Icon, InfoTable } from './styles'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton' import Skeleton from 'react-loading-skeleton'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton' import Skeleton from 'react-loading-skeleton'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { User } from '@/scripts/types' import type { User } from '@/scripts/types'
import ButtonEdit from '@/components/ButtonEdit' import ButtonEdit from '@/components/ButtonEdit'

View File

@ -1,11 +1,11 @@
import React, { useState, useEffect, useLayoutEffect } from 'react' import { useState, useEffect, useLayoutEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer' import { useImmer } from 'use-immer'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra' import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useIsLargeScreen from '@/scripts/hooks/useIsLargeScreen' import useIsLargeScreen from '@/scripts/hooks/useIsLargeScreen'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { User, UserPermission, Paginator } from '@/scripts/types' import { type User, UserPermission, type Paginator } from '@/scripts/types'
import { toast, showModal } from '@/scripts/notify' import { toast, showModal } from '@/scripts/notify'
import urls from '@/scripts/urls' import urls from '@/scripts/urls'
import type { Props as ModalInputProps } from '@/components/ModalInput' import type { Props as ModalInputProps } from '@/components/ModalInput'

View File

@ -1,5 +1,5 @@
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import { User, UserPermission } from '@/scripts/types' import { type User, UserPermission } from '@/scripts/types'
export function humanizePermission(permission: UserPermission): string { export function humanizePermission(permission: UserPermission): string {
switch (permission) { switch (permission) {

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react' import { useState, useRef } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from 'react' import { useState, useRef, useEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra' import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react' import { useState, useRef } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra' import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,5 +1,3 @@
import React from 'react'
interface Props { interface Props {
active?: boolean active?: boolean
bg?: string bg?: string

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import { TextureType } from '@/scripts/types' import { TextureType } from '@/scripts/types'
import Button from './Button' import Button from './Button'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as cssUtils from '@/styles/utils' import * as cssUtils from '@/styles/utils'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra' import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import type { ClosetItem as ClosetItemType } from '@/scripts/types' import type { ClosetItem as ClosetItemType } from '@/scripts/types'
import setAsAvatar from './setAsAvatar' import setAsAvatar from './setAsAvatar'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton' import Skeleton from 'react-loading-skeleton'
import { Card, DropdownButton } from './styles' import { Card, DropdownButton } from './styles'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import $ from 'jquery' import $ from 'jquery'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'
@ -6,9 +6,9 @@ import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { showModal, toast } from '@/scripts/notify' import { showModal, toast } from '@/scripts/notify'
import { import {
ClosetItem as Item, type ClosetItem as Item,
Texture, type Texture,
Paginator, type Paginator,
TextureType, TextureType,
} from '@/scripts/types' } from '@/scripts/types'
import urls from '@/scripts/urls' import urls from '@/scripts/urls'
@ -22,10 +22,8 @@ import removeClosetItem from './removeClosetItem'
type Category = 'skin' | 'cape' type Category = 'skin' | 'cape'
const updater = debounce( const updater = debounce(
<T extends unknown>( (value: React.SetStateAction<any>, setter: React.Dispatch<typeof value>) =>
value: React.SetStateAction<T>, setter(value),
setter: React.Dispatch<React.SetStateAction<T>>,
) => setter(value),
350, 350,
) )
@ -47,7 +45,7 @@ const Closet: React.FC = () => {
useEffect(() => { useEffect(() => {
const element = containerRef.current const element = containerRef.current
/* istanbul ignore next */
if (element) { if (element) {
const { width } = element.getBoundingClientRect() const { width } = element.getBoundingClientRect()
if (width >= 500) { if (width >= 500) {

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback } from 'react' import { useState, useEffect, useCallback } from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import Modal from '@/components/Modal' import Modal from '@/components/Modal'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import ButtonEdit from '@/components/ButtonEdit' import ButtonEdit from '@/components/ButtonEdit'
import type { App } from './types' import type { App } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton' import Skeleton from 'react-loading-skeleton'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { toast } from '@/scripts/notify' import { toast } from '@/scripts/notify'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import Modal from '@/components/Modal' import Modal from '@/components/Modal'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root' import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra' import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted' import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { toast } from '@/scripts/notify' import { toast } from '@/scripts/notify'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { showModal } from '@/scripts/notify' import { showModal } from '@/scripts/notify'

View File

@ -1,11 +1,3 @@
declare module '*.styl' {
export default {} as Record<string, string>
}
declare module '*.scss' {
export default {} as Record<string, string>
}
declare module '*.png' { declare module '*.png' {
export default '' export default ''
} }

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import type { ReaptchaProps } from 'reaptcha' import type ReaptchaProps from 'reaptcha'
class Reaptcha extends React.Component<ReaptchaProps, {}> { class Reaptcha extends React.Component<ReaptchaProps, {}> {
execute() { execute() {

View File

@ -15,7 +15,7 @@ describe('picture captcha', () => {
expect(await ref.current?.execute()).toBe('abc') expect(await ref.current?.execute()).toBe('abc')
}) })
it('refresh on click', async () => { it('refresh on click', () => {
const spy = jest.spyOn(Date, 'now') const spy = jest.spyOn(Date, 'now')
const ref = React.createRef<Captcha>() const ref = React.createRef<Captcha>()
@ -25,7 +25,7 @@ describe('picture captcha', () => {
expect(spy).toBeCalled() expect(spy).toBeCalled()
}) })
it('refresh programatically', async () => { it('refresh programatically', () => {
const spy = jest.spyOn(Date, 'now') const spy = jest.spyOn(Date, 'now')
const ref = React.createRef<Captcha>() const ref = React.createRef<Captcha>()
@ -53,7 +53,7 @@ describe('recaptcha', () => {
expect(value).toBe('token') expect(value).toBe('token')
}) })
it('refresh programatically', async () => { it('refresh programatically', () => {
const spy = jest.spyOn(Reaptcha.prototype, 'reset') const spy = jest.spyOn(Reaptcha.prototype, 'reset')
const ref = React.createRef<Captcha>() const ref = React.createRef<Captcha>()

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent, waitFor } from '@testing-library/react' import { render, fireEvent, waitFor } from '@testing-library/react'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import DarkModeButton from '@/components/DarkModeButton' import DarkModeButton from '@/components/DarkModeButton'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react' import { useState } from 'react'
import { render, fireEvent } from '@testing-library/react' import { render, fireEvent } from '@testing-library/react'
import { on } from '@/scripts/event' import { on } from '@/scripts/event'
import EmailSuggestion from '@/components/EmailSuggestion' import EmailSuggestion from '@/components/EmailSuggestion'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react' import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import FileInput from '@/components/FileInput' import FileInput from '@/components/FileInput'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent, act } from '@testing-library/react' import { render, fireEvent, act } from '@testing-library/react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import $ from 'jquery' import $ from 'jquery'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react' import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react' import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import Viewer, { PICTURES_COUNT } from '@/components/Viewer' import Viewer, { PICTURES_COUNT } from '@/components/Viewer'

View File

@ -1,16 +1,19 @@
/* eslint-disable max-classes-per-file */
import * as fs from 'fs' import * as fs from 'fs'
import 'jest-extended' import * as matchers from 'jest-extended'
import '@testing-library/jest-dom' import '@testing-library/jest-dom'
import yaml from 'js-yaml' import yaml from 'js-yaml'
expect.extend(matchers)
window.blessing = { window.blessing = {
base_url: '', base_url: '',
locale: 'en', locale: 'en',
site_name: 'Blessing Skin', site_name: 'Blessing Skin',
version: '4.0.0', version: '4.0.0',
extra: {}, extra: {},
i18n: yaml.load(fs.readFileSync('resources/lang/en/front-end.yml', 'utf8')), i18n: yaml.load(
fs.readFileSync('resources/lang/en/front-end.yml', 'utf8'),
) as object,
} }
class Headers extends Map { class Headers extends Map {

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/indent */
import type * as net from '../../src/scripts/net' import type * as net from '../../src/scripts/net'
export type { ResponseBody } from '../../src/scripts/net' export type { ResponseBody } from '../../src/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react' import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils' import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react' import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react' import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react' import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils' import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react' import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils' import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react' import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils' import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'

Some files were not shown because too many files have changed in this diff Show More