Change frontend deps
This commit is contained in:
parent
ec6c0cc45b
commit
5ade1c0593
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
src = ./frontend;
|
src = ./frontend;
|
||||||
|
|
||||||
npmDepsHash = "sha256-cN+xm9wBRcpDHuYy8PelV1YWhudw4y8B6Ap4+3En8/4=";
|
npmDepsHash = "sha256-4gjtxGquuFzk4AOnm0lZC5x7+pVAMrt6CeQvj1Cd8W8=";
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
|
7
frontend/jest.config.js
Normal file
7
frontend/jest.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/** @type {import('ts-jest').JestConfigWithTsJest} **/
|
||||||
|
module.exports = {
|
||||||
|
testEnvironment: "jsdom",
|
||||||
|
transform: {
|
||||||
|
"^.+\.tsx?$": ["ts-jest",{}],
|
||||||
|
},
|
||||||
|
};
|
4834
frontend/package-lock.json
generated
4834
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,27 +2,35 @@
|
|||||||
"name": "apiary-frontend",
|
"name": "apiary-frontend",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "parcel src/index.html",
|
"start": "parcel src/index.html",
|
||||||
"build": "parcel build src/index.html"
|
"build": "parcel build src/index.html",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ngneat/falso": "^7.3.0",
|
"@ngneat/falso": "^7.3.0",
|
||||||
|
"@testing-library/dom": "^10.4.0",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"@testing-library/react": "^16.2.0",
|
||||||
|
"@testing-library/user-event": "^14.6.1",
|
||||||
|
"@types/humanize-duration": "^3.27.4",
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
|
"@types/node": "^22.13.9",
|
||||||
|
"@types/react": "^19.0.10",
|
||||||
|
"@types/react-dom": "^19.0.4",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"parcel": "^2.13.3",
|
"parcel": "^2.13.3",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"svgo": "^3.3.2",
|
"svgo": "^3.3.2",
|
||||||
|
"ts-jest": "^29.2.6",
|
||||||
"ts-loader": "^9.5.2",
|
"ts-loader": "^9.5.2",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/humanize-duration": "^3.27.4",
|
|
||||||
"@types/node": "^22.13.9",
|
|
||||||
"@types/react": "^19.0.10",
|
|
||||||
"@types/react-dom": "^19.0.4",
|
|
||||||
"chart.js": "^4.4.8",
|
"chart.js": "^4.4.8",
|
||||||
"humanize-duration": "^3.32.1",
|
"humanize-duration": "^3.32.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-chartjs-2": "^5.3.0",
|
"react-chartjs-2": "^5.3.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-router": "^7.2.0",
|
"react-router": "^7.2.0"
|
||||||
"swr": "^2.3.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,9 @@ a {
|
|||||||
}
|
}
|
||||||
#menu-logo {
|
#menu-logo {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
content: url("../assets/apiary.svg");
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
}
|
}
|
||||||
.menu-link {
|
.menu-link {
|
||||||
color: var(--menu-color-text);
|
color: var(--menu-color-text);
|
||||||
|
@ -8,7 +8,6 @@ import { Pie } from "react-chartjs-2";
|
|||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
|
|
||||||
ChartJS.register(Tooltip, ArcElement, Legend);
|
ChartJS.register(Tooltip, ArcElement, Legend);
|
||||||
const logo = new URL("../assets/apiary.svg", import.meta.url)
|
|
||||||
|
|
||||||
interface AppProps {
|
interface AppProps {
|
||||||
api: ApiaryAPI
|
api: ApiaryAPI
|
||||||
@ -34,14 +33,13 @@ let chartColors = [
|
|||||||
"#d35400",
|
"#d35400",
|
||||||
"#c0392b",
|
"#c0392b",
|
||||||
"#bdc3c7",
|
"#bdc3c7",
|
||||||
"#7f8c8d"
|
"#7f8c8d",
|
||||||
]
|
]
|
||||||
|
|
||||||
export function App({ api }: AppProps) {
|
export function App({ api }: AppProps) {
|
||||||
const [mode, setMode] = useState("light");
|
const [mode, setMode] = useState("light");
|
||||||
const headerProps: HeaderMenuProps = {
|
const headerProps: HeaderMenuProps = {
|
||||||
title: "apiary.home.2rjus.net",
|
title: "apiary.home.2rjus.net",
|
||||||
logo: logo,
|
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
name: "Totals",
|
name: "Totals",
|
||||||
@ -90,7 +88,7 @@ export function App({ api }: AppProps) {
|
|||||||
<>
|
<>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<HeaderMenu title={headerProps.title} logo={logo} items={headerProps.items} />
|
<HeaderMenu title={headerProps.title} items={headerProps.items} />
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home api={api} />} />
|
<Route path="/" element={<Home api={api} />} />
|
||||||
@ -113,7 +111,7 @@ export interface StatsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Stats({ api, type }: StatsProps) {
|
export function Stats({ api, type }: StatsProps) {
|
||||||
const [stats, setStats] = useState<StatsResult[]|null>(null)
|
const [stats, setStats] = useState<StatsResult[] | null>(null)
|
||||||
const [currentType, setCurrentType] = useState(type)
|
const [currentType, setCurrentType] = useState(type)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -250,14 +248,14 @@ export function Live({ api }: AppProps) {
|
|||||||
|
|
||||||
export interface LiveListProps {
|
export interface LiveListProps {
|
||||||
list: LoginAttempt[]
|
list: LoginAttempt[]
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface DateTDProps {
|
export interface DateTDProps {
|
||||||
date: Date
|
date: Date
|
||||||
now: Date
|
now: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DateTD({ date, now}: DateTDProps) {
|
export function DateTD({ date, now }: DateTDProps) {
|
||||||
const [displayDate, setDisplayDate] = useState(date.toLocaleString());
|
const [displayDate, setDisplayDate] = useState(date.toLocaleString());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -270,12 +268,12 @@ export function DateTD({ date, now}: DateTDProps) {
|
|||||||
}, [displayDate, now])
|
}, [displayDate, now])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<td className="live-table-date">{displayDate}</td>
|
<td className="live-table-date">{displayDate}</td>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LiveList({ list }: LiveListProps) {
|
export function LiveList({ list }: LiveListProps) {
|
||||||
const [now, setNow] = useState(new Date())
|
const [now, setNow] = useState(new Date())
|
||||||
|
|
||||||
let items = list.map((a) => {
|
let items = list.map((a) => {
|
||||||
const attemptDate = new Date(a.date);
|
const attemptDate = new Date(a.date);
|
||||||
@ -389,21 +387,21 @@ interface HeaderItem {
|
|||||||
|
|
||||||
interface HeaderMenuProps {
|
interface HeaderMenuProps {
|
||||||
title: string
|
title: string
|
||||||
logo: URL
|
|
||||||
items: Array<HeaderItem>
|
items: Array<HeaderItem>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HeaderMenu({ title, logo, items }: HeaderMenuProps) {
|
export function HeaderMenu({ title, items }: HeaderMenuProps) {
|
||||||
const menuItems = items.map((item) => {
|
const menuItems = items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<li key={item.path}>
|
<li key={item.path}>
|
||||||
<NavLink to={item.path} className={({ isActive }) => isActive ? "menu-link-active" : "menu-link"}>{item.name}</NavLink>
|
<NavLink to={item.path} className={({ isActive }) => isActive ? "menu-link-active" : "menu-link"}>{item.name}</NavLink>
|
||||||
</li>
|
</li>
|
||||||
)})
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="navbar">
|
<div className="navbar">
|
||||||
<img id="menu-logo" src={logo.href}></img>
|
<img id="menu-logo"></img>
|
||||||
<h2 id="menu-title">{title}</h2>
|
<h2 id="menu-title">{title}</h2>
|
||||||
<nav className="nav-flex">
|
<nav className="nav-flex">
|
||||||
<ul>
|
<ul>
|
||||||
|
17
frontend/src/tests/api.test.ts
Normal file
17
frontend/src/tests/api.test.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { DummyApiaryAPIClient, TotalStats } from "../js/api";
|
||||||
|
|
||||||
|
describe("DummyApiaryAPIClient", () => {
|
||||||
|
const api = new DummyApiaryAPIClient()
|
||||||
|
test("totals returns expeced value", async () => {
|
||||||
|
let totals = await api.totals()
|
||||||
|
const expected: TotalStats = {
|
||||||
|
password: 1,
|
||||||
|
username: 1,
|
||||||
|
ip: 1,
|
||||||
|
attempts: 1,
|
||||||
|
country: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(totals).toEqual(expected)
|
||||||
|
})
|
||||||
|
});
|
@ -8,7 +8,7 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"types": ["node"]
|
"types": ["node", "jest"]
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user