upload ai slop

This commit is contained in:
arcanis committed 2026-02-26 02:29:52 +02:00
1 parent 49ebbc34fa
commit 3dfc78cc4c
93 files changed
+7745 -1732

No files matched your search

+3
View File
@@ -12,3 +12,6 @@ __pycache__/
*.pyc *.pyc
*.pyd *.pyd
*.pyo *.pyo
node_modules/
frontend/
+3
View File
@@ -99,3 +99,6 @@ status_cache.json
*.db *.db
docs/html/ docs/html/
# Frontend
node_modules/
+49
View File
@@ -0,0 +1,49 @@
import js from "@eslint/js";
import stylistic from "@stylistic/eslint-plugin";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommendedTypeChecked],
files: ["src/**/*.{ts,tsx}"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
"@stylistic": stylistic,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
"curly": "error",
"@stylistic/brace-style": ["error", "1tbs"],
// stylistic
"@stylistic/indent": ["error", 4],
"@stylistic/quotes": ["error", "double"],
"@stylistic/semi": ["error", "always"],
"@stylistic/comma-dangle": ["error", "always-multiline"],
"@stylistic/object-curly-spacing": ["error", "always"],
"@stylistic/array-bracket-spacing": ["error", "never"],
"@stylistic/arrow-parens": ["error", "always"],
"@stylistic/eol-last": ["error", "always"],
"@stylistic/no-trailing-spaces": "error",
"@stylistic/no-multiple-empty-lines": ["error", { max: 1 }],
"@stylistic/jsx-quotes": ["error", "prefer-double"],
// typescript
"@typescript-eslint/explicit-function-return-type": ["error", { allowExpressions: true }],
"@typescript-eslint/no-deprecated": "error",
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
},
},
);
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ahriman</title>
<link rel="icon" href="/static/favicon.ico" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+4280
View File
File diff suppressed because it is too large. Load diff
+40
View File
@@ -0,0 +1,40 @@
{
"name": "ahriman-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src/",
"lint:fix": "eslint --fix src/",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.0",
"@mui/material": "^5.15.0",
"@mui/x-data-grid": "^7.0.0",
"@tanstack/react-query": "^5.0.0",
"chart.js": "^4.5.0",
"highlight.js": "^11.11.0",
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@eslint/js": "^9.39.3",
"@stylistic/eslint-plugin": "^5.9.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.2.0",
"eslint": "^9.39.3",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"typescript": "^5.3.0",
"typescript-eslint": "^8.56.1",
"vite": "^5.0.0",
"vite-tsconfig-paths": "^6.1.1"
}
}
+35
View File
@@ -0,0 +1,35 @@
import type React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import Theme from "theme/Theme";
import { AuthProvider } from "contexts/AuthProvider";
import { RepositoryProvider } from "contexts/RepositoryProvider";
import { NotificationProvider } from "contexts/NotificationProvider";
import AppLayout from "components/layout/AppLayout";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30_000,
retry: 1,
},
},
});
export default function App(): React.JSX.Element {
return (
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={Theme}>
<CssBaseline />
<AuthProvider>
<RepositoryProvider>
<NotificationProvider>
<AppLayout />
</NotificationProvider>
</RepositoryProvider>
</AuthProvider>
</ThemeProvider>
</QueryClientProvider>
);
}
+30
View File
@@ -0,0 +1,30 @@
import type { RepositoryId } from "api/types/RepositoryId";
function repoKey(repo: RepositoryId): string {
return `${repo.architecture}-${repo.repository}`;
}
export const QueryKeys = {
info: ["info"] as const,
packages: (repo: RepositoryId) => ["packages", repoKey(repo)] as const,
package: (base: string, repo: RepositoryId) => ["packages", repoKey(repo), base] as const,
status: (repo: RepositoryId) => ["status", repoKey(repo)] as const,
logs: (base: string, repo: RepositoryId) => ["logs", repoKey(repo), base] as const,
logsVersion: (base: string, repo: RepositoryId, version: string, processId: string) =>
["logs", repoKey(repo), base, version, processId] as const,
changes: (base: string, repo: RepositoryId) => ["changes", repoKey(repo), base] as const,
dependencies: (base: string, repo: RepositoryId) => ["dependencies", repoKey(repo), base] as const,
patches: (base: string) => ["patches", base] as const,
events: (repo: RepositoryId, objectId?: string) => ["events", repoKey(repo), objectId] as const,
search: (query: string) => ["search", query] as const,
pgpKey: (key: string, server: string) => ["pgp", key, server] as const,
};
+216
View File
@@ -0,0 +1,216 @@
import type { AURPackage } from "api/types/AURPackage";
import type { Changes } from "api/types/Changes";
import type { Dependencies } from "api/types/Dependencies";
import type { Event } from "api/types/Event";
import type { InfoResponse } from "api/types/InfoResponse";
import type { InternalStatus } from "api/types/InternalStatus";
import type { LogRecord } from "api/types/LogRecord";
import type { LoginRequest } from "api/types/LoginRequest";
import type { PackageActionRequest } from "api/types/PackageActionRequest";
import type { PackageStatus } from "api/types/PackageStatus";
import type { Patch } from "api/types/Patch";
import type { PGPKey } from "api/types/PGPKey";
import type { PGPKeyRequest } from "api/types/PGPKeyRequest";
import type { RepositoryId } from "api/types/RepositoryId";
import { ApiError } from "api/client/ApiError";
import type { RequestOptions } from "api/client/RequestOptions";
export class AhrimanClient {
private static repoQuery(repo: RepositoryId): Record<string, string> {
return { architecture: repo.architecture, repository: repo.repository };
}
private async request<T>(url: string, options: RequestOptions = {}): Promise<T> {
const { method, query, json } = options;
let fullUrl = url;
if (query) {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(query)) {
if (value !== undefined && value !== null) {
params.set(key, String(value));
}
}
fullUrl += `?${params.toString()}`;
}
const requestInit: RequestInit = {
method: method || (json ? "POST" : "GET"),
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
if (json !== undefined) {
requestInit.body = JSON.stringify(json);
}
const response = await fetch(fullUrl, requestInit);
if (!response.ok) {
const body = await response.text();
throw new ApiError(response.status, response.statusText, body);
}
const contentType = response.headers.get("Content-Type") ?? "";
if (contentType.includes("application/json")) {
return await response.json() as T;
}
return await response.text() as T;
}
// Info
async fetchInfo(): Promise<InfoResponse> {
return this.request<InfoResponse>("/api/v1/info");
}
// Packages
async fetchPackages(repo: RepositoryId): Promise<PackageStatus[]> {
return this.request<PackageStatus[]>("/api/v1/packages", { query: AhrimanClient.repoQuery(repo) });
}
async fetchPackage(base: string, repo: RepositoryId): Promise<PackageStatus[]> {
return this.request<PackageStatus[]>(`/api/v1/packages/${encodeURIComponent(base)}`, {
query: AhrimanClient.repoQuery(repo),
});
}
// Status
async fetchStatus(repo: RepositoryId): Promise<InternalStatus> {
return this.request<InternalStatus>("/api/v1/status", { query: AhrimanClient.repoQuery(repo) });
}
// Logs
async fetchLogs(
base: string,
repo: RepositoryId,
version?: string,
processId?: string,
head?: boolean,
): Promise<LogRecord[]> {
const query: Record<string, string | boolean> = AhrimanClient.repoQuery(repo);
if (version) {
query.version = version;
}
if (processId) {
query.process_id = processId;
}
if (head) {
query.head = true;
}
return this.request<LogRecord[]>(`/api/v2/packages/${encodeURIComponent(base)}/logs`, { query });
}
// Changes
async fetchChanges(base: string, repo: RepositoryId): Promise<Changes> {
return this.request<Changes>(`/api/v1/packages/${encodeURIComponent(base)}/changes`, {
query: AhrimanClient.repoQuery(repo),
});
}
// Dependencies
async fetchDependencies(base: string, repo: RepositoryId): Promise<Dependencies> {
return this.request<Dependencies>(`/api/v1/packages/${encodeURIComponent(base)}/dependencies`, {
query: AhrimanClient.repoQuery(repo),
});
}
// Patches
async fetchPatches(base: string): Promise<Patch[]> {
return this.request<Patch[]>(`/api/v1/packages/${encodeURIComponent(base)}/patches`);
}
async deletePatch(base: string, key: string): Promise<void> {
return this.request(`/api/v1/packages/${encodeURIComponent(base)}/patches/${encodeURIComponent(key)}`, {
method: "DELETE",
});
}
// Events
async fetchEvents(repo: RepositoryId, objectId?: string, limit?: number): Promise<Event[]> {
const query: Record<string, string | number> = AhrimanClient.repoQuery(repo);
if (objectId) {
query.object_id = objectId;
}
if (limit) {
query.limit = limit;
}
return this.request<Event[]>("/api/v1/events", { query });
}
// Service actions
async addPackages(repo: RepositoryId, data: PackageActionRequest): Promise<void> {
return this.request("/api/v1/service/add", { method: "POST", query: AhrimanClient.repoQuery(repo), json: data });
}
async removePackages(repo: RepositoryId, packages: string[]): Promise<void> {
return this.request("/api/v1/service/remove", {
method: "POST",
query: AhrimanClient.repoQuery(repo),
json: { packages },
});
}
async updatePackages(repo: RepositoryId, data: PackageActionRequest): Promise<void> {
return this.request("/api/v1/service/update", {
method: "POST",
query: AhrimanClient.repoQuery(repo),
json: data,
});
}
async rebuildPackages(repo: RepositoryId, packages: string[]): Promise<void> {
return this.request("/api/v1/service/rebuild", {
method: "POST",
query: AhrimanClient.repoQuery(repo),
json: { packages },
});
}
async requestPackages(repo: RepositoryId, data: PackageActionRequest): Promise<void> {
return this.request("/api/v1/service/request", {
method: "POST",
query: AhrimanClient.repoQuery(repo),
json: data,
});
}
// Search
async searchPackages(query: string): Promise<AURPackage[]> {
return this.request<AURPackage[]>("/api/v1/service/search", { query: { for: query } });
}
// PGP
async fetchPGPKey(key: string, server: string): Promise<PGPKey> {
return this.request<PGPKey>("/api/v1/service/pgp", { query: { key, server } });
}
async importPGPKey(data: PGPKeyRequest): Promise<void> {
return this.request("/api/v1/service/pgp", { method: "POST", json: data });
}
// Auth
async login(data: LoginRequest): Promise<void> {
return this.request("/api/v1/login", { method: "POST", json: data });
}
async logout(): Promise<void> {
return this.request("/api/v1/logout", { method: "POST" });
}
}
export const Client = new AhrimanClient();
+21
View File
@@ -0,0 +1,21 @@
export class ApiError extends Error {
status: number;
statusText: string;
body: string;
constructor(status: number, statusText: string, body: string) {
super(`${status} ${statusText}`);
this.status = status;
this.statusText = statusText;
this.body = body;
}
get detail(): string {
try {
const parsed = JSON.parse(this.body) as Record<string, string>;
return parsed.error ?? (this.body || this.message);
} catch {
return this.body || this.message;
}
}
}
@@ -0,0 +1,5 @@
export interface RequestOptions {
method?: string;
query?: Record<string, string | number | boolean>;
json?: unknown;
}
+4
View File
@@ -0,0 +1,4 @@
export interface AURPackage {
package: string;
description: string;
}
@@ -0,0 +1,5 @@
export interface AutoRefreshInterval {
interval: number;
is_active: boolean;
text: string;
}
+1
View File
@@ -0,0 +1 @@
export type BuildStatus = "unknown" | "pending" | "building" | "failed" | "success";
+4
View File
@@ -0,0 +1,4 @@
export interface Changes {
changes?: string;
last_commit_sha?: string;
}
+8
View File
@@ -0,0 +1,8 @@
export interface Counters {
building: number;
failed: number;
pending: number;
success: number;
total: number;
unknown: number;
}
+3
View File
@@ -0,0 +1,3 @@
export interface Dependencies {
paths: Record<string, string[]>;
}
+7
View File
@@ -0,0 +1,7 @@
export interface Event {
created: number;
data?: Record<string, unknown>;
event: string;
message?: string;
object_id: string;
}
+12
View File
@@ -0,0 +1,12 @@
import type { AutoRefreshInterval } from "api/types/AutoRefreshInterval";
import type { RepositoryId } from "api/types/RepositoryId";
export interface InfoResponse {
auth: boolean;
repositories: RepositoryId[];
version: string;
autorefresh_intervals: AutoRefreshInterval[];
docs_enabled: boolean;
index_url?: string;
username?: string;
}
+12
View File
@@ -0,0 +1,12 @@
import type { Counters } from "api/types/Counters";
import type { RepositoryStats } from "api/types/RepositoryStats";
import type { Status } from "api/types/Status";
export interface InternalStatus {
architecture: string;
repository: string;
packages: Counters;
stats: RepositoryStats;
status: Status;
version: string;
}
+6
View File
@@ -0,0 +1,6 @@
export interface LogRecord {
created: number;
message: string;
process_id: string;
version: string;
}
+4
View File
@@ -0,0 +1,4 @@
export interface LoginRequest {
username: string;
password: string;
}
+3
View File
@@ -0,0 +1,3 @@
export interface PGPKey {
key: string;
}
+4
View File
@@ -0,0 +1,4 @@
export interface PGPKeyRequest {
key: string;
server: string;
}
+10
View File
@@ -0,0 +1,10 @@
import type { PackageProperties } from "api/types/PackageProperties";
import type { Remote } from "api/types/Remote";
export interface Package {
base: string;
packager?: string;
packages: Record<string, PackageProperties>;
remote: Remote;
version: string;
}
@@ -0,0 +1,10 @@
import type { Patch } from "api/types/Patch";
export interface PackageActionRequest {
packages: string[];
patches?: Patch[];
refresh?: boolean;
aur?: boolean;
local?: boolean;
manual?: boolean;
}
@@ -0,0 +1,16 @@
export interface PackageProperties {
architecture?: string;
archive_size?: number;
build_date?: number;
check_depends?: string[];
depends?: string[];
description?: string;
filename?: string;
groups?: string[];
installed_size?: number;
licenses?: string[];
make_depends?: string[];
opt_depends?: string[];
provides?: string[];
url?: string;
}
+15
View File
@@ -0,0 +1,15 @@
import type { BuildStatus } from "api/types/BuildStatus";
export interface PackageRow {
id: string;
base: string;
webUrl?: string;
version: string;
packages: string[];
groups: string[];
licenses: string[];
packager: string;
timestamp: string;
timestampValue: number;
status: BuildStatus;
}
+9
View File
@@ -0,0 +1,9 @@
import type { Package } from "api/types/Package";
import type { RepositoryId } from "api/types/RepositoryId";
import type { Status } from "api/types/Status";
export interface PackageStatus {
package: Package;
status: Status;
repository: RepositoryId;
}
+4
View File
@@ -0,0 +1,4 @@
export interface Patch {
key: string;
value: string;
}
+7
View File
@@ -0,0 +1,7 @@
export interface Remote {
branch?: string;
git_url?: string;
path?: string;
source: string;
web_url?: string;
}
+4
View File
@@ -0,0 +1,4 @@
export interface RepositoryId {
architecture: string;
repository: string;
}
@@ -0,0 +1,6 @@
export interface RepositoryStats {
archive_size?: number;
bases?: number;
installed_size?: number;
packages?: number;
}
+6
View File
@@ -0,0 +1,6 @@
import type { BuildStatus } from "api/types/BuildStatus";
export interface Status {
status: BuildStatus;
timestamp: number;
}
@@ -0,0 +1,33 @@
import type React from "react";
import { Line } from "react-chartjs-2";
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend } from "chart.js";
import type { Event } from "api/types/Event";
import { formatTimestamp } from "components/common/formatTimestamp";
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend);
interface EventDurationLineChartProps {
events: Event[];
}
export default function EventDurationLineChart({ events }: EventDurationLineChartProps): React.JSX.Element | null {
const updateEvents = events.filter((e) => e.event === "package-updated" && e.data?.took);
if (updateEvents.length === 0) {
return null;
}
const data = {
labels: updateEvents.map((e) => formatTimestamp(e.created)),
datasets: [
{
label: "update duration, s",
data: updateEvents.map((e) => (e.data as Record<string, number>).took),
cubicInterpolationMode: "monotone" as const,
tension: 0.4,
},
],
};
return <Line data={data} options={{ responsive: true }} />;
}
@@ -0,0 +1,39 @@
import type React from "react";
import { Bar } from "react-chartjs-2";
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Tooltip, Legend } from "chart.js";
import type { RepositoryStats } from "api/types/RepositoryStats";
ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend);
interface PackageCountBarChartProps {
stats: RepositoryStats;
}
export default function PackageCountBarChart({ stats }: PackageCountBarChartProps): React.JSX.Element {
const data = {
labels: ["packages"],
datasets: [
{
label: "archives",
data: [stats.packages ?? 0],
},
{
label: "bases",
data: [stats.bases ?? 0],
},
],
};
return (
<Bar
data={data}
options={{
maintainAspectRatio: false,
responsive: true,
scales: {
x: { stacked: true },
},
}}
/>
);
}
@@ -0,0 +1,27 @@
import type React from "react";
import { Pie } from "react-chartjs-2";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
import type { Counters } from "api/types/Counters";
import { ChartColors } from "theme/status/ChartColors";
ChartJS.register(ArcElement, Tooltip, Legend);
interface StatusPieChartProps {
counters: Counters;
}
export default function StatusPieChart({ counters }: StatusPieChartProps): React.JSX.Element {
const labels = ["unknown", "pending", "building", "failed", "success"] as const;
const data = {
labels: labels.map((l) => l),
datasets: [
{
label: "packages in status",
data: labels.map((label) => counters[label]),
backgroundColor: labels.map((label) => ChartColors[label]),
},
],
};
return <Pie data={data} options={{ responsive: true }} />;
}
@@ -0,0 +1,75 @@
import React, { useState } from "react";
import { IconButton, Menu, MenuItem, Tooltip, ListItemIcon, ListItemText } from "@mui/material";
import TimerIcon from "@mui/icons-material/Timer";
import TimerOffIcon from "@mui/icons-material/TimerOff";
import CheckIcon from "@mui/icons-material/Check";
import type { AutoRefreshInterval } from "api/types/AutoRefreshInterval";
interface AutoRefreshControlProps {
intervals: AutoRefreshInterval[];
enabled: boolean;
currentInterval: number;
onToggle: (enabled: boolean) => void;
onIntervalChange: (interval: number) => void;
}
export default function AutoRefreshControl({
intervals,
enabled,
currentInterval,
onToggle,
onIntervalChange,
}: AutoRefreshControlProps): React.JSX.Element | null {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
if (intervals.length === 0) {
return null;
}
return (
<>
<Tooltip title="Auto-refresh">
<IconButton
size="small"
onClick={(e) => setAnchorEl(e.currentTarget)}
color={enabled ? "primary" : "default"}
>
{enabled ? <TimerIcon fontSize="small" /> : <TimerOffIcon fontSize="small" />}
</IconButton>
</Tooltip>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
>
<MenuItem
selected={!enabled}
onClick={() => {
onToggle(false);
setAnchorEl(null);
}}
>
<ListItemIcon>
{!enabled && <CheckIcon fontSize="small" />}
</ListItemIcon>
<ListItemText>Off</ListItemText>
</MenuItem>
{intervals.map((iv) => (
<MenuItem
key={iv.interval}
selected={enabled && iv.interval === currentInterval}
onClick={() => {
onIntervalChange(iv.interval);
setAnchorEl(null);
}}
>
<ListItemIcon>
{enabled && iv.interval === currentInterval && <CheckIcon fontSize="small" />}
</ListItemIcon>
<ListItemText>{iv.text}</ListItemText>
</MenuItem>
))}
</Menu>
</>
);
}
@@ -0,0 +1,26 @@
import React, { useState } from "react";
import { IconButton, Tooltip } from "@mui/material";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import CheckIcon from "@mui/icons-material/Check";
interface CopyButtonProps {
getText: () => string;
}
export default function CopyButton({ getText }: CopyButtonProps): React.JSX.Element {
const [copied, setCopied] = useState(false);
const handleCopy = async (): Promise<void> => {
await navigator.clipboard.writeText(getText());
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<Tooltip title={copied ? "Copied!" : "Copy"}>
<IconButton size="small" onClick={() => void handleCopy()}>
{copied ? <CheckIcon fontSize="small" /> : <ContentCopyIcon fontSize="small" />}
</IconButton>
</Tooltip>
);
}
@@ -0,0 +1,5 @@
export function formatTimestamp(unixSeconds: number): string {
const d = new Date(unixSeconds * 1000);
const pad = (n: number): string => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
@@ -0,0 +1,88 @@
import type React from "react";
import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Grid, Typography, Box } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { useQuery } from "@tanstack/react-query";
import StatusPieChart from "components/charts/StatusPieChart";
import PackageCountBarChart from "components/charts/PackageCountBarChart";
import { Client } from "api/client/AhrimanClient";
import { QueryKeys } from "api/QueryKeys";
import { useRepository } from "hooks/useRepository";
import { StatusHeaderStyles } from "theme/status/StatusHeaderStyles";
import { formatTimestamp } from "components/common/formatTimestamp";
import type { InternalStatus } from "api/types/InternalStatus";
interface DashboardDialogProps {
open: boolean;
onClose: () => void;
}
export default function DashboardDialog({ open, onClose }: DashboardDialogProps): React.JSX.Element {
const { current } = useRepository();
const { data: status } = useQuery<InternalStatus>({
queryKey: current ? QueryKeys.status(current) : ["status"],
queryFn: () => Client.fetchStatus(current!),
enabled: !!current && open,
});
const headerStyle = status ? StatusHeaderStyles[status.status.status] : {};
return (
<Dialog open={open} onClose={onClose} maxWidth="lg" fullWidth>
<DialogTitle sx={headerStyle}>System health</DialogTitle>
<DialogContent>
{status && (
<>
<Grid container spacing={2} sx={{ mt: 1 }}>
<Grid item xs={6} md={3}>
<Typography variant="body2" color="text.secondary" align="right">Repository name</Typography>
</Grid>
<Grid item xs={6} md={3}>
<Typography variant="body2">{status.repository}</Typography>
</Grid>
<Grid item xs={6} md={3}>
<Typography variant="body2" color="text.secondary" align="right">Repository architecture</Typography>
</Grid>
<Grid item xs={6} md={3}>
<Typography variant="body2">{status.architecture}</Typography>
</Grid>
</Grid>
<Grid container spacing={2} sx={{ mt: 1 }}>
<Grid item xs={6} md={3}>
<Typography variant="body2" color="text.secondary" align="right">Current status</Typography>
</Grid>
<Grid item xs={6} md={3}>
<Typography variant="body2">{status.status.status}</Typography>
</Grid>
<Grid item xs={6} md={3}>
<Typography variant="body2" color="text.secondary" align="right">Updated at</Typography>
</Grid>
<Grid item xs={6} md={3}>
<Typography variant="body2">{formatTimestamp(status.status.timestamp)}</Typography>
</Grid>
</Grid>
{status.packages.total > 0 && (
<Grid container spacing={2} sx={{ mt: 2 }}>
<Grid item xs={12} md={6}>
<Box sx={{ maxHeight: 300 }}>
<PackageCountBarChart stats={status.stats} />
</Box>
</Grid>
<Grid item xs={12} md={6}>
<Box sx={{ maxHeight: 300 }}>
<StatusPieChart counters={status.packages} />
</Box>
</Grid>
</Grid>
)}
</>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose} variant="contained" startIcon={<CloseIcon />}>close</Button>
</DialogActions>
</Dialog>
);
}
@@ -0,0 +1,106 @@
import React, { useState } from "react";
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button,
TextField, Box,
} from "@mui/material";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import RefreshIcon from "@mui/icons-material/Refresh";
import { useNotification } from "hooks/useNotification";
import { Client } from "api/client/AhrimanClient";
import { ApiError } from "api/client/ApiError";
import CopyButton from "components/common/CopyButton";
interface KeyImportDialogProps {
open: boolean;
onClose: () => void;
}
export default function KeyImportDialog({ open, onClose }: KeyImportDialogProps): React.JSX.Element {
const { showSuccess, showError } = useNotification();
const [fingerprint, setFingerprint] = useState("");
const [server, setServer] = useState("keyserver.ubuntu.com");
const [keyBody, setKeyBody] = useState("");
const handleFetch = async (): Promise<void> => {
if (!fingerprint || !server) {
return;
}
try {
const result = await Client.fetchPGPKey(fingerprint, server);
setKeyBody(result.key);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Could not fetch key: ${detail}`);
}
};
const handleImport = async (): Promise<void> => {
if (!fingerprint || !server) {
return;
}
try {
await Client.importPGPKey({ key: fingerprint, server });
onClose();
showSuccess("Success", `Key ${fingerprint} has been imported`);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Could not import key ${fingerprint} from ${server}: ${detail}`);
}
};
const handleClose = (): void => {
setFingerprint("");
setServer("keyserver.ubuntu.com");
setKeyBody("");
onClose();
};
return (
<Dialog open={open} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogTitle>Import key from PGP server</DialogTitle>
<DialogContent>
<TextField
label="fingerprint"
placeholder="PGP key fingerprint"
fullWidth
margin="normal"
value={fingerprint}
onChange={(e) => setFingerprint(e.target.value)}
/>
<TextField
label="key server"
placeholder="PGP key server"
fullWidth
margin="normal"
value={server}
onChange={(e) => setServer(e.target.value)}
/>
{keyBody && (
<Box sx={{ position: "relative", mt: 2 }}>
<Box
component="pre"
sx={{
backgroundColor: "#f5f5f5",
p: 2,
borderRadius: 1,
overflow: "auto",
maxHeight: 300,
fontSize: "0.85rem",
}}
>
<code>{keyBody}</code>
</Box>
<Box sx={{ position: "absolute", top: 8, right: 8 }}>
<CopyButton getText={() => keyBody} />
</Box>
</Box>
)}
</DialogContent>
<DialogActions>
<Button onClick={() => void handleImport()} variant="contained" startIcon={<PlayArrowIcon />}>import</Button>
<Button onClick={() => void handleFetch()} variant="contained" color="success" startIcon={<RefreshIcon />}>fetch</Button>
</DialogActions>
</Dialog>
);
}
@@ -0,0 +1,91 @@
import React, { useState } from "react";
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField,
InputAdornment, IconButton,
} from "@mui/material";
import VisibilityIcon from "@mui/icons-material/Visibility";
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
import PersonIcon from "@mui/icons-material/Person";
import { useAuth } from "hooks/useAuth";
import { useNotification } from "hooks/useNotification";
import { ApiError } from "api/client/ApiError";
interface LoginDialogProps {
open: boolean;
onClose: () => void;
}
export default function LoginDialog({ open, onClose }: LoginDialogProps): React.JSX.Element {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
const { login } = useAuth();
const { showSuccess, showError } = useNotification();
const handleSubmit = async (): Promise<void> => {
if (!username || !password) {
return;
}
try {
await login(username, password);
onClose();
showSuccess("Logged in", `Successfully logged in as ${username}`);
window.location.href = "/";
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
if (username === "admin" && password === "admin") {
showError("Login error", "You've entered a password for user \"root\", did you make a typo in username?");
} else {
showError("Login error", `Could not login as ${username}: ${detail}`);
}
}
};
const handleClose = (): void => {
setUsername("");
setPassword("");
setShowPassword(false);
onClose();
};
return (
<Dialog open={open} onClose={handleClose} maxWidth="xs" fullWidth>
<DialogTitle>Login</DialogTitle>
<DialogContent>
<TextField
label="username"
fullWidth
margin="normal"
value={username}
onChange={(e) => setUsername(e.target.value)}
autoFocus
/>
<TextField
label="password"
fullWidth
margin="normal"
type={showPassword ? "text" : "password"}
value={password}
onChange={(e) => setPassword(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
void handleSubmit();
}
}}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => setShowPassword(!showPassword)} edge="end" size="small">
{showPassword ? <VisibilityOffIcon /> : <VisibilityIcon />}
</IconButton>
</InputAdornment>
),
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => void handleSubmit()} variant="contained" startIcon={<PersonIcon />}>login</Button>
</DialogActions>
</Dialog>
);
}
@@ -0,0 +1,194 @@
import React, { useState, useCallback } from "react";
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button,
TextField, Autocomplete, Box, IconButton, FormControlLabel, Checkbox, Select, MenuItem, InputLabel, FormControl,
} from "@mui/material";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import AddIcon from "@mui/icons-material/Add";
import DeleteIcon from "@mui/icons-material/Delete";
import { useQuery } from "@tanstack/react-query";
import { useRepository } from "hooks/useRepository";
import { useNotification } from "hooks/useNotification";
import { useDebounce } from "hooks/useDebounce";
import { Client } from "api/client/AhrimanClient";
import { ApiError } from "api/client/ApiError";
import { QueryKeys } from "api/QueryKeys";
import type { AURPackage } from "api/types/AURPackage";
import type { RepositoryId } from "api/types/RepositoryId";
interface EnvVar {
key: string;
value: string;
}
interface PackageAddDialogProps {
open: boolean;
onClose: () => void;
}
export default function PackageAddDialog({ open, onClose }: PackageAddDialogProps): React.JSX.Element {
const { repositories, current } = useRepository();
const { showSuccess, showError } = useNotification();
const [packageName, setPackageName] = useState("");
const [selectedRepo, setSelectedRepo] = useState<string>("");
const [refresh, setRefresh] = useState(true);
const [envVars, setEnvVars] = useState<EnvVar[]>([]);
const debouncedSearch = useDebounce(packageName, 500);
const { data: searchResults = [] } = useQuery<AURPackage[]>({
queryKey: QueryKeys.search(debouncedSearch),
queryFn: () => Client.searchPackages(debouncedSearch),
enabled: debouncedSearch.length >= 3,
});
const getSelectedRepo = useCallback((): RepositoryId => {
if (selectedRepo) {
const repo = repositories.find(
(r) => `${r.architecture}-${r.repository}` === selectedRepo,
);
if (repo) {
return repo;
}
}
return current!;
}, [selectedRepo, repositories, current]);
const handleAdd = async (): Promise<void> => {
if (!packageName) {
return;
}
const repo = getSelectedRepo();
try {
const patches = envVars.filter((v) => v.key);
await Client.addPackages(repo, {
packages: [packageName],
patches: patches.length > 0 ? patches : undefined,
refresh,
});
onClose();
showSuccess("Success", `Packages ${packageName} have been added`);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Package addition failed: ${detail}`);
}
};
const handleRequest = async (): Promise<void> => {
if (!packageName) {
return;
}
const repo = getSelectedRepo();
try {
const patches = envVars.filter((v) => v.key);
await Client.requestPackages(repo, {
packages: [packageName],
patches: patches.length > 0 ? patches : undefined,
});
onClose();
showSuccess("Success", `Packages ${packageName} have been requested`);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Package request failed: ${detail}`);
}
};
const handleClose = (): void => {
setPackageName("");
setSelectedRepo("");
setRefresh(true);
setEnvVars([]);
onClose();
};
return (
<Dialog open={open} onClose={handleClose} maxWidth="md" fullWidth>
<DialogTitle>Add new packages</DialogTitle>
<DialogContent>
<FormControl fullWidth margin="normal">
<InputLabel>repository</InputLabel>
<Select
value={selectedRepo || (current ? `${current.architecture}-${current.repository}` : "")}
label="repository"
onChange={(e) => setSelectedRepo(e.target.value)}
>
{repositories.map((r) => (
<MenuItem key={`${r.architecture}-${r.repository}`} value={`${r.architecture}-${r.repository}`}>
{r.repository} ({r.architecture})
</MenuItem>
))}
</Select>
</FormControl>
<Autocomplete
freeSolo
options={searchResults.map((p) => p.package)}
inputValue={packageName}
onInputChange={(_, value) => setPackageName(value)}
renderOption={(props, option) => {
const pkg = searchResults.find((p) => p.package === option);
return (
<li {...props} key={option}>
{option}{pkg ? ` (${pkg.description})` : ""}
</li>
);
}}
renderInput={(params) => (
<TextField {...params} label="package" placeholder="AUR package" margin="normal" />
)}
/>
<FormControlLabel
control={<Checkbox checked={refresh} onChange={(_, checked) => setRefresh(checked)} />}
label="update pacman databases"
/>
<Button
fullWidth
variant="outlined"
startIcon={<AddIcon />}
onClick={() => setEnvVars([...envVars, { key: "", value: "" }])}
sx={{ mt: 1 }}
>
add environment variable
</Button>
{envVars.map((env, index) => (
<Box key={index} sx={{ display: "flex", gap: 1, mt: 1, alignItems: "center" }}>
<TextField
size="small"
placeholder="name"
value={env.key}
onChange={(e) => {
const updated = [...envVars];
updated[index] = { ...updated[index], key: e.target.value };
setEnvVars(updated);
}}
sx={{ flex: 1 }}
/>
<Box>=</Box>
<TextField
size="small"
placeholder="value"
value={env.value}
onChange={(e) => {
const updated = [...envVars];
updated[index] = { ...updated[index], value: e.target.value };
setEnvVars(updated);
}}
sx={{ flex: 1 }}
/>
<IconButton size="small" color="error" onClick={() => setEnvVars(envVars.filter((_, i) => i !== index))}>
<DeleteIcon />
</IconButton>
</Box>
))}
</DialogContent>
<DialogActions>
<Button onClick={() => void handleAdd()} variant="contained" startIcon={<PlayArrowIcon />}>add</Button>
<Button onClick={() => void handleRequest()} variant="contained" color="success" startIcon={<AddIcon />}>request</Button>
</DialogActions>
</Dialog>
);
}
@@ -0,0 +1,299 @@
import React, { useState } from "react";
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button,
Grid, Typography, Link, Box, Tab, Tabs, IconButton, Chip, FormControlLabel, Checkbox,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import DeleteIcon from "@mui/icons-material/Delete";
import RefreshIcon from "@mui/icons-material/Refresh";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import BuildLogsTab from "components/package/BuildLogsTab";
import ChangesTab from "components/package/ChangesTab";
import EventsTab from "components/package/EventsTab";
import AutoRefreshControl from "components/common/AutoRefreshControl";
import { useRepository } from "hooks/useRepository";
import { useAuth } from "hooks/useAuth";
import { useNotification } from "hooks/useNotification";
import { useAutoRefresh } from "hooks/useAutoRefresh";
import { Client } from "api/client/AhrimanClient";
import { ApiError } from "api/client/ApiError";
import { QueryKeys } from "api/QueryKeys";
import { StatusHeaderStyles } from "theme/status/StatusHeaderStyles";
import { formatTimestamp } from "components/common/formatTimestamp";
import type { AutoRefreshInterval } from "api/types/AutoRefreshInterval";
import type { Dependencies } from "api/types/Dependencies";
import type { PackageProperties } from "api/types/PackageProperties";
import type { PackageStatus } from "api/types/PackageStatus";
import type { Patch } from "api/types/Patch";
import type { RepositoryId } from "api/types/RepositoryId";
interface PackageInfoDialogProps {
packageBase: string | null;
open: boolean;
onClose: () => void;
autorefreshIntervals: AutoRefreshInterval[];
}
function listToString(items: string[]): React.ReactNode {
const unique = [...new Set(items)].sort();
return unique.map((item, i) => (
<React.Fragment key={item}>
{item}
{i < unique.length - 1 && <br />}
</React.Fragment>
));
}
export default function PackageInfoDialog({ packageBase, open, onClose, autorefreshIntervals }: PackageInfoDialogProps): React.JSX.Element {
const { current } = useRepository();
const { enabled: authEnabled, username } = useAuth();
const { showSuccess, showError } = useNotification();
const queryClient = useQueryClient();
const hasAuth = !authEnabled || username !== null;
const [tabIndex, setTabIndex] = useState(0);
const [refreshDb, setRefreshDb] = useState(true);
const defaultInterval = autorefreshIntervals.find((i) => i.is_active)?.interval ?? 0;
const autoRefresh = useAutoRefresh("package-info-autoreload-button", defaultInterval);
const repo = current as RepositoryId;
const { data: packageData } = useQuery<PackageStatus[]>({
queryKey: packageBase && repo ? QueryKeys.package(packageBase, repo) : ["package-none"],
queryFn: () => Client.fetchPackage(packageBase!, repo),
enabled: !!packageBase && !!repo && open,
refetchInterval: autoRefresh.refetchInterval,
});
const { data: dependencies } = useQuery<Dependencies>({
queryKey: packageBase && repo ? QueryKeys.dependencies(packageBase, repo) : ["deps-none"],
queryFn: () => Client.fetchDependencies(packageBase!, repo),
enabled: !!packageBase && !!repo && open,
});
const { data: patches = [] } = useQuery<Patch[]>({
queryKey: packageBase ? QueryKeys.patches(packageBase) : ["patches-none"],
queryFn: () => Client.fetchPatches(packageBase!),
enabled: !!packageBase && open,
});
const description: PackageStatus | undefined = packageData?.[0];
const pkg = description?.package;
const status = description?.status;
const headerStyle = status ? StatusHeaderStyles[status.status] : {};
// Flatten depends from all sub-packages
const allDepends: string[] = pkg
? Object.values(pkg.packages).flatMap((p: PackageProperties) => {
const pkgNames = Object.keys(pkg.packages);
const deps = (p.depends ?? []).filter((d: string) => !pkgNames.includes(d));
const makeDeps = (p.make_depends ?? []).filter((d: string) => !pkgNames.includes(d)).map((d: string) => `${d} (make)`);
const optDeps = (p.opt_depends ?? []).filter((d: string) => !pkgNames.includes(d)).map((d: string) => `${d} (optional)`);
return [...deps, ...makeDeps, ...optDeps];
})
: [];
const implicitDepends: string[] = dependencies
? Object.values(dependencies.paths).flat()
: [];
const groups: string[] = pkg
? Object.values(pkg.packages).flatMap((p: PackageProperties) => p.groups ?? [])
: [];
const licenses: string[] = pkg
? Object.values(pkg.packages).flatMap((p: PackageProperties) => p.licenses ?? [])
: [];
const upstreamUrls: string[] = pkg
? [...new Set(Object.values(pkg.packages).map((p: PackageProperties) => p.url).filter((u): u is string => !!u))].sort()
: [];
const aurUrl = pkg?.remote.web_url;
const packagesList: string[] = pkg
? Object.entries(pkg.packages).map(([name, p]) => `${name}${p.description ? ` (${p.description})` : ""}`)
: [];
const handleUpdate = async (): Promise<void> => {
if (!packageBase || !repo) {
return;
}
try {
await Client.addPackages(repo, { packages: [packageBase], refresh: refreshDb });
showSuccess("Success", `Run update for packages ${packageBase}`);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Package update failed: ${detail}`);
}
};
const handleRemove = async (): Promise<void> => {
if (!packageBase || !repo) {
return;
}
try {
await Client.removePackages(repo, [packageBase]);
showSuccess("Success", `Packages ${packageBase} have been removed`);
onClose();
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Could not remove package: ${detail}`);
}
};
const handleDeletePatch = async (key: string): Promise<void> => {
if (!packageBase) {
return;
}
try {
await Client.deletePatch(packageBase, key);
void queryClient.invalidateQueries({ queryKey: QueryKeys.patches(packageBase) });
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Could not delete variable: ${detail}`);
}
};
const handleReload = (): void => {
if (!packageBase || !repo) {
return;
}
void queryClient.invalidateQueries({ queryKey: QueryKeys.package(packageBase, repo) });
void queryClient.invalidateQueries({ queryKey: QueryKeys.logs(packageBase, repo) });
void queryClient.invalidateQueries({ queryKey: QueryKeys.changes(packageBase, repo) });
void queryClient.invalidateQueries({ queryKey: QueryKeys.events(repo, packageBase) });
void queryClient.invalidateQueries({ queryKey: QueryKeys.dependencies(packageBase, repo) });
void queryClient.invalidateQueries({ queryKey: QueryKeys.patches(packageBase) });
};
const handleClose = (): void => {
setTabIndex(0);
setRefreshDb(true);
onClose();
};
return (
<Dialog open={open} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogTitle sx={headerStyle}>
{pkg && status
? `${pkg.base} ${status.status} at ${formatTimestamp(status.timestamp)}`
: packageBase ?? ""}
</DialogTitle>
<DialogContent>
{pkg && (
<>
<Grid container spacing={1} sx={{ mt: 1 }}>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">packages</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{listToString(packagesList)}</Typography></Grid>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">version</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{pkg.version}</Typography></Grid>
</Grid>
<Grid container spacing={1} sx={{ mt: 0.5 }}>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">packager</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{pkg.packager ?? ""}</Typography></Grid>
<Grid item xs={4} md={1} />
<Grid item xs={8} md={5} />
</Grid>
<Grid container spacing={1} sx={{ mt: 0.5 }}>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">groups</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{listToString(groups)}</Typography></Grid>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">licenses</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{listToString(licenses)}</Typography></Grid>
</Grid>
<Grid container spacing={1} sx={{ mt: 0.5 }}>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">upstream</Typography></Grid>
<Grid item xs={8} md={5}>
{upstreamUrls.map((url) => (
<Link key={url} href={url} target="_blank" rel="noopener" underline="hover" display="block" variant="body2">
{url}
</Link>
))}
</Grid>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">AUR</Typography></Grid>
<Grid item xs={8} md={5}>
{aurUrl && (
<Link href={aurUrl} target="_blank" rel="noopener" underline="hover" variant="body2">AUR link</Link>
)}
</Grid>
</Grid>
<Grid container spacing={1} sx={{ mt: 0.5 }}>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">depends</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{listToString(allDepends)}</Typography></Grid>
<Grid item xs={4} md={1}><Typography variant="body2" color="text.secondary" align="right">implicitly depends</Typography></Grid>
<Grid item xs={8} md={5}><Typography variant="body2">{listToString(implicitDepends)}</Typography></Grid>
</Grid>
{patches.length > 0 && (
<Box sx={{ mt: 2 }}>
<Typography variant="subtitle2" gutterBottom>Environment variables</Typography>
{patches.map((patch) => (
<Box key={patch.key} sx={{ display: "flex", alignItems: "center", gap: 1, mb: 0.5 }}>
<Chip label={patch.key} size="small" />
<Typography variant="body2">=</Typography>
<Typography variant="body2" sx={{ fontFamily: "monospace" }}>{JSON.stringify(patch.value)}</Typography>
{hasAuth && (
<IconButton size="small" color="error" onClick={() => void handleDeletePatch(patch.key)}>
<DeleteIcon fontSize="small" />
</IconButton>
)}
</Box>
))}
</Box>
)}
<Box sx={{ borderBottom: 1, borderColor: "divider", mt: 2 }}>
<Tabs value={tabIndex} onChange={(_, v: number) => setTabIndex(v)}>
<Tab label="Build logs" />
<Tab label="Changes" />
<Tab label="Events" />
</Tabs>
</Box>
{tabIndex === 0 && packageBase && repo && (
<BuildLogsTab packageBase={packageBase} repo={repo} refetchInterval={autoRefresh.refetchInterval} />
)}
{tabIndex === 1 && packageBase && repo && (
<ChangesTab packageBase={packageBase} repo={repo} />
)}
{tabIndex === 2 && packageBase && repo && (
<EventsTab packageBase={packageBase} repo={repo} />
)}
</>
)}
</DialogContent>
<DialogActions sx={{ flexWrap: "wrap", gap: 1 }}>
{hasAuth && (
<>
<FormControlLabel
control={<Checkbox checked={refreshDb} onChange={(_, checked) => setRefreshDb(checked)} size="small" />}
label="update pacman databases"
/>
<Button onClick={() => void handleUpdate()} variant="contained" color="success" startIcon={<PlayArrowIcon />} size="small">
update
</Button>
<Button onClick={() => void handleRemove()} variant="contained" color="error" startIcon={<DeleteIcon />} size="small">
remove
</Button>
</>
)}
<Button onClick={handleReload} variant="outlined" color="secondary" startIcon={<RefreshIcon />} size="small">
reload
</Button>
<AutoRefreshControl
intervals={autorefreshIntervals}
enabled={autoRefresh.enabled}
currentInterval={autoRefresh.interval}
onToggle={autoRefresh.setEnabled}
onIntervalChange={autoRefresh.setInterval}
/>
<Button onClick={handleClose} variant="contained" startIcon={<CloseIcon />} size="small">
close
</Button>
</DialogActions>
</Dialog>
);
}
@@ -0,0 +1,89 @@
import React, { useState } from "react";
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button,
TextField, Select, MenuItem, InputLabel, FormControl,
} from "@mui/material";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import { useRepository } from "hooks/useRepository";
import { useNotification } from "hooks/useNotification";
import { Client } from "api/client/AhrimanClient";
import { ApiError } from "api/client/ApiError";
import type { RepositoryId } from "api/types/RepositoryId";
interface PackageRebuildDialogProps {
open: boolean;
onClose: () => void;
}
export default function PackageRebuildDialog({ open, onClose }: PackageRebuildDialogProps): React.JSX.Element {
const { repositories, current } = useRepository();
const { showSuccess, showError } = useNotification();
const [dependency, setDependency] = useState("");
const [selectedRepo, setSelectedRepo] = useState<string>("");
const getSelectedRepo = (): RepositoryId => {
if (selectedRepo) {
const repo = repositories.find((r) => `${r.architecture}-${r.repository}` === selectedRepo);
if (repo) {
return repo;
}
}
return current!;
};
const handleRebuild = async (): Promise<void> => {
if (!dependency) {
return;
}
const repo = getSelectedRepo();
try {
await Client.rebuildPackages(repo, [dependency]);
onClose();
showSuccess("Success", `Repository rebuild has been run for packages which depend on ${dependency}`);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Repository rebuild failed: ${detail}`);
}
};
const handleClose = (): void => {
setDependency("");
setSelectedRepo("");
onClose();
};
return (
<Dialog open={open} onClose={handleClose} maxWidth="md" fullWidth>
<DialogTitle>Rebuild depending packages</DialogTitle>
<DialogContent>
<FormControl fullWidth margin="normal">
<InputLabel>repository</InputLabel>
<Select
value={selectedRepo || (current ? `${current.architecture}-${current.repository}` : "")}
label="repository"
onChange={(e) => setSelectedRepo(e.target.value)}
>
{repositories.map((r) => (
<MenuItem key={`${r.architecture}-${r.repository}`} value={`${r.architecture}-${r.repository}`}>
{r.repository} ({r.architecture})
</MenuItem>
))}
</Select>
</FormControl>
<TextField
label="dependency"
placeholder="packages dependency"
fullWidth
margin="normal"
value={dependency}
onChange={(e) => setDependency(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => void handleRebuild()} variant="contained" startIcon={<PlayArrowIcon />}>rebuild</Button>
</DialogActions>
</Dialog>
);
}
@@ -0,0 +1,58 @@
import React, { useState, useEffect } from "react";
import { Container, Box } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import Navbar from "components/layout/Navbar";
import Footer from "components/layout/Footer";
import PackageTable from "components/table/PackageTable";
import LoginDialog from "components/dialogs/LoginDialog";
import { useAuth } from "hooks/useAuth";
import { useRepository } from "hooks/useRepository";
import { Client } from "api/client/AhrimanClient";
import { QueryKeys } from "api/QueryKeys";
import type { InfoResponse } from "api/types/InfoResponse";
export default function AppLayout(): React.JSX.Element {
const { setAuthState } = useAuth();
const { setRepositories } = useRepository();
const [loginOpen, setLoginOpen] = useState(false);
const { data: info } = useQuery<InfoResponse>({
queryKey: QueryKeys.info,
queryFn: () => Client.fetchInfo(),
staleTime: Infinity,
});
// Sync info to contexts when loaded
useEffect(() => {
if (info) {
setAuthState({ enabled: info.auth, username: info.username ?? null });
setRepositories(info.repositories);
}
}, [info, setAuthState, setRepositories]);
return (
<Container maxWidth="xl">
<Box sx={{ display: "flex", alignItems: "center", py: 1, gap: 1 }}>
<a href="https://github.com/arcan1s/ahriman" title="logo">
<img src="/static/logo.svg" width={30} height={30} alt="" />
</a>
<Box sx={{ flex: 1 }}>
<Navbar />
</Box>
</Box>
<PackageTable
autorefreshIntervals={info?.autorefresh_intervals ?? []}
/>
<Footer
version={info?.version ?? ""}
docsEnabled={info?.docs_enabled ?? false}
indexUrl={info?.index_url}
onLoginClick={() => setLoginOpen(true)}
/>
<LoginDialog open={loginOpen} onClose={() => setLoginOpen(false)} />
</Container>
);
}
+79
View File
@@ -0,0 +1,79 @@
import type React from "react";
import { Box, Link, Button, Typography } from "@mui/material";
import GitHubIcon from "@mui/icons-material/GitHub";
import LogoutIcon from "@mui/icons-material/Logout";
import HomeIcon from "@mui/icons-material/Home";
import { useAuth } from "hooks/useAuth";
interface FooterProps {
version: string;
docsEnabled: boolean;
indexUrl?: string;
onLoginClick: () => void;
}
export default function Footer({ version, docsEnabled, indexUrl, onLoginClick }: FooterProps): React.JSX.Element {
const { enabled: authEnabled, username, logout } = useAuth();
const handleLogout = async (): Promise<void> => {
await logout();
window.location.href = "/";
};
return (
<Box
component="footer"
sx={{
display: "flex",
flexWrap: "wrap",
justifyContent: "space-between",
alignItems: "center",
borderTop: 1,
borderColor: "divider",
mt: 2,
py: 1,
}}
>
<Box sx={{ display: "flex", gap: 2, alignItems: "center" }}>
<Link href="https://github.com/arcan1s/ahriman" underline="hover" color="inherit" sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
<GitHubIcon fontSize="small" />
<Typography variant="body2">ahriman {version}</Typography>
</Link>
<Link href="https://github.com/arcan1s/ahriman/releases" underline="hover" color="text.secondary" variant="body2">
releases
</Link>
<Link href="https://github.com/arcan1s/ahriman/issues" underline="hover" color="text.secondary" variant="body2">
report a bug
</Link>
{docsEnabled && (
<Link href="/api-docs" underline="hover" color="text.secondary" variant="body2">
api
</Link>
)}
</Box>
{indexUrl && (
<Box>
<Link href={indexUrl} underline="hover" color="inherit" sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
<HomeIcon fontSize="small" />
<Typography variant="body2">repo index</Typography>
</Link>
</Box>
)}
{authEnabled && (
<Box>
{username ? (
<Button size="small" startIcon={<LogoutIcon />} onClick={() => void handleLogout()} sx={{ textTransform: "none" }}>
logout ({username})
</Button>
) : (
<Button size="small" onClick={onLoginClick} sx={{ textTransform: "none" }}>
login
</Button>
)}
</Box>
)}
</Box>
);
}
+33
View File
@@ -0,0 +1,33 @@
import type React from "react";
import { Tabs, Tab, Box } from "@mui/material";
import { useRepository } from "hooks/useRepository";
export default function Navbar(): React.JSX.Element | null {
const { repositories, current, setCurrent } = useRepository();
if (repositories.length === 0 || !current) {
return null;
}
const currentIndex = repositories.findIndex(
(r) => r.architecture === current.architecture && r.repository === current.repository,
);
return (
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
value={currentIndex >= 0 ? currentIndex : 0}
onChange={(_, newValue: number) => setCurrent(repositories[newValue])}
variant="scrollable"
scrollButtons="auto"
>
{repositories.map((repo) => (
<Tab
key={`${repo.architecture}-${repo.repository}`}
label={`${repo.repository} (${repo.architecture})`}
/>
))}
</Tabs>
</Box>
);
}
@@ -0,0 +1,188 @@
import React, { useState, useEffect, useMemo, useRef } from "react";
import { Box, Button, Menu, MenuItem, Typography } from "@mui/material";
import ListIcon from "@mui/icons-material/List";
import { useQuery } from "@tanstack/react-query";
import hljs from "highlight.js/lib/core";
import plaintext from "highlight.js/lib/languages/plaintext";
import "highlight.js/styles/github.css";
import { Client } from "api/client/AhrimanClient";
import { QueryKeys } from "api/QueryKeys";
import { formatTimestamp } from "components/common/formatTimestamp";
import CopyButton from "components/common/CopyButton";
import type { LogRecord } from "api/types/LogRecord";
import type { RepositoryId } from "api/types/RepositoryId";
hljs.registerLanguage("plaintext", plaintext);
interface LogVersion {
version: string;
processId: string;
created: number;
logs: string;
}
interface BuildLogsTabProps {
packageBase: string;
repo: RepositoryId;
refetchInterval: number | false;
}
function convertLogs(records: LogRecord[], filter?: (r: LogRecord) => boolean): string {
return records
.filter(filter || Boolean)
.map((r) => `[${new Date(r.created * 1000).toISOString()}] ${r.message}`)
.join("\n");
}
export default function BuildLogsTab({ packageBase, repo, refetchInterval }: BuildLogsTabProps): React.JSX.Element {
const [activeIndex, setActiveIndex] = useState(0);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const codeRef = useRef<HTMLElement>(null);
const preRef = useRef<HTMLElement>(null);
const initialScrollDone = useRef(false);
const { data: allLogs } = useQuery<LogRecord[]>({
queryKey: QueryKeys.logs(packageBase, repo),
queryFn: () => Client.fetchLogs(packageBase, repo),
enabled: !!packageBase,
});
// Build version selectors from all logs
const versions = useMemo<LogVersion[]>(() => {
if (!allLogs || allLogs.length === 0) {
return [];
}
const grouped: Record<string, LogRecord & { minCreated: number }> = {};
for (const record of allLogs) {
const key = `${record.version}-${record.process_id}`;
if (!grouped[key]) {
grouped[key] = { ...record, minCreated: record.created };
} else {
grouped[key].minCreated = Math.min(grouped[key].minCreated, record.created);
}
}
return Object.values(grouped)
.sort((a, b) => b.minCreated - a.minCreated)
.map((v) => ({
version: v.version,
processId: v.process_id,
created: v.minCreated,
logs: convertLogs(
allLogs,
(r) => r.version === v.version && r.process_id === v.process_id,
),
}));
}, [allLogs]);
// Reset active index when data changes
const [prevAllLogs, setPrevAllLogs] = useState(allLogs);
if (allLogs !== prevAllLogs) {
setPrevAllLogs(allLogs);
setActiveIndex(0);
initialScrollDone.current = false;
}
// Refresh active version logs when using auto-refresh
const activeVersion = versions[activeIndex];
const { data: versionLogs } = useQuery<LogRecord[]>({
queryKey: activeVersion
? QueryKeys.logsVersion(packageBase, repo, activeVersion.version, activeVersion.processId)
: ["logs-none"],
queryFn: () =>
activeVersion
? Client.fetchLogs(packageBase, repo, activeVersion.version, activeVersion.processId)
: Promise.resolve([]),
enabled: !!activeVersion && !!refetchInterval,
refetchInterval,
});
// Derive displayed logs: prefer fresh polled data when available
const displayedLogs = useMemo(() => {
if (versionLogs && versionLogs.length > 0) {
return convertLogs(versionLogs);
}
return activeVersion?.logs ?? "";
}, [versionLogs, activeVersion]);
// Highlight code
useEffect(() => {
if (codeRef.current && displayedLogs) {
codeRef.current.textContent = displayedLogs;
delete codeRef.current.dataset.highlighted;
hljs.highlightElement(codeRef.current);
}
}, [displayedLogs]);
// Auto-scroll: always scroll to bottom on initial load, then only if already near bottom
useEffect(() => {
if (preRef.current && displayedLogs) {
const el = preRef.current;
if (!initialScrollDone.current) {
el.scrollTop = el.scrollHeight;
initialScrollDone.current = true;
} else {
const isAtBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 50;
if (isAtBottom) {
el.scrollTop = el.scrollHeight;
}
}
}
}, [displayedLogs]);
return (
<Box sx={{ display: "flex", gap: 1, mt: 1 }}>
<Box>
<Button
size="small"
startIcon={<ListIcon />}
onClick={(e) => setAnchorEl(e.currentTarget)}
/>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
>
{versions.map((v, idx) => (
<MenuItem
key={`${v.version}-${v.processId}`}
selected={idx === activeIndex}
onClick={() => {
setActiveIndex(idx);
setAnchorEl(null);
initialScrollDone.current = false;
}}
>
<Typography variant="body2">{formatTimestamp(v.created)}</Typography>
</MenuItem>
))}
{versions.length === 0 && (
<MenuItem disabled>No logs available</MenuItem>
)}
</Menu>
</Box>
<Box sx={{ flex: 1, position: "relative" }}>
<Box
ref={preRef}
component="pre"
sx={{
backgroundColor: "#f6f8fa",
p: 2,
borderRadius: 1,
overflow: "auto",
maxHeight: 400,
fontSize: "0.8rem",
fontFamily: "monospace",
}}
>
<code ref={codeRef} className="language-plaintext" />
</Box>
<Box sx={{ position: "absolute", top: 8, right: 8 }}>
<CopyButton getText={() => displayedLogs} />
</Box>
</Box>
</Box>
);
}
@@ -0,0 +1,60 @@
import React, { useEffect, useRef } from "react";
import { Box } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import hljs from "highlight.js/lib/core";
import diff from "highlight.js/lib/languages/diff";
import "highlight.js/styles/github.css";
import { Client } from "api/client/AhrimanClient";
import { QueryKeys } from "api/QueryKeys";
import CopyButton from "components/common/CopyButton";
import type { Changes } from "api/types/Changes";
import type { RepositoryId } from "api/types/RepositoryId";
hljs.registerLanguage("diff", diff);
interface ChangesTabProps {
packageBase: string;
repo: RepositoryId;
}
export default function ChangesTab({ packageBase, repo }: ChangesTabProps): React.JSX.Element {
const codeRef = useRef<HTMLElement>(null);
const { data } = useQuery<Changes>({
queryKey: QueryKeys.changes(packageBase, repo),
queryFn: () => Client.fetchChanges(packageBase, repo),
enabled: !!packageBase,
});
const changesText = data?.changes ?? "";
useEffect(() => {
if (codeRef.current) {
codeRef.current.textContent = changesText;
delete codeRef.current.dataset.highlighted;
hljs.highlightElement(codeRef.current);
}
}, [changesText]);
return (
<Box sx={{ position: "relative", mt: 1 }}>
<Box
component="pre"
sx={{
backgroundColor: "#f6f8fa",
p: 2,
borderRadius: 1,
overflow: "auto",
maxHeight: 400,
fontSize: "0.8rem",
fontFamily: "monospace",
}}
>
<code ref={codeRef} className="language-diff" />
</Box>
<Box sx={{ position: "absolute", top: 8, right: 8 }}>
<CopyButton getText={() => changesText} />
</Box>
</Box>
);
}
@@ -0,0 +1,60 @@
import type React from "react";
import { Box } from "@mui/material";
import { DataGrid, type GridColDef } from "@mui/x-data-grid";
import { useQuery } from "@tanstack/react-query";
import EventDurationLineChart from "components/charts/EventDurationLineChart";
import { Client } from "api/client/AhrimanClient";
import { QueryKeys } from "api/QueryKeys";
import { formatTimestamp } from "components/common/formatTimestamp";
import type { Event } from "api/types/Event";
import type { RepositoryId } from "api/types/RepositoryId";
interface EventsTabProps {
packageBase: string;
repo: RepositoryId;
}
interface EventRow {
id: number;
timestamp: string;
event: string;
message: string;
}
const columns: GridColDef<EventRow>[] = [
{ field: "timestamp", headerName: "date", width: 180, align: "right", headerAlign: "right" },
{ field: "event", headerName: "event", flex: 1 },
{ field: "message", headerName: "description", flex: 2 },
];
export default function EventsTab({ packageBase, repo }: EventsTabProps): React.JSX.Element {
const { data: events = [] } = useQuery<Event[]>({
queryKey: QueryKeys.events(repo, packageBase),
queryFn: () => Client.fetchEvents(repo, packageBase, 30),
enabled: !!packageBase,
});
const rows: EventRow[] = events.map((e, idx) => ({
id: idx,
timestamp: formatTimestamp(e.created),
event: e.event,
message: e.message ?? "",
}));
return (
<Box sx={{ mt: 1 }}>
<EventDurationLineChart events={events} />
<DataGrid
rows={rows}
columns={columns}
density="compact"
initialState={{
sorting: { sortModel: [{ field: "timestamp", sort: "desc" }] },
}}
pageSizeOptions={[10, 25]}
sx={{ height: 300, mt: 1 }}
disableRowSelectionOnClick
/>
</Box>
);
}
@@ -0,0 +1,317 @@
import React, { useState, useMemo, useCallback, useEffect } from "react";
import {
DataGrid,
GridToolbarQuickFilter,
GridToolbarFilterButton,
type GridColDef,
type GridFilterModel,
type GridRowSelectionModel,
type GridRenderCellParams,
} from "@mui/x-data-grid";
import { Box, Link, Stack } from "@mui/material";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import PackageTableToolbar from "components/table/PackageTableToolbar";
import StatusCell from "components/table/StatusCell";
import DashboardDialog from "components/dialogs/DashboardDialog";
import PackageAddDialog from "components/dialogs/PackageAddDialog";
import PackageRebuildDialog from "components/dialogs/PackageRebuildDialog";
import KeyImportDialog from "components/dialogs/KeyImportDialog";
import PackageInfoDialog from "components/dialogs/PackageInfoDialog";
import { useRepository } from "hooks/useRepository";
import { useAuth } from "hooks/useAuth";
import { useNotification } from "hooks/useNotification";
import { useAutoRefresh } from "hooks/useAutoRefresh";
import { useLocalStorage } from "hooks/useLocalStorage";
import { Client } from "api/client/AhrimanClient";
import { ApiError } from "api/client/ApiError";
import { QueryKeys } from "api/QueryKeys";
import { formatTimestamp } from "components/common/formatTimestamp";
import type { AutoRefreshInterval } from "api/types/AutoRefreshInterval";
import type { InternalStatus } from "api/types/InternalStatus";
import type { PackageRow } from "api/types/PackageRow";
import type { PackageStatus } from "api/types/PackageStatus";
interface PackageTableProps {
autorefreshIntervals: AutoRefreshInterval[];
}
function extractListProperties(pkg: PackageStatus["package"], property: "groups" | "licenses"): string[] {
return [
...new Set(
Object.values(pkg.packages)
.flatMap((p) => p[property] ?? []),
),
].sort();
}
function toRow(ps: PackageStatus): PackageRow {
return {
id: ps.package.base,
base: ps.package.base,
webUrl: ps.package.remote.web_url ?? undefined,
version: ps.package.version,
packages: Object.keys(ps.package.packages).sort(),
groups: extractListProperties(ps.package, "groups"),
licenses: extractListProperties(ps.package, "licenses"),
packager: ps.package.packager ?? "",
timestamp: formatTimestamp(ps.status.timestamp),
timestampValue: ps.status.timestamp,
status: ps.status.status,
};
}
const PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
function SearchToolbar(): React.JSX.Element {
return (
<Stack direction="row" alignItems="center" spacing={1} sx={{ px: 1, py: 0.5 }}>
<GridToolbarFilterButton />
<GridToolbarQuickFilter debounceMs={300} sx={{ flex: 1 }} />
</Stack>
);
}
export default function PackageTable({ autorefreshIntervals }: PackageTableProps): React.JSX.Element {
const { current } = useRepository();
const { enabled: authEnabled, username } = useAuth();
const { showSuccess, showError } = useNotification();
const queryClient = useQueryClient();
const hasAuth = !authEnabled || username !== null;
const defaultInterval = autorefreshIntervals.find((i) => i.is_active)?.interval ?? 0;
const autoRefresh = useAutoRefresh("table-autoreload-button", defaultInterval);
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
const [dialogOpen, setDialogOpen] = useState<string | null>(null);
const [selectedPackage, setSelectedPackage] = useState<string | null>(null);
const [paginationModel, setPaginationModel] = useLocalStorage("ahriman-packages-pagination", {
pageSize: 10,
page: 0,
});
const [columnVisibility, setColumnVisibility] = useLocalStorage<Record<string, boolean>>(
"ahriman-packages-columns",
{ groups: false, licenses: false, packager: false },
);
const [filterModel, setFilterModel] = useLocalStorage<GridFilterModel>(
"ahriman-packages-filters",
{ items: [] },
);
// Pause auto-refresh when dialog is open
const isDialogOpen = dialogOpen !== null || selectedPackage !== null;
const setPaused = autoRefresh.setPaused;
useEffect(() => {
setPaused(isDialogOpen);
}, [isDialogOpen, setPaused]);
const { data: packages = [], isLoading } = useQuery<PackageStatus[]>({
queryKey: current ? QueryKeys.packages(current) : ["packages"],
queryFn: () => (current ? Client.fetchPackages(current) : Promise.resolve([])),
enabled: !!current,
refetchInterval: autoRefresh.refetchInterval,
});
const { data: status } = useQuery<InternalStatus>({
queryKey: current ? QueryKeys.status(current) : ["status"],
queryFn: () => Client.fetchStatus(current!),
enabled: !!current,
refetchInterval: autoRefresh.refetchInterval,
});
const rows = useMemo(() => packages.map(toRow), [packages]);
const handleReload = useCallback(() => {
if (!current) {
return;
}
void queryClient.invalidateQueries({ queryKey: QueryKeys.packages(current) });
void queryClient.invalidateQueries({ queryKey: QueryKeys.status(current) });
}, [current, queryClient]);
const handleUpdate = useCallback(async () => {
if (!current) {
return;
}
const selected = selectionModel as string[];
try {
if (selected.length === 0) {
await Client.updatePackages(current, { packages: [] });
showSuccess("Success", "Repository update has been run");
} else {
await Client.addPackages(current, { packages: selected });
showSuccess("Success", `Run update for packages ${selected.join(", ")}`);
}
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Packages update failed: ${detail}`);
}
}, [current, selectionModel, showSuccess, showError]);
const handleRefreshDb = useCallback(async () => {
if (!current) {
return;
}
try {
await Client.updatePackages(current, { packages: [], refresh: true, aur: false, local: false, manual: false });
showSuccess("Success", "Pacman database update has been requested");
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Could not update pacman databases: ${detail}`);
}
}, [current, showSuccess, showError]);
const handleRemove = useCallback(async () => {
if (!current) {
return;
}
const selected = selectionModel as string[];
if (selected.length === 0) {
return;
}
try {
await Client.removePackages(current, selected);
showSuccess("Success", `Packages ${selected.join(", ")} have been removed`);
setSelectionModel([]);
} catch (e) {
const detail = e instanceof ApiError ? e.detail : String(e);
showError("Action failed", `Could not remove packages: ${detail}`);
}
}, [current, selectionModel, showSuccess, showError]);
const columns: GridColDef<PackageRow>[] = useMemo(
() => [
{
field: "base",
headerName: "package base",
flex: 1,
minWidth: 150,
renderCell: (params: GridRenderCellParams<PackageRow>) =>
params.row.webUrl ? (
<Link href={params.row.webUrl} target="_blank" rel="noopener" underline="hover">
{params.value as string}
</Link>
) : (
params.value as string
),
},
{ field: "version", headerName: "version", width: 180, align: "right", headerAlign: "right" },
{
field: "packages",
headerName: "packages",
flex: 1,
minWidth: 120,
valueGetter: (value: string[]) => (value ?? []).join(" "),
renderCell: (params: GridRenderCellParams<PackageRow>) => (params.row.packages ?? []).map((item, i, arr) => (
<React.Fragment key={item}>{item}{i < arr.length - 1 && <br />}</React.Fragment>
)),
sortComparator: (v1: string, v2: string) => v1.localeCompare(v2),
},
{
field: "groups",
headerName: "groups",
width: 150,
valueGetter: (value: string[]) => (value ?? []).join(" "),
renderCell: (params: GridRenderCellParams<PackageRow>) => (params.row.groups ?? []).map((item, i, arr) => (
<React.Fragment key={item}>{item}{i < arr.length - 1 && <br />}</React.Fragment>
)),
},
{
field: "licenses",
headerName: "licenses",
width: 150,
valueGetter: (value: string[]) => (value ?? []).join(" "),
renderCell: (params: GridRenderCellParams<PackageRow>) => (params.row.licenses ?? []).map((item, i, arr) => (
<React.Fragment key={item}>{item}{i < arr.length - 1 && <br />}</React.Fragment>
)),
},
{ field: "packager", headerName: "packager", width: 150 },
{
field: "timestamp",
headerName: "last update",
width: 180,
align: "right",
headerAlign: "right",
},
{
field: "status",
headerName: "status",
width: 120,
align: "center",
headerAlign: "center",
renderCell: (params: GridRenderCellParams<PackageRow>) => <StatusCell status={params.row.status} />,
},
],
[],
);
return (
<Box>
<PackageTableToolbar
hasSelection={(selectionModel as string[]).length > 0}
hasAuth={hasAuth}
repoStatus={status?.status.status}
autorefreshIntervals={autorefreshIntervals}
autoRefreshEnabled={autoRefresh.enabled}
autoRefreshInterval={autoRefresh.interval}
onAutoRefreshToggle={autoRefresh.setEnabled}
onAutoRefreshIntervalChange={autoRefresh.setInterval}
onDashboardClick={() => setDialogOpen("dashboard")}
onAddClick={() => setDialogOpen("add")}
onUpdateClick={() => void handleUpdate()}
onRefreshDbClick={() => void handleRefreshDb()}
onRebuildClick={() => setDialogOpen("rebuild")}
onRemoveClick={() => void handleRemove()}
onKeyImportClick={() => setDialogOpen("keyImport")}
onReloadClick={handleReload}
/>
<DataGrid
rows={rows}
columns={columns}
loading={isLoading}
getRowHeight={() => "auto"}
checkboxSelection
disableRowSelectionOnClick
rowSelectionModel={selectionModel}
onRowSelectionModelChange={setSelectionModel}
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
pageSizeOptions={PAGE_SIZE_OPTIONS}
columnVisibilityModel={columnVisibility}
onColumnVisibilityModelChange={setColumnVisibility}
filterModel={filterModel}
onFilterModelChange={setFilterModel}
slots={{ toolbar: SearchToolbar }}
initialState={{
sorting: { sortModel: [{ field: "base", sort: "asc" }] },
}}
onRowClick={(params: { row: PackageRow }, event) => {
const target = event.target as HTMLElement;
// Don't open info dialog when clicking checkbox or link
if (target.closest("input[type=\"checkbox\"]") || target.closest("a")) {
return;
}
setSelectedPackage(params.row.id);
}}
sx={{
"& .MuiDataGrid-row": { cursor: "pointer" },
height: 600,
}}
density="compact"
/>
<DashboardDialog open={dialogOpen === "dashboard"} onClose={() => setDialogOpen(null)} />
<PackageAddDialog open={dialogOpen === "add"} onClose={() => setDialogOpen(null)} />
<PackageRebuildDialog open={dialogOpen === "rebuild"} onClose={() => setDialogOpen(null)} />
<KeyImportDialog open={dialogOpen === "keyImport"} onClose={() => setDialogOpen(null)} />
<PackageInfoDialog
packageBase={selectedPackage}
open={selectedPackage !== null}
onClose={() => setSelectedPackage(null)}
autorefreshIntervals={autorefreshIntervals}
/>
</Box>
);
}
@@ -0,0 +1,133 @@
import React, { useState } from "react";
import { Button, Menu, MenuItem, Box, Tooltip, IconButton, Divider } from "@mui/material";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import InventoryIcon from "@mui/icons-material/Inventory";
import AddIcon from "@mui/icons-material/Add";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import DownloadIcon from "@mui/icons-material/Download";
import ReplayIcon from "@mui/icons-material/Replay";
import DeleteIcon from "@mui/icons-material/Delete";
import VpnKeyIcon from "@mui/icons-material/VpnKey";
import RefreshIcon from "@mui/icons-material/Refresh";
import AutoRefreshControl from "components/common/AutoRefreshControl";
import type { AutoRefreshInterval } from "api/types/AutoRefreshInterval";
import type { BuildStatus } from "api/types/BuildStatus";
import { StatusColors } from "theme/status/StatusColors";
interface PackageTableToolbarProps {
hasSelection: boolean;
hasAuth: boolean;
repoStatus?: BuildStatus;
autorefreshIntervals: AutoRefreshInterval[];
autoRefreshEnabled: boolean;
autoRefreshInterval: number;
onAutoRefreshToggle: (enabled: boolean) => void;
onAutoRefreshIntervalChange: (interval: number) => void;
onDashboardClick: () => void;
onAddClick: () => void;
onUpdateClick: () => void;
onRefreshDbClick: () => void;
onRebuildClick: () => void;
onRemoveClick: () => void;
onKeyImportClick: () => void;
onReloadClick: () => void;
}
export default function PackageTableToolbar({
hasSelection,
hasAuth,
repoStatus,
autorefreshIntervals,
autoRefreshEnabled,
autoRefreshInterval,
onAutoRefreshToggle,
onAutoRefreshIntervalChange,
onDashboardClick,
onAddClick,
onUpdateClick,
onRefreshDbClick,
onRebuildClick,
onRemoveClick,
onKeyImportClick,
onReloadClick,
}: PackageTableToolbarProps): React.JSX.Element {
const [packagesAnchorEl, setPackagesAnchorEl] = useState<null | HTMLElement>(null);
return (
<Box sx={{ display: "flex", gap: 1, mb: 1, flexWrap: "wrap", alignItems: "center" }}>
<Tooltip title="System health">
<IconButton
onClick={onDashboardClick}
sx={{
borderColor: repoStatus ? StatusColors[repoStatus] : undefined,
borderWidth: 1,
borderStyle: "solid",
color: repoStatus ? StatusColors[repoStatus] : undefined,
}}
>
<InfoOutlinedIcon />
</IconButton>
</Tooltip>
{hasAuth && (
<>
<Button
variant="contained"
startIcon={<InventoryIcon />}
onClick={(e) => setPackagesAnchorEl(e.currentTarget)}
>
packages
</Button>
<Menu
anchorEl={packagesAnchorEl}
open={Boolean(packagesAnchorEl)}
onClose={() => setPackagesAnchorEl(null)}
>
<MenuItem onClick={() => {
setPackagesAnchorEl(null); onAddClick();
}}>
<AddIcon fontSize="small" sx={{ mr: 1 }} /> add
</MenuItem>
<MenuItem onClick={() => {
setPackagesAnchorEl(null); onUpdateClick();
}}>
<PlayArrowIcon fontSize="small" sx={{ mr: 1 }} /> update
</MenuItem>
<MenuItem onClick={() => {
setPackagesAnchorEl(null); onRefreshDbClick();
}}>
<DownloadIcon fontSize="small" sx={{ mr: 1 }} /> update pacman databases
</MenuItem>
<MenuItem onClick={() => {
setPackagesAnchorEl(null); onRebuildClick();
}}>
<ReplayIcon fontSize="small" sx={{ mr: 1 }} /> rebuild
</MenuItem>
<Divider />
<MenuItem onClick={() => {
setPackagesAnchorEl(null); onRemoveClick();
}} disabled={!hasSelection}>
<DeleteIcon fontSize="small" sx={{ mr: 1 }} /> remove
</MenuItem>
</Menu>
<Button variant="contained" color="info" startIcon={<VpnKeyIcon />} onClick={onKeyImportClick}>
import key
</Button>
</>
)}
<Button variant="outlined" color="secondary" startIcon={<RefreshIcon />} onClick={onReloadClick}>
reload
</Button>
<AutoRefreshControl
intervals={autorefreshIntervals}
enabled={autoRefreshEnabled}
currentInterval={autoRefreshInterval}
onToggle={onAutoRefreshToggle}
onIntervalChange={onAutoRefreshIntervalChange}
/>
</Box>
);
}
@@ -0,0 +1,22 @@
import type React from "react";
import { Chip } from "@mui/material";
import type { BuildStatus } from "api/types/BuildStatus";
import { StatusColors } from "theme/status/StatusColors";
interface StatusCellProps {
status: BuildStatus;
}
export default function StatusCell({ status }: StatusCellProps): React.JSX.Element {
return (
<Chip
label={status}
size="small"
sx={{
backgroundColor: StatusColors[status],
color: "#fff",
fontWeight: 500,
}}
/>
);
}
+14
View File
@@ -0,0 +1,14 @@
import { createContext } from "react";
interface AuthState {
enabled: boolean;
username: string | null;
}
export interface AuthContextValue extends AuthState {
setAuthState: (state: AuthState) => void;
login: (username: string, password: string) => Promise<void>;
logout: () => Promise<void>;
}
export const AuthContext = createContext<AuthContextValue | null>(null);
+23
View File
@@ -0,0 +1,23 @@
import React, { useState, useCallback, type ReactNode } from "react";
import { Client } from "api/client/AhrimanClient";
import { AuthContext } from "contexts/AuthContext";
export function AuthProvider({ children }: { children: ReactNode }): React.JSX.Element {
const [state, setState] = useState({ enabled: false, username: null as string | null });
const login = useCallback(async (username: string, password: string) => {
await Client.login({ username, password });
setState((prev) => ({ ...prev, username }));
}, []);
const doLogout = useCallback(async () => {
await Client.logout();
setState((prev) => ({ ...prev, username: null }));
}, []);
return (
<AuthContext.Provider value={{ ...state, setAuthState: setState, login, logout: doLogout }}>
{children}
</AuthContext.Provider>
);
}
@@ -0,0 +1,8 @@
import { createContext } from "react";
export interface NotificationContextValue {
showSuccess: (title: string, message: string) => void;
showError: (title: string, message: string) => void;
}
export const NotificationContext = createContext<NotificationContextValue | null>(null);
@@ -0,0 +1,54 @@
import React, { useState, useCallback, type ReactNode } from "react";
import { Snackbar, Alert, type AlertColor } from "@mui/material";
import { NotificationContext } from "contexts/NotificationContext";
interface Notification {
id: number;
title: string;
message: string;
severity: AlertColor;
}
let nextId = 0;
export function NotificationProvider({ children }: { children: ReactNode }): React.JSX.Element {
const [notifications, setNotifications] = useState<Notification[]>([]);
const addNotification = useCallback((title: string, message: string, severity: AlertColor) => {
const id = nextId++;
setNotifications((prev) => [...prev, { id, title, message, severity }]);
}, []);
const removeNotification = useCallback((id: number) => {
setNotifications((prev) => prev.filter((n) => n.id !== id));
}, []);
const showSuccess = useCallback(
(title: string, message: string) => addNotification(title, message, "success"),
[addNotification],
);
const showError = useCallback(
(title: string, message: string) => addNotification(title, message, "error"),
[addNotification],
);
return (
<NotificationContext.Provider value={{ showSuccess, showError }}>
{children}
{notifications.map((n) => (
<Snackbar
key={n.id}
open
autoHideDuration={5000}
onClose={() => removeNotification(n.id)}
anchorOrigin={{ vertical: "top", horizontal: "center" }}
>
<Alert onClose={() => removeNotification(n.id)} severity={n.severity} variant="filled" sx={{ width: "100%", maxWidth: 500 }}>
<strong>{n.title}</strong>
{n.message && ` - ${n.message}`}
</Alert>
</Snackbar>
))}
</NotificationContext.Provider>
);
}
@@ -0,0 +1,11 @@
import { createContext } from "react";
import type { RepositoryId } from "api/types/RepositoryId";
export interface RepositoryContextValue {
repositories: RepositoryId[];
current: RepositoryId | null;
setRepositories: (repos: RepositoryId[]) => void;
setCurrent: (repo: RepositoryId) => void;
}
export const RepositoryContext = createContext<RepositoryContextValue | null>(null);
@@ -0,0 +1,47 @@
import React, { useState, useCallback, useEffect, type ReactNode } from "react";
import type { RepositoryId } from "api/types/RepositoryId";
import { RepositoryContext } from "contexts/RepositoryContext";
function repoId(repo: RepositoryId): string {
return `${repo.architecture}-${repo.repository}`;
}
export function RepositoryProvider({ children }: { children: ReactNode }): React.JSX.Element {
const [repositories, setRepositories] = useState<RepositoryId[]>([]);
const [current, setCurrentState] = useState<RepositoryId | null>(null);
const setCurrent = useCallback((repo: RepositoryId) => {
setCurrentState(repo);
window.location.hash = repoId(repo);
}, []);
// Sync current repository when repositories list changes
const [prevRepositories, setPrevRepositories] = useState(repositories);
if (repositories !== prevRepositories) {
setPrevRepositories(repositories);
if (repositories.length > 0) {
const hash = window.location.hash.replace("#", "");
const match = repositories.find((r) => repoId(r) === hash);
setCurrentState(match || repositories[0]);
}
}
// Listen for hash changes
useEffect(() => {
const handler = (): void => {
const hash = window.location.hash.replace("#", "");
const match = repositories.find((r) => repoId(r) === hash);
if (match) {
setCurrentState(match);
}
};
window.addEventListener("hashchange", handler);
return () => window.removeEventListener("hashchange", handler);
}, [repositories]);
return (
<RepositoryContext.Provider value={{ repositories, current, setRepositories, setCurrent }}>
{children}
</RepositoryContext.Provider>
);
}
+10
View File
@@ -0,0 +1,10 @@
import { useContext } from "react";
import { AuthContext, type AuthContextValue } from "contexts/AuthContext";
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) {
throw new Error("useAuth must be used within AuthProvider");
}
return ctx;
}
+52
View File
@@ -0,0 +1,52 @@
import { useState, useCallback, type Dispatch, type SetStateAction } from "react";
import { useLocalStorage } from "hooks/useLocalStorage";
interface AutoRefreshState {
enabled: boolean;
interval: number;
}
interface AutoRefreshResult {
enabled: boolean;
interval: number;
paused: boolean;
refetchInterval: number | false;
setEnabled: (enabled: boolean) => void;
setInterval: (interval: number) => void;
setPaused: Dispatch<SetStateAction<boolean>>;
}
export function useAutoRefresh(key: string, defaultInterval: number = 0): AutoRefreshResult {
const [stored, setStored] = useLocalStorage<AutoRefreshState>(`ahriman-${key}`, {
enabled: defaultInterval > 0,
interval: defaultInterval,
});
const [paused, setPaused] = useState(false);
const refetchInterval: number | false = stored.enabled && !paused && stored.interval > 0 ? stored.interval : false;
const setEnabled = useCallback(
(enabled: boolean) => {
setStored((prev) => ({ ...prev, enabled }));
},
[setStored],
);
const setInterval = useCallback(
(interval: number) => {
setStored({ enabled: true, interval });
},
[setStored],
);
return {
enabled: stored.enabled,
interval: stored.interval,
paused,
refetchInterval,
setEnabled,
setInterval,
setPaused,
};
}
+12
View File
@@ -0,0 +1,12 @@
import { useState, useEffect } from "react";
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
+25
View File
@@ -0,0 +1,25 @@
import { useState, useCallback, type Dispatch, type SetStateAction } from "react";
export function useLocalStorage<T>(key: string, initialValue: T): [T, Dispatch<SetStateAction<T>>] {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch {
return initialValue;
}
});
const setValue: Dispatch<SetStateAction<T>> = useCallback(
(value) => {
setStoredValue((prev) => {
const nextValue = value instanceof Function ? value(prev) : value;
window.localStorage.setItem(key, JSON.stringify(nextValue));
return nextValue;
});
},
[key],
);
return [storedValue, setValue];
}
+10
View File
@@ -0,0 +1,10 @@
import { useContext } from "react";
import { NotificationContext, type NotificationContextValue } from "contexts/NotificationContext";
export function useNotification(): NotificationContextValue {
const ctx = useContext(NotificationContext);
if (!ctx) {
throw new Error("useNotification must be used within NotificationProvider");
}
return ctx;
}
+10
View File
@@ -0,0 +1,10 @@
import { useContext } from "react";
import { RepositoryContext, type RepositoryContextValue } from "contexts/RepositoryContext";
export function useRepository(): RepositoryContextValue {
const ctx = useContext(RepositoryContext);
if (!ctx) {
throw new Error("useRepository must be used within RepositoryProvider");
}
return ctx;
}
+9
View File
@@ -0,0 +1,9 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
+67
View File
@@ -0,0 +1,67 @@
import { createTheme } from "@mui/material/styles";
// Bootswatch Cosmo-inspired palette
const Theme = createTheme({
palette: {
primary: {
main: "#2780e3",
contrastText: "#fff",
},
secondary: {
main: "#373a3c",
contrastText: "#fff",
},
success: {
main: "#3fb618",
contrastText: "#fff",
},
error: {
main: "#ff0039",
contrastText: "#fff",
},
warning: {
main: "#ff7518",
contrastText: "#fff",
},
info: {
main: "#9954bb",
contrastText: "#fff",
},
background: {
default: "#fff",
paper: "#fff",
},
text: {
primary: "#373a3c",
secondary: "#6c757d",
},
},
typography: {
fontFamily: "\"Source Sans Pro\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
fontSize: 14,
},
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: "none",
},
},
},
MuiTab: {
styleOverrides: {
root: {
textTransform: "none",
},
},
},
MuiDialog: {
defaultProps: {
maxWidth: "lg",
fullWidth: true,
},
},
},
});
export default Theme;
+9
View File
@@ -0,0 +1,9 @@
import type { BuildStatus } from "api/types/BuildStatus";
export const ChartColors: Record<BuildStatus, string> = {
unknown: "rgb(55, 58, 60)",
pending: "rgb(255, 117, 24)",
building: "rgb(255, 117, 24)",
failed: "rgb(255, 0, 57)",
success: "rgb(63, 182, 24)",
};
@@ -0,0 +1,9 @@
import type { BuildStatus } from "api/types/BuildStatus";
export const StatusBackgrounds: Record<BuildStatus, string> = {
unknown: "rgba(55, 58, 60, 0.1)",
pending: "rgba(255, 117, 24, 0.1)",
building: "rgba(255, 117, 24, 0.1)",
failed: "rgba(255, 0, 57, 0.1)",
success: "rgba(63, 182, 24, 0.1)",
};
@@ -0,0 +1,9 @@
import type { BuildStatus } from "api/types/BuildStatus";
export const StatusColors: Record<BuildStatus, string> = {
unknown: "#373a3c",
pending: "#ff7518",
building: "#ff7518",
failed: "#ff0039",
success: "#3fb618",
};
@@ -0,0 +1,9 @@
import type { BuildStatus } from "api/types/BuildStatus";
export const StatusHeaderStyles: Record<BuildStatus, { backgroundColor: string; color: string }> = {
unknown: { backgroundColor: "#373a3c", color: "#fff" },
pending: { backgroundColor: "#ff7518", color: "#fff" },
building: { backgroundColor: "#ff7518", color: "#fff" },
failed: { backgroundColor: "#ff0039", color: "#fff" },
success: { backgroundColor: "#3fb618", color: "#fff" },
};
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": "src"
},
"include": ["src"]
}
+41
View File
@@ -0,0 +1,41 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import path from "path";
import fs from "fs";
import type { Plugin } from "vite";
function renameIndexHtml(): Plugin {
return {
name: "rename-index-html",
closeBundle() {
const outDir = path.resolve(__dirname, "../package/share/ahriman/templates");
const src = path.join(outDir, "index.html");
const dest = path.join(outDir, "build-status.jinja2");
if (fs.existsSync(src)) {
fs.renameSync(src, dest);
}
},
};
}
export default defineConfig({
plugins: [react(), tsconfigPaths(), renameIndexHtml()],
base: "/",
build: {
outDir: path.resolve(__dirname, "../package/share/ahriman/templates"),
emptyOutDir: false,
rollupOptions: {
output: {
entryFileNames: "static/[name].js",
chunkFileNames: "static/[name].js",
assetFileNames: "static/[name].[ext]",
},
},
},
server: {
proxy: {
"/api": "http://localhost:8080",
},
},
});
@@ -1,191 +1,14 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ahriman</title> <title>ahriman</title>
<link rel="icon" href="/static/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <script type="module" crossorigin src="/static/index.js"></script>
<link rel="stylesheet" crossorigin href="/static/index.css">
{% include "utils/style.jinja2" %}
{% include "user-style.jinja2" ignore missing %}
</head> </head>
<body> <body>
<div id="root"></div>
{% include "utils/bootstrap-scripts.jinja2" %}
<div class="container">
<nav class="navbar navbar-expand-lg">
<div class="navbar-brand"><a href="https://github.com/arcan1s/ahriman" title="logo"><img src="/static/logo.svg" width="30" height="30" alt=""></a></div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#repositories-navbar" aria-controls="repositories-navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div id="repositories-navbar" class="collapse navbar-collapse">
<ul id="repositories" class="nav nav-tabs">
{% for repository in repositories %}
<li class="nav-item">
<a id="{{ repository.id }}-link" class="nav-link" href="#{{ repository.id }}" data-repository="{{ repository.repository }}" data-architecture="{{ repository.architecture }}">{{ repository.repository }} ({{ repository.architecture }})</a>
</li>
{% endfor %}
</ul>
</div>
</nav>
</div>
<div id="alert-placeholder" class="toast-container p3 top-0 start-50 translate-middle-x"></div>
<div class="container">
<div id="toolbar" class="dropdown">
<button id="dashboard-button" type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#dashboard-modal">
<i class="bi bi-info-circle"></i>
</button>
{% if not auth.enabled or auth.username is not none %}
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-box"></i><span class="d-none d-sm-inline"> packages</span>
</button>
<ul class="dropdown-menu">
<li>
<button id="package-add-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-add-modal">
<i class="bi bi-plus"></i> add
</button>
</li>
<li>
<button id="package-update-button" class="btn dropdown-item" onclick="packagesUpdate()">
<i class="bi bi-play"></i> update
</button>
</li>
<li>
<button id="update-repositories-button" class="btn dropdown-item" onclick="refreshDatabases()">
<i class="bi bi-arrow-down-circle"></i> update pacman databases
</button>
</li>
<li>
<button id="package-rebuild-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-rebuild-modal">
<i class="bi bi-arrow-clockwise"></i> rebuild
</button>
</li>
<li>
<button id="package-remove-button" class="btn dropdown-item" onclick="packagesRemove()" disabled>
<i class="bi bi-trash"></i> remove
</button>
</li>
</ul>
<button id="key-import-button" type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#key-import-modal">
<i class="bi bi-key"></i><span class="d-none d-sm-inline"> import key</span>
</button>
{% endif %}
<button type="button" class="btn btn-secondary" onclick="reload()">
<i class="bi bi-arrow-clockwise"></i><span class="d-none d-sm-inline"> reload</span>
</button>
{% if autorefresh_intervals %}
<div class="btn-group">
<input id="table-autoreload-button" type="checkbox" class="btn-check" autocomplete="off" onclick="toggleTableAutoReload()" checked>
<label for="table-autoreload-button" class="btn btn-outline-secondary" title="toggle auto reload"><i class="bi bi-clock"></i></label>
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">select interval</span>
</button>
<ul id="table-autoreload-input" class="dropdown-menu">
{% for interval in autorefresh_intervals %}
<li><a class="dropdown-item {{ "active" if interval.is_active }}" onclick="toggleTableAutoReload({{ interval.interval }})" data-interval="{{ interval.interval }}">{{ interval.text }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
<table id="packages"
data-classes="table table-hover"
data-cookie="true"
data-cookie-id-table="ahriman-packages"
data-cookie-storage="localStorage"
data-export-options='{"fileName": "packages"}'
data-filter-control="true"
data-filter-control-visible="false"
data-page-list="[10, 25, 50, 100, all]"
data-page-size="10"
data-pagination="true"
data-resizable="true"
data-search="true"
data-show-columns="true"
data-show-columns-search="true"
data-show-columns-toggle-all="true"
data-show-export="true"
data-show-filter-control-switch="true"
data-show-fullscreen="true"
data-show-search-clear-button="true"
data-sortable="true"
data-sort-name="base"
data-sort-order="asc"
data-toolbar="#toolbar"
data-unique-id="id">
<thead class="table-primary">
<tr>
<th data-checkbox="true"></th>
<th data-sortable="true" data-switchable="false" data-field="base" data-filter-control="input" data-filter-control-placeholder="(any base)">package base</th>
<th data-sortable="true" data-align="right" data-field="version" data-filter-control="input" data-filter-control-placeholder="(any version)">version</th>
<th data-sortable="true" data-field="packages" data-filter-control="input" data-filter-control-placeholder="(any package)">packages</th>
<th data-sortable="true" data-visible="false" data-field="groups" data-filter-control="select" data-filter-data="func:filterListGroups" data-filter-custom-search="filterList" data-filter-control-placeholder="(any group)">groups</th>
<th data-sortable="true" data-visible="false" data-field="licenses" data-filter-control="select" data-filter-data="func:filterListLicenses" data-filter-custom-search="filterList" data-filter-control-placeholder="(any license)">licenses</th>
<th data-sortable="true" data-visible="false" data-field="packager" data-filter-control="select" data-filter-custom-search="filterContains" data-filter-control-placeholder="(any packager)">packager</th>
<th data-sortable="true" data-align="right" data-field="timestamp" data-filter-control="input" data-filter-custom-search="filterDateRange" data-filter-control-placeholder="(any date)">last update</th>
<th data-sortable="true" data-align="center" data-cell-style="statusFormat" data-field="status" data-filter-control="select" data-filter-control-placeholder="(any status)">status</th>
</tr>
</thead>
</table>
</div>
<div class="container">
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
<ul class="nav">
<li><a id="badge-version" class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources"><i class="bi bi-github"></i> ahriman</a></li>
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman/releases" title="releases list">releases</a></li>
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman/issues" title="issues tracker">report a bug</a></li>
{% if docs_enabled %}
<li><a class="nav-link" href="/api-docs" title="API documentation">api</a></li>
{% endif %}
</ul>
{% if index_url is not none %}
<ul class="nav">
<li><a class="nav-link" href="{{ index_url }}" title="repo index"><i class="bi bi-house"></i> repo index</a></li>
</ul>
{% endif %}
{% if auth.enabled %}
<ul class="nav">
{% if auth.username is none %}
<li>{{ auth.control | safe }}</li>
{% else %}
<li>
<form action="/api/v1/logout" method="post">
<button class="btn btn-link" style="text-decoration: none"><i class="bi bi-box-arrow-right"></i> logout ({{ auth.username }})</button>
</form>
</li>
{% endif %}
</ul>
{% endif %}
</footer>
</div>
{% if auth.enabled %}
{% include "build-status/login-modal.jinja2" %}
{% endif %}
{% include "build-status/alerts.jinja2" %}
{% include "build-status/dashboard.jinja2" %}
{% include "build-status/package-add-modal.jinja2" %}
{% include "build-status/package-rebuild-modal.jinja2" %}
{% include "build-status/key-import-modal.jinja2" %}
{% include "build-status/package-info-modal.jinja2" %}
{% include "build-status/table.jinja2" %}
</body> </body>
</html> </html>
@@ -1,51 +0,0 @@
<script>
const alertPlaceholder = document.getElementById("alert-placeholder");
function createAlert(title, message, clz, action, id) {
id ??= md5(title + message); // MD5 id from the content
if (alertPlaceholder.querySelector(`#alert-${id}`)) {
return; // check if there are duplicates
}
const wrapper = document.createElement("div");
wrapper.id = `alert-${id}`;
wrapper.classList.add("toast", clz);
wrapper.role = "alert";
wrapper.ariaLive = "assertive";
wrapper.ariaAtomic = "true";
wrapper.style.width = "500px"; // 500px is default modal size
const header = document.createElement("div");
header.classList.add("toast-header");
header.innerHTML = `<strong class="me-auto">${safe(title)}</strong> <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="close"></button>`;
wrapper.appendChild(header);
const body = document.createElement("div");
body.classList.add("toast-body", "text-bg-light");
body.innerText = message;
wrapper.appendChild(body);
alertPlaceholder.appendChild(wrapper);
const toast = new bootstrap.Toast(wrapper);
wrapper.addEventListener("hidden.bs.toast", _ => {
wrapper.remove(); // bootstrap doesn't remove elements
(action || reload)();
});
toast.show();
}
function showFailure(title, description, error) {
let details;
try {
details = JSON.parse(error.text).error; // execution handler json error response
} catch (_) {
details = error.text ?? error.message ?? error;
}
createAlert(title, description(details), "text-bg-danger");
}
function showSuccess(title, description, action) {
createAlert(title, description, "text-bg-success", action);
}
</script>
@@ -1,157 +0,0 @@
<div id="dashboard-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div id="dashboard-modal-header" class="modal-header">
<h4 class="modal-title">System health</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row mt-2">
<div class="col-4 col-lg-2" style="text-align: right">Repository name</div>
<div id="dashboard-name" class="col-8 col-lg-3"></div>
<div class="col-4 col-lg-2" style="text-align: right">Repository architecture</div>
<div id="dashboard-architecture" class="col-8 col-lg-3"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-2" style="text-align: right">Current status</div>
<div id="dashboard-status" class="col-8 col-lg-3"></div>
<div class="col-4 col-lg-2" style="text-align: right">Updated at</div>
<div id="dashboard-status-timestamp" class="col-8 col-lg-3"></div>
</div>
<div id="dashboard-canvas" class="form-group row mt-2">
<div class="col-8 col-lg-6">
<canvas id="dashboard-packages-count-chart"></canvas>
</div>
<div class="col-8 col-lg-6">
<canvas id="dashboard-packages-statuses-chart"></canvas>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button>
</div>
</div>
</div>
</div>
<script>
const dashboardModal = document.getElementById("dashboard-modal");
const dashboardModalHeader = document.getElementById("dashboard-modal-header");
const dashboardName = document.getElementById("dashboard-name");
const dashboardArchitecture = document.getElementById("dashboard-architecture");
const dashboardStatus = document.getElementById("dashboard-status");
const dashboardStatusTimestamp = document.getElementById("dashboard-status-timestamp");
const dashboardCanvas = document.getElementById("dashboard-canvas");
const dashboardPackagesStatusesChartCanvas = document.getElementById("dashboard-packages-statuses-chart");
let dashboardPackagesStatusesChart = null;
const dashboardPackagesCountChartCanvas = document.getElementById("dashboard-packages-count-chart");
let dashboardPackagesCountChart = null;
function statusLoad() {
const badgeClass = status => {
if (status === "pending") return "btn-outline-warning";
if (status === "building") return "btn-outline-warning";
if (status === "failed") return "btn-outline-danger";
if (status === "success") return "btn-outline-success";
return "btn-outline-secondary";
};
makeRequest(
"/api/v1/status",
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
dashboardButton.classList.remove(...dashboardButton.classList);
dashboardButton.classList.add("btn");
dashboardButton.classList.add(badgeClass(data.status.status));
dashboardModalHeader.classList.remove(...dashboardModalHeader.classList);
dashboardModalHeader.classList.add("modal-header");
headerClass(data.status.status).forEach(clz => dashboardModalHeader.classList.add(clz));
dashboardName.textContent = data.repository;
dashboardArchitecture.textContent = data.architecture;
dashboardStatus.textContent = data.status.status;
dashboardStatusTimestamp.textContent = new Date(1000 * data.status.timestamp).toISOStringShort();
if (dashboardPackagesStatusesChart) {
const labels = [
"unknown",
"pending",
"building",
"failed",
"success",
];
dashboardPackagesStatusesChart.config.data = {
labels: labels,
datasets: [{
label: "packages in status",
data: labels.map(label => data.packages[label]),
backgroundColor: [
"rgb(55, 58, 60)",
"rgb(255, 117, 24)",
"rgb(255, 117, 24)",
"rgb(255, 0, 57)",
"rgb(63, 182, 24)", // copy-paste from current style
],
}],
};
dashboardPackagesStatusesChart.update();
}
if (dashboardPackagesCountChart) {
dashboardPackagesCountChart.config.data = {
labels: ["packages"],
datasets: [
{
label: "archives",
data: [data.stats.packages],
},
{
label: "bases",
data: [data.stats.bases],
},
],
};
dashboardPackagesCountChart.update();
}
dashboardCanvas.hidden = data.status.total > 0;
},
);
}
ready(_ => {
dashboardPackagesStatusesChart = new Chart(dashboardPackagesStatusesChartCanvas, {
type: "pie",
data: {},
options: {
responsive: true,
},
});
dashboardPackagesCountChart = new Chart(dashboardPackagesCountChartCanvas, {
type: "bar",
data: {},
options: {
maintainAspectRatio: false,
responsive: true,
scales: {
x: {
stacked: true,
},
},
},
});
});
</script>
@@ -1,104 +0,0 @@
<div id="key-import-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<form id="key-import-form" onsubmit="return false">
<div class="modal-header">
<h4 class="modal-title">Import key from PGP server</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="key-import-fingerprint-input" class="col-2 col-form-label">fingerprint</label>
<div class="col-10">
<input id="key-import-fingerprint-input" type="text" class="form-control" placeholder="PGP key fingerprint" name="key" required>
</div>
</div>
<div class="form-group row">
<label for="key-import-server-input" class="col-2 col-form-label">key server</label>
<div class="col-10">
<input id="key-import-server-input" type="text" class="form-control" placeholder="PGP key server" name="server" value="keyserver.ubuntu.com" required>
</div>
</div>
<div class="form-group row">
<div class="col-2"></div>
<div class="col-10">
<pre class="language-less"><samp id="key-import-body-input" class="pre-scrollable language-less"></samp><button id="key-import-copy-button" type="button" class="btn language-less" onclick="copyPgpKey()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" onclick="importPgpKey()"><i class="bi bi-play"></i> import</button>
<button type="submit" class="btn btn-success" onclick="fetchPgpKey()"><i class="bi bi-arrow-clockwise"></i> fetch</button>
</div>
</form>
</div>
</div>
</div>
<script>
const keyImportModal = document.getElementById("key-import-modal");
const keyImportForm = document.getElementById("key-import-form");
const keyImportBodyInput = document.getElementById("key-import-body-input");
const keyImportCopyButton = document.getElementById("key-import-copy-button");
const keyImportFingerprintInput = document.getElementById("key-import-fingerprint-input");
const keyImportServerInput = document.getElementById("key-import-server-input");
async function copyPgpKey() {
const key = keyImportBodyInput.textContent;
await copyToClipboard(key, keyImportCopyButton);
}
function fetchPgpKey() {
const key = keyImportFingerprintInput.value;
const server = keyImportServerInput.value;
if (key && server) {
makeRequest(
"/api/v1/service/pgp",
{
query: {
key: key,
server: server,
},
convert: response => response.json(),
},
data => { keyImportBodyInput.textContent = data.key; },
);
}
}
function importPgpKey() {
const key = keyImportFingerprintInput.value;
const server = keyImportServerInput.value;
if (key && server) {
makeRequest(
"/api/v1/service/pgp",
{
method: "POST",
json: {
key: key,
server: server,
},
},
_ => {
bootstrap.Modal.getOrCreateInstance(keyImportModal).hide();
showSuccess("Success", `Key ${key} has been imported`);
},
error => {
const message = _ => `Could not import key ${key} from ${server}`;
showFailure("Action failed", message, error);
},
);
}
}
ready(_ => {
keyImportModal.addEventListener("hidden.bs.modal", _ => {
keyImportBodyInput.textContent = "";
keyImportForm.reset();
});
});
</script>
@@ -1,90 +0,0 @@
<div id="login-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form id="login-form" onsubmit="return false">
<div class="modal-header">
<h4 class="modal-title">Login</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="login-username" class="col-4 col-form-label">username</label>
<div class="col-8">
<input id="login-username" type="text" class="form-control" placeholder="enter username" name="username" required>
</div>
</div>
<div class="form-group row">
<label for="login-password" class="col-4 col-form-label">password</label>
<div class="col-8">
<div class="input-group">
<input id="login-password" type="password" class="form-control" placeholder="enter password" name="password" required>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="showPassword()"><i id="login-show-hide-password-button" class="bi bi-eye"></i></button>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" onclick="login()"><i class="bi bi-person"></i> login</button>
</div>
</form>
</div>
</div>
</div>
<script>
const loginModal = document.getElementById("login-modal");
const loginForm = document.getElementById("login-form");
const loginPasswordInput = document.getElementById("login-password");
const loginUsernameInput = document.getElementById("login-username");
const showHidePasswordButton = document.getElementById("login-show-hide-password-button");
function login() {
const password = loginPasswordInput.value;
const username = loginUsernameInput.value;
if (username && password) {
makeRequest(
"/api/v1/login",
{
method: "POST",
json: {
username: username,
password: password,
},
},
_ => {
bootstrap.Modal.getOrCreateInstance(loginModal).hide();
showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/");
},
error => {
const message = _ =>
username === "admin" && password === "admin"
? "You've entered a password for user \"root\", did you make a typo in username?"
: `Could not login as ${username}`;
showFailure("Login error", message, error);
},
);
}
}
function showPassword() {
if (loginPasswordInput.getAttribute("type") === "password") {
loginPasswordInput.setAttribute("type", "text");
showHidePasswordButton.classList.remove("bi-eye");
showHidePasswordButton.classList.add("bi-eye-slash");
} else {
loginPasswordInput.setAttribute("type", "password");
showHidePasswordButton.classList.remove("bi-eye-slash");
showHidePasswordButton.classList.add("bi-eye");
}
}
ready(_ => {
loginModal.addEventListener("hidden.bs.modal", _ => {
loginForm.reset();
});
});
</script>
@@ -1,188 +0,0 @@
<div id="package-add-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<form id="package-add-form" onsubmit="return false">
<div class="modal-header">
<h4 class="modal-title">Add new packages</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="package-add-repository-input" class="col-3 col-form-label">repository</label>
<div class="col-9">
<select id="package-add-repository-input" class="form-control" required>
{% for repository in repositories %}
<option value="{{ repository.id }}" data-repository="{{ repository.repository }}" data-architecture="{{ repository.architecture }}">{{ repository.repository }} ({{ repository.architecture }})</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group row">
<label for="package-add-input" class="col-3 col-form-label">package</label>
<div class="col-9">
<input id="package-add-input" type="text" list="package-add-known-packages-dlist" autocomplete="off" class="form-control" placeholder="AUR package" required>
<datalist id="package-add-known-packages-dlist"></datalist>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label"></label>
<div class="col-9">
<input id="package-add-refresh-input" type="checkbox" class="form-check-input" value="" checked>
<label for="package-add-refresh-input" class="form-check-label">update pacman databases</label>
</div>
</div>
<div class="form-group row">
<div class="col-12">
<button id="package-add-variable-button" type="button" class="form-control btn btn-light rounded" onclick="packageAddVariableInputCreate()"><i class="bi bi-plus"></i> add environment variable </button>
</div>
</div>
<div id="package-add-variables-div" class="form-group row"></div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" onclick="packagesAdd()"><i class="bi bi-play"></i> add</button>
<button type="submit" class="btn btn-success" onclick="packagesRequest()"><i class="bi bi-plus"></i> request</button>
</div>
</form>
</div>
</div>
</div>
<script>
const packageAddModal = document.getElementById("package-add-modal");
const packageAddForm = document.getElementById("package-add-form");
const packageAddInput = document.getElementById("package-add-input");
const packageAddRepositoryInput = document.getElementById("package-add-repository-input");
const packageAddKnownPackagesList = document.getElementById("package-add-known-packages-dlist");
const packageAddVariablesDiv = document.getElementById("package-add-variables-div");
const packageAddRefreshInput = document.getElementById("package-add-refresh-input");
function packageAddVariableInputCreate() {
const variableInput = document.createElement("div");
variableInput.classList.add("input-group");
variableInput.classList.add("package-add-variable");
const variableNameInput = document.createElement("input");
variableNameInput.type = "text";
variableNameInput.classList.add("form-control");
variableNameInput.classList.add("package-add-variable-name");
variableNameInput.placeholder = "name";
variableNameInput.ariaLabel = "variable name";
const variableSeparator = document.createElement("span");
variableSeparator.classList.add("input-group-text")
variableSeparator.textContent = "=";
const variableValueInput = document.createElement("input");
variableValueInput.type = "text";
variableValueInput.classList.add("form-control");
variableValueInput.classList.add("package-add-variable-value");
variableValueInput.placeholder = "value";
variableValueInput.ariaLabel = "variable value";
const variableButtonRemove = document.createElement("button");
variableButtonRemove.type = "button";
variableButtonRemove.classList.add("btn");
variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>";
variableButtonRemove.onclick = _ => { variableInput.remove(); };
// bring them together
variableInput.appendChild(variableNameInput);
variableInput.appendChild(variableSeparator);
variableInput.appendChild(variableValueInput);
variableInput.appendChild(variableButtonRemove);
packageAddVariablesDiv.appendChild(variableInput);
}
function patchesParse() {
const patches = Array.from(packageAddVariablesDiv.getElementsByClassName("package-add-variable")).map(element => {
return {
key: element.querySelector(".package-add-variable-name").value,
value: element.querySelector(".package-add-variable-value").value,
};
}).filter(patch => patch.key);
return {patches: patches};
}
function packagesAdd(packages, patches, repository, data) {
packages = packages ?? packageAddInput.value;
patches = patches ?? patchesParse();
repository = repository ?? getRepositorySelector(packageAddRepositoryInput);
data = data ?? {refresh: packageAddRefreshInput.checked};
if (packages) {
bootstrap.Modal.getOrCreateInstance(packageAddModal).hide();
const onSuccess = update => `Packages ${update} have been added`;
const onFailure = error => `Package addition failed: ${error}`;
const parameters = Object.assign({}, data, patches);
doPackageAction("/api/v1/service/add", [packages], repository, onSuccess, onFailure, parameters);
}
}
function packagesRequest(packages, patches) {
packages = packages ?? packageAddInput.value;
patches = patches ?? patchesParse();
const repository = getRepositorySelector(packageAddRepositoryInput);
if (packages) {
bootstrap.Modal.getOrCreateInstance(packageAddModal).hide();
const onSuccess = update => `Packages ${update} have been requested`;
const onFailure = error => `Package request failed: ${error}`;
doPackageAction("/api/v1/service/request", [packages], repository, onSuccess, onFailure, patches);
}
}
ready(_ => {
packageAddModal.addEventListener("shown.bs.modal", _ => {
const option = packageAddRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`);
option.selected = "selected";
});
packageAddModal.addEventListener("hidden.bs.modal", _ => {
packageAddVariablesDiv.replaceChildren();
packageAddForm.reset();
});
packageAddInput.addEventListener("keyup", _ => {
clearTimeout(packageAddInput.requestTimeout);
// do not update datalist if search string didn't change yet
const value = packageAddInput.value;
const previousValue = packageAddInput.dataset.previousValue;
if (value === previousValue) {
return;
}
// store current search string in attributes
packageAddInput.dataset.previousValue = value;
// perform data list update
packageAddInput.requestTimeout = setTimeout(_ => {
if (value.length >= 3) {
makeRequest(
"/api/v1/service/search",
{
query: {
for: value,
},
convert: response => response.json(),
},
data => {
const options = data.map(pkg => {
const option = document.createElement("option");
option.value = pkg.package;
option.innerText = `${pkg.package} (${pkg.description})`;
return option;
});
packageAddKnownPackagesList.replaceChildren(...options);
},
);
}
}, 500);
});
});
</script>
@@ -1,586 +0,0 @@
<div id="package-info-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div id="package-info-modal-header" class="modal-header">
<h4 id="package-info" class="modal-title"></h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">packages</div>
<div id="package-info-packages" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">version</div>
<div id="package-info-version" class="col-8 col-lg-5"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">packager</div>
<div id="package-info-packager" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right"></div>
<div id="package-info---placeholder" class="col-8 col-lg-5"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">groups</div>
<div id="package-info-groups" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">licenses</div>
<div id="package-info-licenses" class="col-8 col-lg-5"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">upstream</div>
<div id="package-info-upstream-url" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">AUR</div>
<div id="package-info-aur-url" class="col-8 col-lg-5"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">depends</div>
<div id="package-info-depends" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">implicitly depends</div>
<div id="package-info-implicitly-depends" class="col-8 col-lg-5"></div>
</div>
<hr class="col-12">
<div id="package-info-variables-block" hidden>
<h3>Environment variables</h3>
<div id="package-info-variables-div" class="form-group row"></div>
<hr class="col-12">
</div>
<nav>
<div class="nav nav-tabs" role="tablist">
<button id="package-info-logs-button" class="nav-link active" data-bs-toggle="tab" data-bs-target="#package-info-logs" type="button" role="tab" aria-controls="package-info-logs" aria-selected="true">Build logs</button>
<button id="package-info-changes-button" class="nav-link" data-bs-toggle="tab" data-bs-target="#package-info-changes" type="button" role="tab" aria-controls="package-info-changes" aria-selected="false">Changes</button>
<button id="package-info-events-button" class="nav-link" data-bs-toggle="tab" data-bs-target="#package-info-events" type="button" role="tab" aria-controls="package-info-events" aria-selected="false">Events</button>
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
<div id="package-info-logs" class="tab-pane fade show active" role="tabpanel" aria-labelledby="package-info-logs-button" tabindex="0">
<div class="row">
<div class="col-1 dropend">
<button id="package-info-logs-dropdown" class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-list"></i>
</button>
<nav id="package-info-logs-versions" class="dropdown-menu" aria-labelledby="package-info-logs-dropdown"></nav>
</div>
<div class="col-11">
<pre class="language-console"><code id="package-info-logs-input" class="pre-scrollable language-console"></code><button id="package-info-logs-copy-button" type="button" class="btn language-console" onclick="copyLogs()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div>
</div>
</div>
<div id="package-info-changes" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-changes-button" tabindex="0">
<pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div>
<div id="package-info-events" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-events-button" tabindex="0">
<canvas id="package-info-events-update-chart" hidden></canvas>
<table id="package-info-events-table"
data-classes="table table-hover"
data-sortable="true"
data-sort-name="timestamp"
data-sort-order="desc">
<thead class="table-primary">
<tr>
<th data-align="right" data-field="timestamp">date</th>
<th data-field="event">event</th>
<th data-field="message">description</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
<div class="modal-footer">
{% if not auth.enabled or auth.username is not none %}
<input id="package-info-refresh-input" type="checkbox" class="form-check-input" value="" checked>
<label for="package-info-refresh-input" class="form-check-label">update pacman databases</label>
<button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button>
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal"><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button>
{% endif %}
{% if autorefresh_intervals %}
<button type="button" class="btn btn-secondary" onclick="showPackageInfo()"><i class="bi bi-arrow-clockwise"></i><span class="d-none d-sm-inline"> reload</span></button>
<div class="btn-group dropup">
<input id="package-info-autoreload-button" type="checkbox" class="btn-check" autocomplete="off" onclick="togglePackageInfoAutoReload()" checked>
<label for="package-info-autoreload-button" class="btn btn-outline-secondary" title="toggle auto reload"><i class="bi bi-clock"></i></label>
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">select interval</span>
</button>
<ul id="package-info-autoreload-input" class="dropdown-menu">
{% for interval in autorefresh_intervals %}
<li><a class="dropdown-item {{ "active" if interval.is_active }}" onclick="togglePackageInfoAutoReload({{ interval.interval }})" data-interval="{{ interval.interval }}">{{ interval.text }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button>
</div>
</div>
</div>
</div>
<script>
const packageInfoModal = document.getElementById("package-info-modal");
const packageInfoModalHeader = document.getElementById("package-info-modal-header");
const packageInfo = document.getElementById("package-info");
const packageInfoLogsVersions = document.getElementById("package-info-logs-versions");
const packageInfoLogsInput = document.getElementById("package-info-logs-input");
const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button");
const packageInfoChangesInput = document.getElementById("package-info-changes-input");
const packageInfoChangesCopyButton = document.getElementById("package-info-changes-copy-button");
// so far bootstrap-table only operates with jquery elements
const packageInfoEventsTable = $(document.getElementById("package-info-events-table"));
const packageInfoEventsUpdateChartCanvas = document.getElementById("package-info-events-update-chart");
let packageInfoEventsUpdateChart = null;
const packageInfoAurUrl = document.getElementById("package-info-aur-url");
const packageInfoDepends = document.getElementById("package-info-depends");
const packageInfoGroups = document.getElementById("package-info-groups");
const packageInfoImplicitlyDepends = document.getElementById("package-info-implicitly-depends");
const packageInfoLicenses = document.getElementById("package-info-licenses");
const packageInfoPackager = document.getElementById("package-info-packager");
const packageInfoPackages = document.getElementById("package-info-packages");
const packageInfoUpstreamUrl = document.getElementById("package-info-upstream-url");
const packageInfoVersion = document.getElementById("package-info-version");
const packageInfoVariablesBlock = document.getElementById("package-info-variables-block");
const packageInfoVariablesDiv = document.getElementById("package-info-variables-div");
const packageInfoRefreshInput = document.getElementById("package-info-refresh-input");
const packageInfoAutoReloadButton = document.getElementById("package-info-autoreload-button");
const packageInfoAutoReloadInput = document.getElementById("package-info-autoreload-input");
let packageInfoAutoReloadTask = null;
function clearChart() {
packageInfoEventsUpdateChartCanvas.hidden = true;
if (packageInfoEventsUpdateChart) {
packageInfoEventsUpdateChart.data = {};
packageInfoEventsUpdateChart.update();
}
}
function convertLogs(data, filter) {
return data
.filter((filter || Boolean))
.map(log_record => `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`)
.join("\n");
}
async function copyChanges() {
const changes = packageInfoChangesInput.textContent;
await copyToClipboard(changes, packageInfoChangesCopyButton);
}
async function copyLogs() {
const logs = packageInfoLogsInput.textContent;
await copyToClipboard(logs, packageInfoLogsCopyButton);
}
function highlight(element) {
delete element.dataset.highlighted;
hljs.highlightElement(element);
}
function insertVariable(packageBase, variable) {
const variableInput = document.createElement("div");
variableInput.classList.add("input-group");
const variableNameInput = document.createElement("input");
variableNameInput.classList.add("form-control");
variableNameInput.readOnly = true;
variableNameInput.value = variable.key;
const variableSeparator = document.createElement("span");
variableSeparator.classList.add("input-group-text")
variableSeparator.textContent = "=";
const variableValueInput = document.createElement("input");
variableValueInput.classList.add("form-control");
variableValueInput.readOnly = true;
variableValueInput.value = JSON.stringify(variable.value);
const variableButtonRemove = document.createElement("button");
variableButtonRemove.type = "button";
variableButtonRemove.classList.add("btn");
variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>";
variableButtonRemove.onclick = _ => {
makeRequest(
`/api/v1/packages/${packageBase}/patches/${variable.key}`,
{
method: "DELETE",
},
_ => variableInput.remove(),
);
};
// bring them together
variableInput.appendChild(variableNameInput);
variableInput.appendChild(variableSeparator);
variableInput.appendChild(variableValueInput);
variableInput.appendChild(variableButtonRemove);
packageInfoVariablesDiv.appendChild(variableInput);
}
function loadChanges(packageBase, onFailure) {
makeRequest(
`/api/v1/packages/${packageBase}/changes`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
const changes = data.changes;
packageInfoChangesInput.textContent = changes ?? "";
highlight(packageInfoChangesInput);
},
onFailure,
);
}
function loadDependencies(packageBase, onFailure) {
makeRequest(
`/api/v1/packages/${packageBase}/dependencies`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
packageInfoImplicitlyDepends.innerHTML = listToTable(
Object.values(data.paths)
.reduce((accumulator, currentValue) => accumulator.concat(currentValue), [])
);
},
onFailure,
);
}
function loadEvents(packageBase, onFailure) {
packageInfoEventsTable.bootstrapTable("showLoading");
clearChart();
makeRequest(
"/api/v1/events",
{
query: {
architecture: repository.architecture,
repository: repository.repository,
object_id: packageBase,
limit: 30,
},
convert: response => response.json(),
},
data => {
const events = data.map(event => {
return {
timestamp: new Date(1000 * event.created).toISOStringShort(),
event: event.event,
message: event.message || "",
};
});
const chart = data.filter(event => event.event === "package-updated");
packageInfoEventsTable.bootstrapTable("load", events);
packageInfoEventsTable.bootstrapTable("hideLoading");
if (packageInfoEventsUpdateChart) {
packageInfoEventsUpdateChart.config.data = {
labels: chart.map(event => new Date(1000 * event.created).toISOStringShort()),
datasets: [{
label: "update duration, s",
data: chart.map(event => event.data.took),
cubicInterpolationMode: "monotone",
tension: 0.4,
}],
};
packageInfoEventsUpdateChart.update();
}
packageInfoEventsUpdateChartCanvas.hidden = !chart.length;
},
onFailure,
);
}
function loadLogs(packageBase, onFailure) {
const sortFn = (left, right) => left.process_id.localeCompare(right.process_id) || left.version.localeCompare(right.version);
const compareFn = (left, right) => left.process_id === right.process_id && left.version === right.version;
makeRequest(
`/api/v2/packages/${packageBase}/logs`,
{
query: {
architecture: repository.architecture,
head: true,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
const currentVersions = Array.from(packageInfoLogsVersions.children)
.map(el => {
return {
process_id: el.dataset.processId,
version: el.dataset.version,
};
})
.sort(sortFn);
const newVersions = data
.map(el => {
return {
process_id: el.process_id,
version: el.version,
};
})
.sort(sortFn);
if (currentVersions.equals(newVersions, compareFn))
loadLogsActive(packageBase);
else
loadLogsAll(packageBase, onFailure);
},
)
}
function loadLogsActive(packageBase) {
const activeLogSelector = packageInfoLogsVersions.querySelector(".active");
if (activeLogSelector) {
makeRequest(
`/api/v2/packages/${packageBase}/logs`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
version: activeLogSelector.dataset.version,
process_id: activeLogSelector.dataset.processId,
},
convert: response => response.json(),
},
data => {
activeLogSelector.dataset.logs = convertLogs(data);
activeLogSelector.click();
},
);
}
}
function loadLogsAll(packageBase, onFailure) {
makeRequest(
`/api/v2/packages/${packageBase}/logs`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
const selectors = Object
.values(
data.reduce((acc, log_record) => {
const id = `${log_record.version}-${log_record.process_id}`;
if (acc[id])
acc[id].created = Math.min(log_record.created, acc[id].created);
else
acc[id] = log_record;
return acc;
}, {})
)
.sort(({created: left}, {created: right}) =>
right - left
)
.map(version => {
const link = document.createElement("a");
link.classList.add("dropdown-item");
link.dataset.version = version.version;
link.dataset.processId = version.process_id;
link.dataset.logs = convertLogs(data, log_record => log_record.version === version.version && log_record.process_id === version.process_id);
link.textContent = new Date(1000 * version.created).toISOStringShort();
link.href = "#";
link.onclick = _ => {
// check if we are at the bottom of the code block
const isScrolledToBottom = packageInfoLogsInput.scrollTop + packageInfoLogsInput.clientHeight >= packageInfoLogsInput.scrollHeight;
packageInfoLogsInput.textContent = link.dataset.logs;
highlight(packageInfoLogsInput);
if (isScrolledToBottom)
packageInfoLogsInput.scrollTop = packageInfoLogsInput.scrollHeight; // scroll to the new end
Array.from(packageInfoLogsVersions.children).forEach(el => el.classList.remove("active"));
link.classList.add("active");
return false;
};
return link;
});
packageInfoLogsVersions.replaceChildren(...selectors);
selectors.find(Boolean)?.click();
},
onFailure,
);
}
function loadPackage(packageBase, onFailure) {
makeRequest(
`/api/v1/packages/${packageBase}`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
const description = data.find(Boolean);
const packages = description.package.packages;
const aurUrl = description.package.remote.web_url;
const upstreamUrls = Array.from(new Set(Object.values(packages).map(single => single.url))).sort();
packageInfo.textContent = `${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`;
packageInfoModalHeader.classList.remove(...packageInfoModalHeader.classList);
packageInfoModalHeader.classList.add("modal-header");
headerClass(description.status.status).forEach(clz => packageInfoModalHeader.classList.add(clz));
packageInfoAurUrl.innerHTML = aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : "";
packageInfoDepends.innerHTML = listToTable(
Object.values(packages)
.reduce((accumulator, currentValue) => {
return accumulator.concat(currentValue.depends.filter(v => !packages.hasOwnProperty(v)))
.concat(currentValue.make_depends.filter(v => !packages.hasOwnProperty(v)).map(v => `${v} (make)`))
.concat(currentValue.opt_depends.filter(v => !packages.hasOwnProperty(v)).map(v => `${v} (optional)`));
}, [])
);
packageInfoGroups.innerHTML = listToTable(extractListProperties(description.package, "groups"));
packageInfoLicenses.innerHTML = listToTable(extractListProperties(description.package, "licenses"));
packageInfoPackager.textContent = description.package.packager;
packageInfoPackages.innerHTML = listToTable(Object.entries(packages).map(([key, value]) => `${key} (${value.description})`));
packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>");
packageInfoVersion.textContent = description.package.version;
},
onFailure,
);
}
function loadPatches(packageBase, onFailure) {
makeRequest(
`/api/v1/packages/${packageBase}/patches`,
{
convert: response => response.json(),
},
data => {
packageInfoVariablesDiv.replaceChildren();
data.map(patch => insertVariable(packageBase, patch));
packageInfoVariablesBlock.hidden = !data.length;
},
onFailure,
);
}
function packageInfoRemove() {
const packageBase = packageInfoModal.dataset.package;
packagesRemove([packageBase]);
}
function packageInfoUpdate() {
const packageBase = packageInfoModal.dataset.package;
packagesAdd(packageBase, [], repository, {refresh: packageInfoRefreshInput.checked});
}
function showPackageInfo(packageBase) {
const isPackageBaseSet = packageBase !== undefined;
if (isPackageBaseSet) {
// set package base as currently used
packageInfoModal.dataset.package = packageBase;
} else {
// read package base from the current window attribute
packageBase = packageInfoModal.dataset.package;
}
const onFailure = error => {
if (isPackageBaseSet) {
const message = details => `Could not load package ${packageBase} info: ${details}`;
showFailure("Load failure", message, error);
}
};
loadPackage(packageBase, onFailure);
loadDependencies(packageBase, onFailure);
loadPatches(packageBase, onFailure);
loadLogs(packageBase, onFailure);
loadChanges(packageBase, onFailure);
loadEvents(packageBase, onFailure);
if (isPackageBaseSet) {
bootstrap.Modal.getOrCreateInstance(packageInfoModal).show();
{% if autorefresh_intervals %}
togglePackageInfoAutoReload();
{% endif %}
}
}
function togglePackageInfoAutoReload(interval) {
clearInterval(packageInfoAutoReloadTask);
packageInfoAutoReloadTask = toggleAutoReload(packageInfoAutoReloadButton, interval, packageInfoAutoReloadInput, _ => {
if (!hasActiveSelection()) {
const packageBase = packageInfoModal.dataset.package;
// we only poll status and logs here
loadPackage(packageBase);
loadLogs(packageBase);
}
});
}
ready(_ => {
packageInfoEventsTable.bootstrapTable({});
packageInfoEventsUpdateChart = new Chart(packageInfoEventsUpdateChartCanvas, {
type: "line",
data: {},
options: {
responsive: true,
},
});
packageInfoModal.addEventListener("hidden.bs.modal", _ => {
packageInfoAurUrl.textContent = "";
packageInfoDepends.textContent = "";
packageInfoGroups.textContent = "";
packageInfoImplicitlyDepends.textContent = "";
packageInfoLicenses.textContent = "";
packageInfoPackager.textContent = "";
packageInfoPackages.textContent = "";
packageInfoUpstreamUrl.textContent = "";
packageInfoVersion.textContent = "";
packageInfoVariablesBlock.hidden = true;
packageInfoVariablesDiv.replaceChildren();
packageInfoLogsInput.textContent = "";
packageInfoChangesInput.textContent = "";
packageInfoEventsTable.bootstrapTable("load", []);
clearChart();
clearInterval(packageInfoAutoReloadTask);
packageInfoAutoReloadTask = null; // not really required (?) but lets clear everything
});
restoreAutoReloadSettings(packageInfoAutoReloadButton, packageInfoAutoReloadInput);
});
</script>
@@ -1,63 +0,0 @@
<div id="package-rebuild-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<form id="package-rebuild-form" onsubmit="return false">
<div class="modal-header">
<h4 class="modal-title">Rebuild depending packages</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="package-rebuild-repository-input" class="col-3 col-form-label">repository</label>
<div class="col-9">
<select id="package-rebuild-repository-input" class="form-control" name="repository" required>
{% for repository in repositories %}
<option value="{{ repository.id }}" data-repository="{{ repository.repository }}" data-architecture="{{ repository.architecture }}">{{ repository.repository }} ({{ repository.architecture }})</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group row">
<label for="package-rebuild-dependency-input" class="col-3 col-form-label">dependency</label>
<div class="col-9">
<input id="package-rebuild-dependency-input" type="text" class="form-control" placeholder="packages dependency" name="package" required>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" onclick="packagesRebuild()"><i class="bi bi-play"></i> rebuild</button>
</div>
</form>
</div>
</div>
</div>
<script>
const packageRebuildModal = document.getElementById("package-rebuild-modal");
const packageRebuildForm = document.getElementById("package-rebuild-form");
const packageRebuildDependencyInput = document.getElementById("package-rebuild-dependency-input");
const packageRebuildRepositoryInput = document.getElementById("package-rebuild-repository-input");
function packagesRebuild() {
const packages = packageRebuildDependencyInput.value;
const repository = getRepositorySelector(packageRebuildRepositoryInput);
if (packages) {
bootstrap.Modal.getOrCreateInstance(packageRebuildModal).hide();
const onSuccess = update => `Repository rebuild has been run for packages which depend on ${update}`;
const onFailure = error => `Repository rebuild failed: ${error}`;
doPackageAction("/api/v1/service/rebuild", [packages], repository, onSuccess, onFailure);
}
}
ready(_ => {
packageRebuildModal.addEventListener("shown.bs.modal", _ => {
const option = packageRebuildRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`);
option.selected = "selected";
});
packageRebuildModal.addEventListener("hidden.bs.modal", _ => {
packageRebuildForm.reset();
});
});
</script>
@@ -1,247 +0,0 @@
<script>
const packageRemoveButton = document.getElementById("package-remove-button");
const packageUpdateButton = document.getElementById("package-update-button");
let repository = null;
// so far bootstrap-table only operates with jquery elements
const table = $(document.getElementById("packages"));
const dashboardButton = document.getElementById("dashboard-button");
const versionBadge = document.getElementById("badge-version");
const tableAutoReloadButton = document.getElementById("table-autoreload-button");
const tableAutoReloadInput = document.getElementById("table-autoreload-input");
let tableAutoReloadTask = null;
function doPackageAction(uri, packages, repository, successText, failureText, data) {
makeRequest(
uri,
{
method: "POST",
query: {
architecture: repository.architecture,
repository: repository.repository,
},
json: Object.assign({}, {packages: packages}, data || {}),
},
_ => {
const message = successText(packages.join(", "));
showSuccess("Success", message);
},
error => {
showFailure("Action failed", failureText, error);
},
);
}
function filterListGroups() {
return extractDataList(table.bootstrapTable("getData"), "groups");
}
function filterListLicenses() {
return extractDataList(table.bootstrapTable("getData"), "licenses");
}
function filterListPackagers() {
return extractDataList(table.bootstrapTable("getData"), "packager");
}
function getRepositorySelector(selector) {
const selected = selector.options[selector.selectedIndex];
return {
architecture: selected.getAttribute("data-architecture"),
repository: selected.getAttribute("data-repository"),
};
}
function getSelection() {
return table.bootstrapTable("getSelections").map(row => row.id);
}
function packagesLoad(onFailure) {
makeRequest(
"/api/v1/packages",
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
const payload = data
.map(description => {
const package_base = description.package.base;
const web_url = description.package.remote.web_url;
return {
id: package_base,
base: web_url ? safeLink(web_url, package_base, package_base).outerHTML : safe(package_base),
version: safe(description.package.version),
packager: description.package.packager ? safe(description.package.packager) : "",
packages: listToTable(Object.keys(description.package.packages)),
groups: listToTable(extractListProperties(description.package, "groups")),
licenses: listToTable(extractListProperties(description.package, "licenses")),
timestamp: new Date(1000 * description.status.timestamp).toISOStringShort(),
status: description.status.status,
};
});
updateTable(table, payload, row => row.timestamp);
table.bootstrapTable("hideLoading");
},
onFailure,
);
}
function packagesRemove(packages) {
packages = packages ?? getSelection();
const onSuccess = update => `Packages ${update} have been removed`;
const onFailure = error => `Could not remove packages: ${error}`;
doPackageAction("/api/v1/service/remove", packages, repository, onSuccess, onFailure);
}
function packagesUpdate() {
const currentSelection = getSelection();
const [url, onSuccess] = currentSelection.length === 0
? ["/api/v1/service/update", _ => `Repository update has been run`]
: ["/api/v1/service/add", update => `Run update for packages ${update}`];
const onFailure = error => `Packages update failed: ${error}`;
doPackageAction(url, currentSelection, repository, onSuccess, onFailure);
}
function refreshDatabases() {
const onSuccess = _ => "Pacman database update has been requested";
const onFailure = error => `Could not update pacman databases: ${error}`;
const parameters = {
refresh: true,
aur: false,
local: false,
manual: false,
};
doPackageAction("/api/v1/service/update", [], repository, onSuccess, onFailure, parameters);
}
function reload() {
table.bootstrapTable("showLoading");
const onFailure = error => {
if ((error.status === 401) || (error.status === 403)) {
// authorization error
const text = "In order to see statuses you must login first.";
table.find("tr.unauthorized").remove();
table.find("tbody").append(`<tr class="unauthorized"><td colspan="100%">${safe(text)}</td></tr>`);
table.bootstrapTable("hideLoading");
} else {
// other errors
const message = details => `Could not load list of packages: ${details}`;
showFailure("Load failure", message, error);
}
};
packagesLoad(onFailure);
statusLoad();
}
function selectRepository() {
const fragment = window.location.hash.replace("#", "") || "{{ repositories[0].id }}";
document.getElementById(`${fragment}-link`).click();
}
function statusFormat(value) {
const cellClass = status => {
if (status === "pending") return "table-warning";
if (status === "building") return "table-warning";
if (status === "failed") return "table-danger";
if (status === "success") return "table-success";
return "table-secondary";
};
return {classes: cellClass(value)};
}
function toggleTableAutoReload(interval) {
clearInterval(tableAutoReloadTask);
tableAutoReloadTask = toggleAutoReload(tableAutoReloadButton, interval, tableAutoReloadInput, _ => {
if (!hasActiveModal() &&
!hasActiveDropdown()) {
packagesLoad();
statusLoad();
}
});
}
ready(_ => {
const onCheckFunction = function () {
if (packageRemoveButton) {
packageRemoveButton.disabled = !getSelection().length;
}
};
document.querySelectorAll("#repositories a").forEach(element => {
element.onclick = _ => {
repository = {
architecture: element.dataset.architecture,
repository: element.dataset.repository,
};
if (packageUpdateButton) {
packageUpdateButton.innerHTML = `<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`;
}
bootstrap.Tab.getOrCreateInstance(document.getElementById(element.id)).show();
reload();
};
});
table.bootstrapTable({
onCheck: onCheckFunction,
onCheckAll: onCheckFunction,
onClickRow: (data, row, cell) => {
if (0 === cell || "base" === cell) {
const method = data[0] === true ? "uncheckBy" : "checkBy"; // fck javascript
table.bootstrapTable(method, {field: "id", values: [data.id]});
} else showPackageInfo(data.id);
},
onCreatedControls: _ => {
new easepick.create({
element: document.querySelector(".bootstrap-table-filter-control-timestamp"),
css: [
"https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",
],
grid: 2,
calendars: 2,
autoApply: false,
locale: {
cancel: "Clear",
},
RangePlugin: {
tooltip: false,
},
plugins: [
"RangePlugin",
],
setup: picker => {
picker.on("select", _ => { table.bootstrapTable("triggerSearch"); });
// replace "Cancel" behaviour to "Clear"
picker.onClickCancelButton = element => {
if (picker.isCancelButton(element)) {
picker.clear();
picker.hide();
table.bootstrapTable("triggerSearch");
}
};
},
});
},
onUncheck: onCheckFunction,
onUncheckAll: onCheckFunction,
});
restoreAutoReloadSettings(tableAutoReloadButton, tableAutoReloadInput);
selectRepository();
{% if autorefresh_intervals %}
toggleTableAutoReload();
{% endif %}
});
</script>
@@ -0,0 +1,10 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}
@@ -0,0 +1,328 @@
var SF=Object.defineProperty;var Zw=e=>{throw TypeError(e)};var kF=(e,t,n)=>t in e?SF(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Fe=(e,t,n)=>kF(e,typeof t!="symbol"?t+"":t,n),Mb=(e,t,n)=>t.has(e)||Zw("Cannot "+n);var W=(e,t,n)=>(Mb(e,t,"read from private field"),n?n.call(e):t.get(e)),Ue=(e,t,n)=>t.has(e)?Zw("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),$e=(e,t,n,r)=>(Mb(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),ut=(e,t,n)=>(Mb(e,t,"access private method"),n);var nh=(e,t,n,r)=>({set _(o){$e(e,t,o,n)},get _(){return W(e,t,r)}});function PF(e,t){for(var n=0;n<t.length;n++){const r=t[n];if(typeof r!="string"&&!Array.isArray(r)){for(const o in r)if(o!=="default"&&!(o in e)){const s=Object.getOwnPropertyDescriptor(r,o);s&&Object.defineProperty(e,o,s.get?s:{enumerable:!0,get:()=>r[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const i of s.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&r(i)}).observe(document,{childList:!0,subtree:!0});function n(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(o){if(o.ep)return;o.ep=!0;const s=n(o);fetch(o.href,s)}})();function Ug(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function Vs(e){if(e.__esModule)return e;var t=e.default;if(typeof t=="function"){var n=function r(){return this instanceof r?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(n,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}),n}var ZI={exports:{}},Kg={},JI={exports:{}},lt={};/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var _f=Symbol.for("react.element"),MF=Symbol.for("react.portal"),IF=Symbol.for("react.fragment"),EF=Symbol.for("react.strict_mode"),_F=Symbol.for("react.profiler"),TF=Symbol.for("react.provider"),RF=Symbol.for("react.context"),OF=Symbol.for("react.forward_ref"),$F=Symbol.for("react.suspense"),FF=Symbol.for("react.memo"),LF=Symbol.for("react.lazy"),Jw=Symbol.iterator;function DF(e){return e===null||typeof e!="object"?null:(e=Jw&&e[Jw]||e["@@iterator"],typeof e=="function"?e:null)}var eE={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},tE=Object.assign,nE={};function Vc(e,t,n){this.props=e,this.context=t,this.refs=nE,this.updater=n||eE}Vc.prototype.isReactComponent={};Vc.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Vc.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function rE(){}rE.prototype=Vc.prototype;function Dx(e,t,n){this.props=e,this.context=t,this.refs=nE,this.updater=n||eE}var Ax=Dx.prototype=new rE;Ax.constructor=Dx;tE(Ax,Vc.prototype);Ax.isPureReactComponent=!0;var eS=Array.isArray,oE=Object.prototype.hasOwnProperty,jx={current:null},sE={key:!0,ref:!0,__self:!0,__source:!0};function iE(e,t,n){var r,o={},s=null,i=null;if(t!=null)for(r in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(s=""+t.key),t)oE.call(t,r)&&!sE.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(l===1)o.children=n;else if(1<l){for(var a=Array(l),c=0;c<l;c++)a[c]=arguments[c+2];o.children=a}if(e&&e.defaultProps)for(r in l=e.defaultProps,l)o[r]===void 0&&(o[r]=l[r]);return{$$typeof:_f,type:e,key:s,ref:i,props:o,_owner:jx.current}}function AF(e,t){return{$$typeof:_f,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}function zx(e){return typeof e=="object"&&e!==null&&e.$$typeof===_f}function jF(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(n){return t[n]})}var tS=/\/+/g;function Ib(e,t){return typeof e=="object"&&e!==null&&e.key!=null?jF(""+e.key):t.toString(36)}function Yh(e,t,n,r,o){var s=typeof e;(s==="undefined"||s==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(s){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case _f:case MF:i=!0}}if(i)return i=e,o=o(i),e=r===""?"."+Ib(i,0):r,eS(o)?(n="",e!=null&&(n=e.replace(tS,"$&/")+"/"),Yh(o,t,n,"",function(c){return c})):o!=null&&(zx(o)&&(o=AF(o,n+(!o.key||i&&i.key===o.key?"":(""+o.key).replace(tS,"$&/")+"/")+e)),t.push(o)),1;if(i=0,r=r===""?".":r+":",eS(e))for(var l=0;l<e.length;l++){s=e[l];var a=r+Ib(s,l);i+=Yh(s,t,n,a,o)}else if(a=DF(e),typeof a=="function")for(e=a.call(e),l=0;!(s=e.next()).done;)s=s.value,a=r+Ib(s,l++),i+=Yh(s,t,n,a,o);else if(s==="object")throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return i}function rh(e,t,n){if(e==null)return e;var r=[],o=0;return Yh(e,r,"","",function(s){return t.call(n,s,o++)}),r}function zF(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(n){(e._status===0||e._status===-1)&&(e._status=1,e._result=n)},function(n){(e._status===0||e._status===-1)&&(e._status=2,e._result=n)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var nr={current:null},Qh={transition:null},NF={ReactCurrentDispatcher:nr,ReactCurrentBatchConfig:Qh,ReactCurrentOwner:jx};function lE(){throw Error("act(...) is not supported in production builds of React.")}lt.Children={map:rh,forEach:function(e,t,n){rh(e,function(){t.apply(this,arguments)},n)},count:function(e){var t=0;return rh(e,function(){t++}),t},toArray:function(e){return rh(e,function(t){return t})||[]},only:function(e){if(!zx(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};lt.Component=Vc;lt.Fragment=IF;lt.Profiler=_F;lt.PureComponent=Dx;lt.StrictMode=EF;lt.Suspense=$F;lt.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=NF;lt.act=lE;lt.cloneElement=function(e,t,n){if(e==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var r=tE({},e.props),o=e.key,s=e.ref,i=e._owner;if(t!=null){if(t.ref!==void 0&&(s=t.ref,i=jx.current),t.key!==void 0&&(o=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(a in t)oE.call(t,a)&&!sE.hasOwnProperty(a)&&(r[a]=t[a]===void 0&&l!==void 0?l[a]:t[a])}var a=arguments.length-2;if(a===1)r.children=n;else if(1<a){l=Array(a);for(var c=0;c<a;c++)l[c]=arguments[c+2];r.children=l}return{$$typeof:_f,type:e.type,key:o,ref:s,props:r,_owner:i}};lt.createContext=function(e){return e={$$typeof:RF,_currentValue:e,_currentValue2:e,_threadCountLine truncated
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var HF=p,BF=Symbol.for("react.element"),VF=Symbol.for("react.fragment"),WF=Object.prototype.hasOwnProperty,GF=HF.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,UF={key:!0,ref:!0,__self:!0,__source:!0};function aE(e,t,n){var r,o={},s=null,i=null;n!==void 0&&(s=""+n),t.key!==void 0&&(s=""+t.key),t.ref!==void 0&&(i=t.ref);for(r in t)WF.call(t,r)&&!UF.hasOwnProperty(r)&&(o[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)o[r]===void 0&&(o[r]=t[r]);return{$$typeof:BF,type:e,key:s,ref:i,props:o,_owner:GF.current}}Kg.Fragment=VF;Kg.jsx=aE;Kg.jsxs=aE;ZI.exports=Kg;var v=ZI.exports,cE={exports:{}},Nr={},uE={exports:{}},dE={};/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/(function(e){function t(F,j){var z=F.length;F.push(j);e:for(;0<z;){var H=z-1>>>1,B=F[H];if(0<o(B,j))F[H]=j,F[z]=B,z=H;else break e}}function n(F){return F.length===0?null:F[0]}function r(F){if(F.length===0)return null;var j=F[0],z=F.pop();if(z!==j){F[0]=z;e:for(var H=0,B=F.length,G=B>>>1;H<G;){var V=2*(H+1)-1,Z=F[V],Q=V+1,U=F[Q];if(0>o(Z,z))Q<B&&0>o(U,Z)?(F[H]=U,F[Q]=z,H=Q):(F[H]=Z,F[V]=z,H=V);else if(Q<B&&0>o(U,z))F[H]=U,F[Q]=z,H=Q;else break e}}return j}function o(F,j){var z=F.sortIndex-j.sortIndex;return z!==0?z:F.id-j.id}if(typeof performance=="object"&&typeof performance.now=="function"){var s=performance;e.unstable_now=function(){return s.now()}}else{var i=Date,l=i.now();e.unstable_now=function(){return i.now()-l}}var a=[],c=[],u=1,d=null,f=3,h=!1,g=!1,m=!1,C=typeof setTimeout=="function"?setTimeout:null,b=typeof clearTimeout=="function"?clearTimeout:null,y=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function w(F){for(var j=n(c);j!==null;){if(j.callback===null)r(c);else if(j.startTime<=F)r(c),j.sortIndex=j.expirationTime,t(a,j);else break;j=n(c)}}function S(F){if(m=!1,w(F),!g)if(n(a)!==null)g=!0,_(k);else{var j=n(c);j!==null&&O(S,j.startTime-F)}}function k(F,j){g=!1,m&&(m=!1,b(I),I=-1),h=!0;var z=f;try{for(w(j),d=n(a);d!==null&&(!(d.expirationTime>j)||F&&!D());){var H=d.callback;if(typeof H=="function"){d.callback=null,f=d.priorityLevel;var B=H(d.expirationTime<=j);j=e.unstable_now(),typeof B=="function"?d.callback=B:d===n(a)&&r(a),w(j)}else r(a);d=n(a)}if(d!==null)var G=!0;else{var V=n(c);V!==null&&O(S,V.startTime-j),G=!1}return G}finally{d=null,f=z,h=!1}}var P=!1,M=null,I=-1,E=5,T=-1;function D(){return!(e.unstable_now()-T<E)}function $(){if(M!==null){var F=e.unstable_now();T=F;var j=!0;try{j=M(!0,F)}finally{j?L():(P=!1,M=null)}}else P=!1}var L;if(typeof y=="function")L=function(){y($)};else if(typeof MessageChannel<"u"){var A=new MessageChannel,R=A.port2;A.port1.onmessage=$,L=function(){R.postMessage(null)}}else L=function(){C($,0)};function _(F){M=F,P||(P=!0,L())}function O(F,j){I=C(function(){F(e.unstable_now())},j)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(F){F.callback=null},e.unstable_continueExecution=function(){g||h||(g=!0,_(k))},e.unstable_forceFrameRate=function(F){0>F||125<F?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):E=0<F?Math.floor(1e3/F):5},e.unstable_getCurrentPriorityLevel=function(){return f},e.unstable_getFirstCallbackNode=function(){return n(a)},e.unstable_next=function(F){switch(f){case 1:case 2:case 3:var j=3;break;default:j=f}var z=f;f=j;try{return F()}finally{f=z}},e.unstable_pauseExecution=function(){},e.unstable_requestPaint=function(){},e.unstable_runWithPriority=function(F,j){switch(F){case 1:case 2:case 3:case 4:case 5:break;default:F=3}var z=f;f=F;try{return j()}finally{f=z}},e.unstable_scheduleCallback=function(F,j,z){var H=e.unstable_now();switch(typeof z=="object"&&z!==null?(z=z.delay,z=typeof z=="number"&&0<z?H+z:H):z=H,F){case 1:var B=-1;break;case 2:B=250;break;case 5:B=1073741823;break;case 4:B=1e4;break;default:B=5e3}return B=z+B,F={id:u++,callback:j,priorityLevel:F,startTime:z,expirationTime:B,sortIndex:-1},z>H?(F.sortIndex=z,t(c,F),n(a)===null&&F===n(c)&&(m?(b(I),I=-1):m=!0,O(S,z-H))):(F.sortIndex=B,t(a,F),g||h||(g=!0,_(k))),F},e.unstable_shouldYield=D,e.unstable_wrapCallback=function(F){var j=f;return function(){var z=f;f=j;try{return F.apply(this,arguments)}finally{f=z}}}})(dE);uE.exports=dE;var KF=uE.exports;/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var qF=p,jr=KF;function Ce(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var fE=new Set,Rd={};function ta(e,t){bc(e,t),bc(e+"Capture",t)}function bc(e,t){for(Rd[e]=t,e=0;e<t.length;e++)fE.add(t[e])}var Fs=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Gv=Object.prototype.hasOwnProperty,XF=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,nS={},rS={};function YF(e){return Gv.call(rS,e)?!0:Gv.call(nS,e)?!1:XF.test(e)?rS[e]=!0:(nS[e]=!0,!1)}function QF(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function ZF(e,t,n,r){if(t===null||typeof t>"u"||QF(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function rr(e,t,n,r,o,s,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=s,this.removeEmptyString=i}var Nn={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Nn[e]=new rr(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Nn[t]=new rr(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Nn[e]=new rr(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Nn[e]=new rr(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Nn[e]=new rr(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Nn[e]=new rr(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Nn[e]=new rr(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Nn[e]=new rr(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Nn[e]=new rr(e,5,!1,e.toLowerCase(),null,!1,!1)});var Nx=/[\-:]([a-z])/g;function Hx(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Nx,Hx);Nn[t]=new rr(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Nx,Hx);Nn[t]=new rr(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Nx,Hx);Nn[t]=new rr(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Nn[e]=new rr(e,1,!1,e.toLowerCase(),null,!1,!1)});Nn.xlinkHref=new rr("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Nn[e]=new rr(e,1,!1,e.toLowerCase(),null,!0,!0)});function Bx(e,t,n,r){var o=Nn.hasOwnProperty(t)?Nn[t]:null;(o!==null?o.type!==0:r||!(2<t.length)||t[0]!=="o"&&t[0]!== Line truncated
`+Eb+e}var _b=!1;function Tb(e,t){if(!e||_b)return"";_b=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(t,[])}catch(c){var r=c}Reflect.construct(e,[],t)}else{try{t.call()}catch(c){r=c}e.call(t.prototype)}else{try{throw Error()}catch(c){r=c}e()}}catch(c){if(c&&r&&typeof c.stack=="string"){for(var o=c.stack.split(`
`),s=r.stack.split(`
`),i=o.length-1,l=s.length-1;1<=i&&0<=l&&o[i]!==s[l];)l--;for(;1<=i&&0<=l;i--,l--)if(o[i]!==s[l]){if(i!==1||l!==1)do if(i--,l--,0>l||o[i]!==s[l]){var a=`
`+o[i].replace(" at new "," at ");return e.displayName&&a.includes("<anonymous>")&&(a=a.replace("<anonymous>",e.displayName)),a}while(1<=i&&0<=l);break}}}finally{_b=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Xu(e):""}function JF(e){switch(e.tag){case 5:return Xu(e.type);case 16:return Xu("Lazy");case 13:return Xu("Suspense");case 19:return Xu("SuspenseList");case 0:case 2:case 15:return e=Tb(e.type,!1),e;case 11:return e=Tb(e.type.render,!1),e;case 1:return e=Tb(e.type,!0),e;default:return""}}function Xv(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Ta:return"Fragment";case _a:return"Portal";case Uv:return"Profiler";case Vx:return"StrictMode";case Kv:return"Suspense";case qv:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case pE:return(e.displayName||"Context")+".Consumer";case hE:return(e._context.displayName||"Context")+".Provider";case Wx:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Gx:return t=e.displayName||null,t!==null?t:Xv(e.type)||"Memo";case li:t=e._payload,e=e._init;try{return Xv(e(t))}catch{}}return null}function eL(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Xv(t);case 8:return t===Vx?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ki(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function mE(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function tL(e){var t=mE(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,s=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(i){r=""+i,s.call(this,i)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(i){r=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function sh(e){e._valueTracker||(e._valueTracker=tL(e))}function bE(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=mE(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function _p(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Yv(e,t){var n=t.checked;return Yt({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function sS(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Ki(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function vE(e,t){t=t.checked,t!=null&&Bx(e,"checked",t,!1)}function Qv(e,t){vE(e,t);var n=Ki(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Zv(e,t.type,n):t.hasOwnProperty("defaultValue")&&Zv(e,t.type,Ki(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function iS(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Zv(e,t,n){(t!=="number"||_p(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Yu=Array.isArray;function Ua(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o<n.length;o++)t["$"+n[o]]=!0;for(n=0;n<e.length;n++)o=t.hasOwnProperty("$"+e[n].value),e[n].selected!==o&&(e[n].selected=o),o&&r&&(e[n].defaultSelected=!0)}else{for(n=""+Ki(n),t=null,o=0;o<e.length;o++){if(e[o].value===n){e[o].selected=!0,r&&(e[o].defaultSelected=!0);return}t!==null||e[o].disabled||(t=e[o])}t!==null&&(t.selected=!0)}}function Jv(e,t){if(t.dan Line truncated
`).replace(dD,"")}function hh(e,t,n){if(t=_S(t),_S(e)!==t&&n)throw Error(Ce(425))}function Ap(){}var fy=null,hy=null;function py(e,t){return e==="textarea"||e==="noscript"||typeof t.children=="string"||typeof t.children=="number"||typeof t.dangerouslySetInnerHTML=="object"&&t.dangerouslySetInnerHTML!==null&&t.dangerouslySetInnerHTML.__html!=null}var gy=typeof setTimeout=="function"?setTimeout:void 0,fD=typeof clearTimeout=="function"?clearTimeout:void 0,TS=typeof Promise=="function"?Promise:void 0,hD=typeof queueMicrotask=="function"?queueMicrotask:typeof TS<"u"?function(e){return TS.resolve(null).then(e).catch(pD)}:gy;function pD(e){setTimeout(function(){throw e})}function Vb(e,t){var n=t,r=0;do{var o=n.nextSibling;if(e.removeChild(n),o&&o.nodeType===8)if(n=o.data,n==="/$"){if(r===0){e.removeChild(o),Dd(t);return}r--}else n!=="$"&&n!=="$?"&&n!=="$!"||r++;n=o}while(n);Dd(t)}function Li(e){for(;e!=null;e=e.nextSibling){var t=e.nodeType;if(t===1||t===3)break;if(t===8){if(t=e.data,t==="$"||t==="$!"||t==="$?")break;if(t==="/$")return null}}return e}function RS(e){e=e.previousSibling;for(var t=0;e;){if(e.nodeType===8){var n=e.data;if(n==="$"||n==="$!"||n==="$?"){if(t===0)return e;t--}else n==="/$"&&t++}e=e.previousSibling}return null}var Gc=Math.random().toString(36).slice(2),ts="__reactFiber$"+Gc,Hd="__reactProps$"+Gc,Ls="__reactContainer$"+Gc,my="__reactEvents$"+Gc,gD="__reactListeners$"+Gc,mD="__reactHandles$"+Gc;function bl(e){var t=e[ts];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Ls]||n[ts]){if(n=t.alternate,t.child!==null||n!==null&&n.child!==null)for(e=RS(e);e!==null;){if(n=e[ts])return n;e=RS(e)}return t}e=n,n=e.parentNode}return null}function Of(e){return e=e[ts]||e[Ls],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function Fa(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(Ce(33))}function Zg(e){return e[Hd]||null}var by=[],La=-1;function Ji(e){return{current:e}}function Ht(e){0>La||(e.current=by[La],by[La]=null,La--)}function jt(e,t){La++,by[La]=e.current,e.current=t}var qi={},Xn=Ji(qi),br=Ji(!1),Vl=qi;function vc(e,t){var n=e.type.contextTypes;if(!n)return qi;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},s;for(s in n)o[s]=t[s];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function vr(e){return e=e.childContextTypes,e!=null}function jp(){Ht(br),Ht(Xn)}function OS(e,t,n){if(Xn.current!==qi)throw Error(Ce(168));jt(Xn,t),jt(br,n)}function i_(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(Ce(108,eL(e)||"Unknown",o));return Yt({},n,r)}function zp(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||qi,Vl=Xn.current,jt(Xn,e),jt(br,br.current),!0}function $S(e,t,n){var r=e.stateNode;if(!r)throw Error(Ce(169));n?(e=i_(e,t,Vl),r.__reactInternalMemoizedMergedChildContext=e,Ht(br),Ht(Xn),jt(Xn,e)):Ht(br),jt(br,n)}var ks=null,Jg=!1,Wb=!1;function l_(e){ks===null?ks=[e]:ks.push(e)}function bD(e){Jg=!0,l_(e)}function el(){if(!Wb&&ks!==null){Wb=!0;var e=0,t=It;try{var n=ks;for(It=1;e<n.length;e++){var r=n[e];do r=r(!0);while(r!==null)}ks=null,Jg=!1}catch(o){throw ks!==null&&(ks=ks.slice(e+1)),OE(Kx,el),o}finally{It=t,Wb=!1}}return null}var Da=[],Aa=0,Np=null,Hp=0,Xr=[],Yr=0,Wl=null,_s=1,Ts="";function cl(e,t){Da[Aa++]=Hp,Da[Aa++]=Np,Np=e,Hp=t}function a_(e,t,n){Xr[Yr++]=_s,Xr[Yr++]=Ts,Xr[Yr++]=Wl,Wl=e;var r=_s;e=Ts;var o=32-Ro(r)-1;r&=~(1<<o),n+=1;var s=32-Ro(t)+o;if(30<s){var i=o-o%5;s=(r&(1<<i)-1).toString(32),r>>=i,o-=i,_s=1<<32-Ro(t)+o|n<<o|r,Ts=s+e}else _s=1<<s|n<<o|r,Ts=e}function n0(e){e.return!==null&&(cl(e,1),a_(e,1,0))}function r0(e){for(;e===Np;)Np=Da[--Aa],Da[Aa]=null,Hp=Da[--Aa],Da[Aa]=null;for(;e===Wl;)Wl=Xr[--Yr],Xr[Yr]=null,Ts=Xr[--Yr],Xr[Yr]=null,_s=Xr[--Yr],Xr[Yr]=null}var Fr=null,$r=null,Gt=!1,Eo=null;function c_(e,t){var n=eo(5,null,null,0);n.elementType="DELETED",n.stateNode=t,n.return=e,t=e.deletions,t===null?(e.deletions=[n],e.flags|=16):t.push(n)}function FS(e,t){switch(e.tag){case 5:var n=e.type;return t=t.nodeType!==1||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t,t!==null?(e.stateNode=t,Fr=e,$r=Li(t.firstChild),!0):!1;case 6:return t=e.pendingProps===""||t.nodeType!==3?null:t,t!==null?(e.stateNode=t,Fr=e,$r=null,!0):!1;case 13:return t=t.nodeType!==8?null:t,t!==null?(n=Wl!==null?{id:_s,overflow:Ts}:null,e.memoizedState={dehydrated:t,treeContext:n,retryLane:1073741824},n=eo(18,null,null,0),n.stateNode=t,n.return=e,e.child=n,Fr=e,$r=null,!0):!1;default:return!1}}function vy(e){return(e.mode&1)!==0&&(e.flags&128)===0}function yy(e){if(Gt){var t=$r;if(t){var n=t;if(!FS(e,t)){if(vy(e))throw Error(Ce(418));t=Li(n.nextSibling);var r=Fr;t&&FS(e,t)?c_(r,n):(e.flags=e.flags&-4097|2,Gt=!1,Fr=e)}}else{if(vy(e))throw Error(Ce(418));e.flags=e.flags&-4097|2,Gt=!1,Fr=e}}}function LS(e){ Line truncated
Error generating stack: `+s.message+`
`+s.stack}return{value:e,source:t,stack:o,digest:null}}function Xb(e,t,n){return{value:e,source:null,stack:n??null,digest:t??null}}function Sy(e,t){try{console.error(t.value)}catch(n){setTimeout(function(){throw n})}}var MD=typeof WeakMap=="function"?WeakMap:Map;function D_(e,t,n){n=Os(-1,n),n.tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Xp||(Xp=!0,$y=r),Sy(e,t)},n}function A_(e,t,n){n=Os(-1,n),n.tag=3;var r=e.type.getDerivedStateFromError;if(typeof r=="function"){var o=t.value;n.payload=function(){return r(o)},n.callback=function(){Sy(e,t)}}var s=e.stateNode;return s!==null&&typeof s.componentDidCatch=="function"&&(n.callback=function(){Sy(e,t),typeof r!="function"&&(Ai===null?Ai=new Set([this]):Ai.add(this));var i=t.stack;this.componentDidCatch(t.value,{componentStack:i!==null?i:""})}),n}function VS(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new MD;var o=new Set;r.set(t,o)}else o=r.get(t),o===void 0&&(o=new Set,r.set(t,o));o.has(n)||(o.add(n),e=ND.bind(null,e,t,n),t.then(e,e))}function WS(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function GS(e,t,n,r,o){return e.mode&1?(e.flags|=65536,e.lanes=o,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(t=Os(-1,1),t.tag=2,Di(n,t,1))),n.lanes|=1),e)}var ID=Ws.ReactCurrentOwner,hr=!1;function Zn(e,t,n,r){t.child=e===null?f_(t,null,n,r):xc(t,e.child,n,r)}function US(e,t,n,r,o){n=n.render;var s=t.ref;return Ya(t,o),r=p0(e,t,n,r,s,o),n=g0(),e!==null&&!hr?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,As(e,t,o)):(Gt&&n&&n0(t),t.flags|=1,Zn(e,t,r,o),t.child)}function KS(e,t,n,r,o){if(e===null){var s=n.type;return typeof s=="function"&&!P0(s)&&s.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(t.tag=15,t.type=s,j_(e,t,s,r,o)):(e=lp(n.type,null,r,t,t.mode,o),e.ref=t.ref,e.return=t,t.child=e)}if(s=e.child,!(e.lanes&o)){var i=s.memoizedProps;if(n=n.compare,n=n!==null?n:jd,n(i,r)&&e.ref===t.ref)return As(e,t,o)}return t.flags|=1,e=zi(s,r),e.ref=t.ref,e.return=t,t.child=e}function j_(e,t,n,r,o){if(e!==null){var s=e.memoizedProps;if(jd(s,r)&&e.ref===t.ref)if(hr=!1,t.pendingProps=r=s,(e.lanes&o)!==0)e.flags&131072&&(hr=!0);else return t.lanes=e.lanes,As(e,t,o)}return ky(e,t,n,r,o)}function z_(e,t,n){var r=t.pendingProps,o=r.children,s=e!==null?e.memoizedState:null;if(r.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},jt(Na,Er),Er|=n;else{if(!(n&1073741824))return e=s!==null?s.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,jt(Na,Er),Er|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=s!==null?s.baseLanes:n,jt(Na,Er),Er|=r}else s!==null?(r=s.baseLanes|n,t.memoizedState=null):r=n,jt(Na,Er),Er|=r;return Zn(e,t,o,n),t.child}function N_(e,t){var n=t.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function ky(e,t,n,r,o){var s=vr(n)?Vl:Xn.current;return s=vc(t,s),Ya(t,o),n=p0(e,t,n,r,s,o),r=g0(),e!==null&&!hr?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,As(e,t,o)):(Gt&&r&&n0(t),t.flags|=1,Zn(e,t,n,o),t.child)}function qS(e,t,n,r,o){if(vr(n)){var s=!0;zp(t)}else s=!1;if(Ya(t,o),t.stateNode===null)op(e,t),L_(t,n,r),wy(t,n,r,o),r=!0;else if(e===null){var i=t.stateNode,l=t.memoizedProps;i.props=l;var a=i.context,c=n.contextType;typeof c=="object"&&c!==null?c=ao(c):(c=vr(n)?Vl:Xn.current,c=vc(t,c));var u=n.getDerivedStateFromProps,d=typeof u=="function"||typeof i.getSnapshotBeforeUpdate=="function";d||typeof i.UNSAFE_componentWillReceiveProps!="function"&&typeof i.componentWillReceiveProps!="function"||(l!==r||a!==c)&&BS(t,i,r,c),ai=!1;var f=t.memoizedState;i.state=f,Wp(t,r,i,o),a=t.memoizedState,l!==r||f!==a||br.current||ai?(typeof u=="function"&&(Cy(t,n,u,r),a=t.memoizedState),(l=ai||HS(t,n,l,r,f,a,c))?(d||typeof i.UNSAFE_componentWillMount!="function"&&typeof i.componentWillMount!="function"||(typeof i.componentWillMount=="function"&&i.componentWillMount(),typeof i.UNSAFE_componentWillMount=="function"&&i.UNSAFE_componentWillMount()),typeof i.componentDidMount=="function"&&(t.flags|=4194308)):(typeof i.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=a),i.props=r,i.state=a,i.context=c,r=l):(typeof i.componentDidMount=="function"&&(t.flags|=4194308),r=!1)}else{i=t.stateNode,p_(e,t),l=t.memoizedProps,c=t.type===t.elementType?l:Co(t.type,l),i.props=c,d=t.pendingProps,f=i.context,a=n.contextType,typeof a=="object"&&a!==null?a=ao(a):(a=vr(n)?Vl:Xn.current,a=vc(t,a));var h=n.getDerivedStateFromProps;(u=typeof h=="function"||typeof i.getSnapshotBeforeUpdate=="function")||typeof i.UNSAFE_componentWillReceiveProps!="function"&&typeof i.componentWillReceiveProps!="function"||(l!==d||f!==a)&&BS(t,i,r,a),ai=!1,f=t.memoizedState,i.state=f,Wp(t,r,i,o);var g=t.memoizedS Line truncated
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Fn=typeof Symbol=="function"&&Symbol.for,j0=Fn?Symbol.for("react.element"):60103,z0=Fn?Symbol.for("react.portal"):60106,hm=Fn?Symbol.for("react.fragment"):60107,pm=Fn?Symbol.for("react.strict_mode"):60108,gm=Fn?Symbol.for("react.profiler"):60114,mm=Fn?Symbol.for("react.provider"):60109,bm=Fn?Symbol.for("react.context"):60110,N0=Fn?Symbol.for("react.async_mode"):60111,vm=Fn?Symbol.for("react.concurrent_mode"):60111,ym=Fn?Symbol.for("react.forward_ref"):60112,xm=Fn?Symbol.for("react.suspense"):60113,aj=Fn?Symbol.for("react.suspense_list"):60120,Cm=Fn?Symbol.for("react.memo"):60115,wm=Fn?Symbol.for("react.lazy"):60116,cj=Fn?Symbol.for("react.block"):60121,uj=Fn?Symbol.for("react.fundamental"):60117,dj=Fn?Symbol.for("react.responder"):60118,fj=Fn?Symbol.for("react.scope"):60119;function Br(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case j0:switch(e=e.type,e){case N0:case vm:case hm:case gm:case pm:case xm:return e;default:switch(e=e&&e.$$typeof,e){case bm:case ym:case wm:case Cm:case mm:return e;default:return t}}case z0:return t}}}function OT(e){return Br(e)===vm}_t.AsyncMode=N0;_t.ConcurrentMode=vm;_t.ContextConsumer=bm;_t.ContextProvider=mm;_t.Element=j0;_t.ForwardRef=ym;_t.Fragment=hm;_t.Lazy=wm;_t.Memo=Cm;_t.Portal=z0;_t.Profiler=gm;_t.StrictMode=pm;_t.Suspense=xm;_t.isAsyncMode=function(e){return OT(e)||Br(e)===N0};_t.isConcurrentMode=OT;_t.isContextConsumer=function(e){return Br(e)===bm};_t.isContextProvider=function(e){return Br(e)===mm};_t.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===j0};_t.isForwardRef=function(e){return Br(e)===ym};_t.isFragment=function(e){return Br(e)===hm};_t.isLazy=function(e){return Br(e)===wm};_t.isMemo=function(e){return Br(e)===Cm};_t.isPortal=function(e){return Br(e)===z0};_t.isProfiler=function(e){return Br(e)===gm};_t.isStrictMode=function(e){return Br(e)===pm};_t.isSuspense=function(e){return Br(e)===xm};_t.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===hm||e===vm||e===gm||e===pm||e===xm||e===aj||typeof e=="object"&&e!==null&&(e.$$typeof===wm||e.$$typeof===Cm||e.$$typeof===mm||e.$$typeof===bm||e.$$typeof===ym||e.$$typeof===uj||e.$$typeof===dj||e.$$typeof===fj||e.$$typeof===cj)};_t.typeOf=Br;RT.exports=_t;var hj=RT.exports,$T=hj,pj={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},gj={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},FT={};FT[$T.ForwardRef]=pj;FT[$T.Memo]=gj;var mj=!0;function LT(e,t,n){var r="";return n.split(" ").forEach(function(o){e[o]!==void 0?t.push(e[o]+";"):o&&(r+=o+" ")}),r}var H0=function(t,n,r){var o=t.key+"-"+n.name;(r===!1||mj===!1)&&t.registered[o]===void 0&&(t.registered[o]=n.styles)},B0=function(t,n,r){H0(t,n,r);var o=t.key+"-"+n.name;if(t.inserted[n.name]===void 0){var s=n;do t.insert(n===s?"."+o:"",s,t.sheet,!0),s=s.next;while(s!==void 0)}};function bj(e){for(var t=0,n,r=0,o=e.length;o>=4;++r,o-=4)n=e.charCodeAt(r)&255|(e.charCodeAt(++r)&255)<<8|(e.charCodeAt(++r)&255)<<16|(e.charCodeAt(++r)&255)<<24,n=(n&65535)*1540483477+((n>>>16)*59797<<16),n^=n>>>24,t=(n&65535)*1540483477+((n>>>16)*59797<<16)^(t&65535)*1540483477+((t>>>16)*59797<<16);switch(o){case 3:t^=(e.charCodeAt(r+2)&255)<<16;case 2:t^=(e.charCodeAt(r+1)&255)<<8;case 1:t^=e.charCodeAt(r)&255,t=(t&65535)*1540483477+((t>>>16)*59797<<16)}return t^=t>>>13,t=(t&65535)*1540483477+((t>>>16)*59797<<16),((t^t>>>15)>>>0).toString(36)}var vj={animationIterationCount:1,aspectRatio:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,scale:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},yj=/[A-Z]|^ms/g,xj=/_EMO_([^_]+?)_([^]*?)_EMO_/g,DT=function(t){return t.charCodeAt(1)===45},w1=function(t){return t!=null&&typeof t!="boolean"},Jb=ET(function(e){return DT(e)?e:e.replace(yj,"-$&").toLowerCase()}),S1=function(t,n){switch(t){case"animation":case"animationName":if(typeof n=="string")return n.replace(xj,function(r,o,s){return es={name:o,styles:s,next:es},o})}return vj[t]!==1&&!DT(t)&&typeof n=="number"&&n!==0?n+"px":n};function Zd(e,t,n){if(n==null)return"";var r=n;if(r.__emotion_styles!==void 0)return r;switch(typeof n){case"boolean":return"";case"object":{var o=n;if(o.anim===1)return es={name:o.name,styles:o.styles,next:es},o.name;var s=n;if(s.styles!==void 0){var i=s.next;if(i!==void 0)for(;i!==void 0;)es={name:i.name,styles:i.styles,next:es},i=i.next;var l=s.styles+";";return l}return Cj(e,t,n)}case"function":{if(e!==void 0){var a=es,c=n(e);return es=a,Line truncated
* @license React
* react-is.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var J0=Symbol.for("react.transitional.element"),eC=Symbol.for("react.portal"),_m=Symbol.for("react.fragment"),Tm=Symbol.for("react.strict_mode"),Rm=Symbol.for("react.profiler"),Om=Symbol.for("react.consumer"),$m=Symbol.for("react.context"),Fm=Symbol.for("react.forward_ref"),Lm=Symbol.for("react.suspense"),Dm=Symbol.for("react.suspense_list"),Am=Symbol.for("react.memo"),jm=Symbol.for("react.lazy"),qz=Symbol.for("react.view_transition"),Xz=Symbol.for("react.client.reference");function mo(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case J0:switch(e=e.type,e){case _m:case Rm:case Tm:case Lm:case Dm:case qz:return e;default:switch(e=e&&e.$$typeof,e){case $m:case Fm:case jm:case Am:return e;case Om:return e;default:return t}}case eC:return t}}}Lt.ContextConsumer=Om;Lt.ContextProvider=$m;Lt.Element=J0;Lt.ForwardRef=Fm;Lt.Fragment=_m;Lt.Lazy=jm;Lt.Memo=Am;Lt.Portal=eC;Lt.Profiler=Rm;Lt.StrictMode=Tm;Lt.Suspense=Lm;Lt.SuspenseList=Dm;Lt.isContextConsumer=function(e){return mo(e)===Om};Lt.isContextProvider=function(e){return mo(e)===$m};Lt.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===J0};Lt.isForwardRef=function(e){return mo(e)===Fm};Lt.isFragment=function(e){return mo(e)===_m};Lt.isLazy=function(e){return mo(e)===jm};Lt.isMemo=function(e){return mo(e)===Am};Lt.isPortal=function(e){return mo(e)===eC};Lt.isProfiler=function(e){return mo(e)===Rm};Lt.isStrictMode=function(e){return mo(e)===Tm};Lt.isSuspense=function(e){return mo(e)===Lm};Lt.isSuspenseList=function(e){return mo(e)===Dm};Lt.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===_m||e===Rm||e===Tm||e===Lm||e===Dm||typeof e=="object"&&e!==null&&(e.$$typeof===jm||e.$$typeof===Am||e.$$typeof===$m||e.$$typeof===Om||e.$$typeof===Fm||e.$$typeof===Xz||e.getModuleId!==void 0)};Lt.typeOf=mo;eR.exports=Lt;var og=eR.exports;const Yz=/^\s*function(?:\s|\s*\/\*.*\*\/\s*)+([^(\s/]*)\s*/;function tR(e){const t=`${e}`.match(Yz);return t&&t[1]||""}function nR(e,t=""){return e.displayName||e.name||tR(e)||t}function F1(e,t,n){const r=nR(t);return e.displayName||(r!==""?`${n}(${r})`:n)}function Qz(e){if(e!=null){if(typeof e=="string")return e;if(typeof e=="function")return nR(e,"Component");if(typeof e=="object")switch(e.$$typeof){case og.ForwardRef:return F1(e,e.render,"ForwardRef");case og.Memo:return F1(e,e.type,"memo");default:return}}}const Zz=Object.freeze(Object.defineProperty({__proto__:null,default:Qz,getFunctionName:tR},Symbol.toStringTag,{value:"Module"})),Jz=["ownerState"],eN=["variants"],tN=["name","slot","skipVariantsResolver","skipSx","overridesResolver"];function nN(e){return Object.keys(e).length===0}function rN(e){return typeof e=="string"&&e.charCodeAt(0)>96}function rv(e){return e!=="ownerState"&&e!=="theme"&&e!=="sx"&&e!=="as"}function L1(e,t){return t&&e&&typeof e=="object"&&e.styles&&!e.styles.startsWith("@layer")&&(e.styles=`@layer ${t}{${String(e.styles)}}`),e}const oN=Yc(),sN=e=>e&&e.charAt(0).toLowerCase()+e.slice(1);function Sh({defaultTheme:e,theme:t,themeId:n}){return nN(t)?e:t[n]||t}function iN(e){return e?(t,n)=>n[e]:null}function dp(e,t,n){let{ownerState:r}=t,o=te(t,Jz);const s=typeof e=="function"?e(x({ownerState:r},o)):e;if(Array.isArray(s))return s.flatMap(i=>dp(i,x({ownerState:r},o),n));if(s&&typeof s=="object"&&Array.isArray(s.variants)){const{variants:i=[]}=s;let a=te(s,eN);return i.forEach(c=>{let u=!0;if(typeof c.props=="function"?u=c.props(x({ownerState:r},o,r)):Object.keys(c.props).forEach(d=>{(r==null?void 0:r[d])!==c.props[d]&&o[d]!==c.props[d]&&(u=!1)}),u){Array.isArray(a)||(a=[a]);const d=typeof c.style=="function"?c.style(x({ownerState:r},o,r)):c.style;a.push(n?L1(ng(d),n):d)}}),a}return n?L1(ng(s),n):s}function lN(e={}){const{themeId:t,defaultTheme:n=oN,rootShouldForwardProp:r=rv,slotShouldForwardProp:o=rv}=e,s=i=>Xc(x({},i,{theme:Sh(x({},i,{defaultTheme:n,themeId:t}))}));return s.__mui_systemSx=!0,(i,l={})=>{GT(i,P=>P.filter(M=>!(M!=null&&M.__mui_systemSx)));const{name:a,slot:c,skipVariantsResolver:u,skipSx:d,overridesResolver:f=iN(sN(c))}=l,h=te(l,tN),g=a&&a.startsWith("Mui")||c?"components":"custom",m=u!==void 0?u:c&&c!=="Root"&&c!=="root"||!1,C=d||!1;let b,y=rv;c==="Root"||c==="root"?y=r:c?y=o:rN(i)&&(y=void 0);const w=G0(i,x({shouldForwardProp:y,label:b},h)),S=P=>typeof P=="function"&&P.__emotion_real!==P||Es(P)?M=>{const I=Sh({theme:M.theme,defaultTheme:n,themeId:t});return dp(P,x({},M,{theme:I}),I.modularCssLayers?g:void 0)}:P,k=(P,...M)=>{let I=S(P);const E=M?M.map(S):[];a&&f&&E.push($=>{const L=Sh(x({},$,{defaultTheme:n,themeId:t}));if(!L.components||!L.components[a]||!L.components[a].styleOverrides)return null;const A=L.components[a].styleOverrides,R={};return Object.entries(A).forEach(([_,O])=>{R[_]=dp(O,x({},$,{theme:L}),L.modularCssLayers?"theme":void 0)}),f($,R)}),a&&!m&&E.push($=>{var L;const A=Sh(x({},$,{defaultTheme:n,themeId:t})),R=A==null||(L=A.components)==null||(L=L[a])==null?void 0:L.variants;return dp({variants:R},x({},$,{themeLine truncated
0% {
transform: scale(0);
opacity: 0.1;
}
100% {
transform: scale(1);
opacity: 0.3;
}
`)),j5=jo(ek||(ek=Bm`
0% {
opacity: 1;
}
100% {
opacity: 0;
}
`)),z5=jo(tk||(tk=Bm`
0% {
transform: scale(1);
}
50% {
transform: scale(0.92);
}
100% {
transform: scale(1);
}
`)),N5=re("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),H5=re(F5,{name:"MuiTouchRipple",slot:"Ripple"})(nk||(nk=Bm`
opacity: 0;
position: absolute;
&.${0} {
opacity: 0.3;
transform: scale(1);
animation-name: ${0};
animation-duration: ${0}ms;
animation-timing-function: ${0};
}
&.${0} {
animation-duration: ${0}ms;
}
& .${0} {
opacity: 1;
display: block;
width: 100%;
height: 100%;
border-radius: 50%;
background-color: currentColor;
}
& .${0} {
opacity: 0;
animation-name: ${0};
animation-duration: ${0}ms;
animation-timing-function: ${0};
}
& .${0} {
position: absolute;
/* @noflip */
left: 0px;
top: 0;
animation-name: ${0};
animation-duration: 2500ms;
animation-timing-function: ${0};
animation-iteration-count: infinite;
animation-delay: 200ms;
}
`),qr.rippleVisible,A5,lx,({theme:e})=>e.transitions.easing.easeInOut,qr.ripplePulsate,({theme:e})=>e.transitions.duration.shorter,qr.child,qr.childLeaving,j5,lx,({theme:e})=>e.transitions.easing.easeInOut,qr.childPulsate,z5,({theme:e})=>e.transitions.easing.easeInOut),B5=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiTouchRipple"}),{center:o=!1,classes:s={},className:i}=r,l=te(r,L5),[a,c]=p.useState([]),u=p.useRef(0),d=p.useRef(null);p.useEffect(()=>{d.current&&(d.current(),d.current=null)},[a]);const f=p.useRef(!1),h=pr(),g=p.useRef(null),m=p.useRef(null),C=p.useCallback(S=>{const{pulsate:k,rippleX:P,rippleY:M,rippleSize:I,cb:E}=S;c(T=>[...T,v.jsx(H5,{classes:{ripple:le(s.ripple,qr.ripple),rippleVisible:le(s.rippleVisible,qr.rippleVisible),ripplePulsate:le(s.ripplePulsate,qr.ripplePulsate),child:le(s.child,qr.child),childLeaving:le(s.childLeaving,qr.childLeaving),childPulsate:le(s.childPulsate,qr.childPulsate)},timeout:lx,pulsate:k,rippleX:P,rippleY:M,rippleSize:I},u.current)]),u.current+=1,d.current=E},[s]),b=p.useCallback((S={},k={},P=()=>{})=>{const{pulsate:M=!1,center:I=o||k.pulsate,fakeElement:E=!1}=k;if((S==null?void 0:S.type)==="mousedown"&&f.current){f.current=!1;return}(S==null?void 0:S.type)==="touchstart"&&(f.current=!0);const T=E?null:m.current,D=T?T.getBoundingClientRect():{width:0,height:0,left:0,top:0};let $,L,A;if(I||S===void 0||S.clientX===0&&S.clientY===0||!S.clientX&&!S.touches)$=Math.round(D.width/2),L=Math.round(D.height/2);else{const{clientX:R,clientY:_}=S.touches&&S.touches.length>0?S.touches[0]:S;$=Math.round(R-D.left),L=Math.round(_-D.top)}if(I)A=Math.sqrt((2*D.width**2+D.height**2)/3),A%2===0&&(A+=1);else{const R=Math.max(Math.abs((T?T.clientWidth:0)-$),$)*2+2,_=Math.max(Math.abs((T?T.clientHeight:0)-L),L)*2+2;A=Math.sqrt(R**2+_**2)}S!=null&&S.touches?g.current===null&&(g.current=()=>{C({pulsate:M,rippleX:$,rippleY:L,rippleSize:A,cb:P})},h.start(D5,()=>{g.current&&(g.current(),g.current=null)})):C({pulsate:M,rippleX:$,rippleY:L,rippleSize:A,cb:P})},[o,C,h]),y=p.useCallback(()=>{b({},{pulsate:!0})},[b]),w=p.useCallback((S,k)=>{if(h.clear(),(S==null?void 0:S.type)==="touchend"&&g.current){g.current(),g.current=null,h.start(0,()=>{w(S,k)});return}g.current=null,c(P=>P.length>0?P.slice(1):P),d.current=k},[h]);return p.useImperativeHandle(n,()=>({pulsate:y,start:b,stop:w}),[y,b,w]),v.jsx(N5,x({className:le(qr.root,s.root,i),ref:m},l,{children:v.jsx(uC,{component:null,exit:!0,children:a})}))});function V5(e){return ze("MuiButtonBase",e)}const W5=Ne("MuiButtonBase",["root","disabled","focusVisible"]),G5=["action","centerRipple","children","className","component","disabled","disableRipple","disableTouchRipple","focusRipple","focusVisibleClassName","LinkComponent","onBlur","onClick","onContextMenu","onDragLeave","onFocus","onFocusVisible","onKeyDown","onKeyUp","onMouseDown","onMouseLeave","onMouseUp","onTouchEnd","onTouchMove","onTouchStart","tabIndex","TouchRippleProps","touchRippleRef","type"],U5=e=>{const{disabled:t,focusVisible:n,focusVisibleClassName:r,classes:o}=e,i=ve({root:["root",t&&"disabled",n&&"focusVisible"]},V5,o);return n&&r&&(i.root+=` ${r}`),i},K5=re("button",{name:"MuiButtonBase",slot:"Root",overridesResolver:(e,t)=>t.root})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${W5.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),Xi=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiButtonBase"}),{action:o,centerRipple:s=!1,children:i,className:l,component:a="button",disabled:c=!1,disableRipple:u=!1,disableTouchRipple:d=!1,focusRipple:f=!1,LinkComponent:h="a",onBlur:g,onClick:m,onContextMenu:C,onDragLeave:b,onFocus:y,onFocusVisible:w,onKeyDown:S,onKeyUp:k,onMouseDown:P,onMouseLeave:M,onMouseUp:I,onTouchEnd:E,onTouchMove:T,onTouchStart:D,tabIndex:$=0,TouchRippleProps:L,touchRippleRef:A,type:R}=r,_=te(r,G5),O=p.useRef(null),F=p.useRef(null),j=vt(F,A),{isFocusVisibleRef:z,onFocus:H,onBlur:B,ref:G}=Hm(),[V,Z]=p.useState(!1);c&&V&&Z(!1),p.useImperativeHandle(o,()=>({focusVisible:()=>{Z(!0),O.current.focus()}}),[]);const[Q,U]=p.useState(!1);p.useEffect(()=>{U(!0)},[]);const K=Q&&!u&&!c;p.useEffect(()=>{V&&f&&!u&&Q&&F.current.pulsate()},[u,f,V,Q]);function ee(Y,xe,Re=d){return Ke(Ze=>(xe&&xe(Ze),!Re&&F.current&&F.current[Y](Ze),!0))}const de=ee("start",P),se=ee("stop",C),ge=ee("stop",b),q=ee("stop",I),me=ee("stop",Y=>{V&&Y.preventDefault(),M&&M(Y)}),ae=ee("start",D),ce=ee("stop",E),ye=ee("stop",T),ne=ee("stop",Y=>{B(Y),z.current===!1&&Z(!1),g&&g(Y)},!1),Oe=Ke(Y=>{O.current||(O.current=Y.currentTarget),H(Y),z.current===!0&&(Z(!0),w&&w(Y)),y&&y(Y)}),_e=()=>{const Y Line truncated
`&&(S.value+=" ");const M=P.boxSizing,I=Ih(P.paddingBottom)+Ih(P.paddingTop),E=Ih(P.borderBottomWidth)+Ih(P.borderTopWidth),T=S.scrollHeight;S.value="x";const D=S.scrollHeight;let $=T;s&&($=Math.max(Number(s)*D,$)),o&&($=Math.min(Number(o)*D,$)),$=Math.max($,D);const L=$+(M==="border-box"?I+E:0),A=Math.abs($-T)<=1;return{outerHeightStyle:L,overflowing:A}},[o,s,t.placeholder]),m=Ke(()=>{const w=u.current,S=g();if(!w||!S||yk(S))return!1;const k=S.outerHeightStyle;return f.current!=null&&f.current!==k}),C=p.useCallback(()=>{const w=u.current,S=g();if(!w||!S||yk(S))return;const k=S.outerHeightStyle;f.current!==k&&(f.current=k,w.style.height=`${k}px`),w.style.overflow=S.overflowing?"hidden":""},[g]),b=p.useRef(-1);Et(()=>{const w=Qc(C),S=u==null?void 0:u.current;if(!S)return;const k=Do(S);k.addEventListener("resize",w);let P;return typeof ResizeObserver<"u"&&(P=new ResizeObserver(()=>{m()&&(P.unobserve(S),cancelAnimationFrame(b.current),C(),b.current=requestAnimationFrame(()=>{P.observe(S)}))}),P.observe(S)),()=>{w.clear(),cancelAnimationFrame(b.current),k.removeEventListener("resize",w),P&&P.disconnect()}},[g,C,m]),Et(()=>{C()});const y=w=>{c||C(),r&&r(w)};return v.jsxs(p.Fragment,{children:[v.jsx("textarea",x({value:l,onChange:y,ref:d,rows:s,style:i},a)),v.jsx("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:h,tabIndex:-1,style:x({},e3.shadow,i,{paddingTop:0,paddingBottom:0})})]})});function sa({props:e,states:t,muiFormControl:n}){return t.reduce((r,o)=>(r[o]=e[o],n&&typeof e[o]>"u"&&(r[o]=n[o]),r),{})}const Gm=p.createContext(void 0);function Us(){return p.useContext(Gm)}function xk(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function dg(e,t=!1){return e&&(xk(e.value)&&e.value!==""||t&&xk(e.defaultValue)&&e.defaultValue!=="")}function r3(e){return e.startAdornment}function o3(e){return ze("MuiInputBase",e)}const Rn=Ne("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),s3=["aria-describedby","autoComplete","autoFocus","className","color","components","componentsProps","defaultValue","disabled","disableInjectingGlobalStyles","endAdornment","error","fullWidth","id","inputComponent","inputProps","inputRef","margin","maxRows","minRows","multiline","name","onBlur","onChange","onClick","onFocus","onKeyDown","onKeyUp","placeholder","readOnly","renderSuffix","rows","size","slotProps","slots","startAdornment","type","value"],Um=(e,t)=>{const{ownerState:n}=e;return[t.root,n.formControl&&t.formControl,n.startAdornment&&t.adornedStart,n.endAdornment&&t.adornedEnd,n.error&&t.error,n.size==="small"&&t.sizeSmall,n.multiline&&t.multiline,n.color&&t[`color${oe(n.color)}`],n.fullWidth&&t.fullWidth,n.hiddenLabel&&t.hiddenLabel]},Km=(e,t)=>{const{ownerState:n}=e;return[t.input,n.size==="small"&&t.inputSizeSmall,n.multiline&&t.inputMultiline,n.type==="search"&&t.inputTypeSearch,n.startAdornment&&t.inputAdornedStart,n.endAdornment&&t.inputAdornedEnd,n.hiddenLabel&&t.inputHiddenLabel]},i3=e=>{const{classes:t,color:n,disabled:r,error:o,endAdornment:s,focused:i,formControl:l,fullWidth:a,hiddenLabel:c,multiline:u,readOnly:d,size:f,startAdornment:h,type:g}=e,m={root:["root",`color${oe(n)}`,r&&"disabled",o&&"error",a&&"fullWidth",i&&"focused",l&&"formControl",f&&f!=="medium"&&`size${oe(f)}`,u&&"multiline",h&&"adornedStart",s&&"adornedEnd",c&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",g==="search"&&"inputTypeSearch",u&&"inputMultiline",f==="small"&&"inputSizeSmall",c&&"inputHiddenLabel",h&&"inputAdornedStart",s&&"inputAdornedEnd",d&&"readOnly"]};return ve(m,o3,t)},qm=re("div",{name:"MuiInputBase",slot:"Root",overridesResolver:Um})(({theme:e,ownerState:t})=>x({},e.typography.body1,{color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Rn.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"}},t.multiline&&x({padding:"4px 0 5px"},t.size==="small"&&{paddingTop:1}),t.fullWidth&&{width:"100%"})),Xm=re("input",{name:"MuiInputBase",slot:"Input",overridesResolver:Km})(({theme:e,ownerState:t})=>{const n=e.palette.mode==="light",r=x({color:"currentColor"},e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:n?.42:.5},{transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})}),o={opacity:"0 !important"},s=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:n?.42:.5};return x({font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%",animationName:"mui-auto-fill-cancel",animationDuration:"10ms","&::-webkit-input-placeholder":r,"&::-mo Line truncated
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
`)),mV=jo(kk||(kk=Ym`
0% {
stroke-dasharray: 1px, 200px;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100px, 200px;
stroke-dashoffset: -15px;
}
100% {
stroke-dasharray: 100px, 200px;
stroke-dashoffset: -125px;
}
`)),bV=e=>{const{classes:t,variant:n,color:r,disableShrink:o}=e,s={root:["root",n,`color${oe(r)}`],svg:["svg"],circle:["circle",`circle${oe(n)}`,o&&"circleDisableShrink"]};return ve(s,hV,t)},vV=re("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,t[n.variant],t[`color${oe(n.color)}`]]}})(({ownerState:e,theme:t})=>x({display:"inline-block"},e.variant==="determinate"&&{transition:t.transitions.create("transform")},e.color!=="inherit"&&{color:(t.vars||t).palette[e.color].main}),({ownerState:e})=>e.variant==="indeterminate"&&zs(Pk||(Pk=Ym`
animation: ${0} 1.4s linear infinite;
`),gV)),yV=re("svg",{name:"MuiCircularProgress",slot:"Svg",overridesResolver:(e,t)=>t.svg})({display:"block"}),xV=re("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.circle,t[`circle${oe(n.variant)}`],n.disableShrink&&t.circleDisableShrink]}})(({ownerState:e,theme:t})=>x({stroke:"currentColor"},e.variant==="determinate"&&{transition:t.transitions.create("stroke-dashoffset")},e.variant==="indeterminate"&&{strokeDasharray:"80px, 200px",strokeDashoffset:0}),({ownerState:e})=>e.variant==="indeterminate"&&!e.disableShrink&&zs(Mk||(Mk=Ym`
animation: ${0} 1.4s ease-in-out infinite;
`),mV)),CV=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiCircularProgress"}),{className:o,color:s="primary",disableShrink:i=!1,size:l=40,style:a,thickness:c=3.6,value:u=0,variant:d="indeterminate"}=r,f=te(r,pV),h=x({},r,{color:s,disableShrink:i,size:l,thickness:c,value:u,variant:d}),g=bV(h),m={},C={},b={};if(d==="determinate"){const y=2*Math.PI*((ti-c)/2);m.strokeDasharray=y.toFixed(3),b["aria-valuenow"]=Math.round(u),m.strokeDashoffset=`${((100-u)/100*y).toFixed(3)}px`,C.transform="rotate(-90deg)"}return v.jsx(vV,x({className:le(g.root,o),style:x({width:l,height:l},C,a),ownerState:h,ref:n,role:"progressbar"},b,f,{children:v.jsx(yV,{className:g.svg,ownerState:h,viewBox:`${ti/2} ${ti/2} ${ti} ${ti}`,children:v.jsx(xV,{className:g.circle,style:m,ownerState:h,cx:ti,cy:ti,r:(ti-c)/2,fill:"none",strokeWidth:c})})}))});function Ik(e){return e.substring(2).toLowerCase()}function wV(e,t){return t.documentElement.clientWidth<e.clientX||t.documentElement.clientHeight<e.clientY}function CC(e){const{children:t,disableReactTree:n=!1,mouseEvent:r="onClick",onClickAway:o,touchEvent:s="onTouchEnd"}=e,i=p.useRef(!1),l=p.useRef(null),a=p.useRef(!1),c=p.useRef(!1);p.useEffect(()=>(setTimeout(()=>{a.current=!0},0),()=>{a.current=!1}),[]);const u=vt(ra(t),l),d=Ke(g=>{const m=c.current;c.current=!1;const C=Ft(l.current);if(!a.current||!l.current||"clientX"in g&&wV(g,C))return;if(i.current){i.current=!1;return}let b;g.composedPath?b=g.composedPath().indexOf(l.current)>-1:b=!C.documentElement.contains(g.target)||l.current.contains(g.target),!b&&(n||!m)&&o(g)}),f=g=>m=>{c.current=!0;const C=t.props[g];C&&C(m)},h={ref:u};return s!==!1&&(h[s]=f(s)),p.useEffect(()=>{if(s!==!1){const g=Ik(s),m=Ft(l.current),C=()=>{i.current=!0};return m.addEventListener(g,d),m.addEventListener("touchmove",C),()=>{m.removeEventListener(g,d),m.removeEventListener("touchmove",C)}}},[d,s]),r!==!1&&(h[r]=f(r)),p.useEffect(()=>{if(r!==!1){const g=Ik(r),m=Ft(l.current);return m.addEventListener(g,d),()=>{m.removeEventListener(g,d)}}},[d,r]),v.jsx(p.Fragment,{children:p.cloneElement(t,h)})}const SV=WN({createStyledComponent:re("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,t[`maxWidth${oe(String(n.maxWidth))}`],n.fixed&&t.fixed,n.disableGutters&&t.disableGutters]}}),useThemeProps:e=>We({props:e,name:"MuiContainer"})});function kV(e){const t=Ft(e);return t.body===e?Do(e).innerWidth>t.documentElement.clientWidth:e.scrollHeight>e.clientHeight}function Sd(e,t){t?e.setAttribute("aria-hidden","true"):e.removeAttribute("aria-hidden")}function Ek(e){return parseInt(Do(e).getComputedStyle(e).paddingRight,10)||0}function PV(e){const n=["TEMPLATE","SCRIPT","STYLE","LINK","MAP","META","NOSCRIPT","PICTURE","COL","COLGROUP","PARAM","SLOT","SOURCE","TRACK"].indexOf(e.tagName)!==-1,r=e.tagName==="INPUT"&&e.getAttribute("type")==="hidden";return n||r}function _k(e,t,n,r,o){const s=[t,n,...r];[].forEach.call(e.children,i=>{const l=s.indexOf(i)===-1,a=!PV(i);l&&a&&Sd(i,o)})}function dv(e,t){let n=-1;return e.some((r,o)=>t(r)?(n=o,!0):!1),n}function MV(e,t){const n=[],r=e.container;if(!t.disableScrollLock){if(kV(r)){const i=iR(Ft(r));n.push({value:r.style.paddingRight,property:"padding-right",el:r}),r.style.paddingRight=`${Ek(r)+i}px`;const l=Ft(r).querySelectorAll(".mui-fixed");[].forEach.call(l,a=>{n.push({value:a.style.paddingRight,property:"padding-right",el:a}),a.style.paddingRight=`${Ek(a)+i}px`})}let s;if(r.parentNode instanceof DocumentFragment)s=Ft(r).body;else{const i=r.parentElement,l=Do(r);s=(i==null?void 0:i.nodeName)==="HTML"&&l.getComputedStyle(i).overflowY==="scroll"?i:r}n.push({value:s.style.overflow,property:"overflow",el:s},{value:s.style.overflowX,property:"overflow-x",el:s},{value:s.style.overflowY,property:"overflow-y",el:s}),s.style.overflow="hidden"}return()=>{n.forEach(({value:s,el:i,property:l})=>{s?i.style.setProperty(l,s):i.style.removeProperty(l)})}}function IV(e){const t=[];return[].forEach.call(e.children,n=>{n.getAttribute("aria-hidden")==="true"&&t.push(n)}),t}class EV{constructor(){this.containers=void 0,this.modals=void 0,this.modals=[],this.containers=[]}add(t,n){let r=this.modals.indexOf(t);if(r!==-1)return r;r=this.modals.length,this.modals.push(t),t.modalRef&&Sd(t.modalRef,!1);const o=IV(n);_k(n,t.mount,t.modalRef,o,!0);const s=dv(this.containers,i=>i.container===n);return s!==-1?(this.containers[s].modals.push(t),r):(this.containers.push({modals:[t],container:n,restore:null,hiddenSiblings:o}),r)}mount(t,n){const r=dv(this.containers,s=>s.modals.indexOf(t)!==-1),o=this.containers[r];o.restore||(o.restore=MV(o,n))}remove(t,n=!0){const r=this.modals.indexOf(t);if(r===-1)return r;const o=dv(this.containers,i=>i.modals.indexOf(t)!==-1),s=this.containers[o];if(s.modals.splice(s.modals.indexOf(t),1),this.modals.splice(r,1),s.modals.length===0)s.restore&&s.restore(),t.modalRef&&Sd(t.modalRef,n),_k(s.container,t.mount,t.modalRef,s.hiddenSiblings,!1),this.containers.splice(o,1);else Line truncated
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
`)),mG=jo(Ak||(Ak=iu`
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
`)),bG=jo(jk||(jk=iu`
0% {
opacity: 1;
background-position: 0 -23px;
}
60% {
opacity: 0;
background-position: 0 -23px;
}
100% {
opacity: 1;
background-position: -200px -23px;
}
`)),vG=e=>{const{classes:t,variant:n,color:r}=e,o={root:["root",`color${oe(r)}`,n],dashed:["dashed",`dashedColor${oe(r)}`],bar1:["bar",`barColor${oe(r)}`,(n==="indeterminate"||n==="query")&&"bar1Indeterminate",n==="determinate"&&"bar1Determinate",n==="buffer"&&"bar1Buffer"],bar2:["bar",n!=="buffer"&&`barColor${oe(r)}`,n==="buffer"&&`color${oe(r)}`,(n==="indeterminate"||n==="query")&&"bar2Indeterminate",n==="buffer"&&"bar2Buffer"]};return ve(o,hG,t)},PC=(e,t)=>t==="inherit"?"currentColor":e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?of(e.palette[t].main,.62):rf(e.palette[t].main,.5),yG=re("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,t[`color${oe(n.color)}`],t[n.variant]]}})(({ownerState:e,theme:t})=>x({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},backgroundColor:PC(t,e.color)},e.color==="inherit"&&e.variant!=="buffer"&&{backgroundColor:"none","&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}},e.variant==="buffer"&&{backgroundColor:"transparent"},e.variant==="query"&&{transform:"rotate(180deg)"})),xG=re("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.dashed,t[`dashedColor${oe(n.color)}`]]}})(({ownerState:e,theme:t})=>{const n=PC(t,e.color);return x({position:"absolute",marginTop:0,height:"100%",width:"100%"},e.color==="inherit"&&{opacity:.3},{backgroundImage:`radial-gradient(${n} 0%, ${n} 16%, transparent 42%)`,backgroundSize:"10px 10px",backgroundPosition:"0 -23px"})},zs(zk||(zk=iu`
animation: ${0} 3s infinite linear;
`),bG)),CG=re("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.bar,t[`barColor${oe(n.color)}`],(n.variant==="indeterminate"||n.variant==="query")&&t.bar1Indeterminate,n.variant==="determinate"&&t.bar1Determinate,n.variant==="buffer"&&t.bar1Buffer]}})(({ownerState:e,theme:t})=>x({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",backgroundColor:e.color==="inherit"?"currentColor":(t.vars||t).palette[e.color].main},e.variant==="determinate"&&{transition:`transform .${fx}s linear`},e.variant==="buffer"&&{zIndex:1,transition:`transform .${fx}s linear`}),({ownerState:e})=>(e.variant==="indeterminate"||e.variant==="query")&&zs(Nk||(Nk=iu`
width: auto;
animation: ${0} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
`),gG)),wG=re("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.bar,t[`barColor${oe(n.color)}`],(n.variant==="indeterminate"||n.variant==="query")&&t.bar2Indeterminate,n.variant==="buffer"&&t.bar2Buffer]}})(({ownerState:e,theme:t})=>x({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left"},e.variant!=="buffer"&&{backgroundColor:e.color==="inherit"?"currentColor":(t.vars||t).palette[e.color].main},e.color==="inherit"&&{opacity:.3},e.variant==="buffer"&&{backgroundColor:PC(t,e.color),transition:`transform .${fx}s linear`}),({ownerState:e})=>(e.variant==="indeterminate"||e.variant==="query")&&zs(Hk||(Hk=iu`
width: auto;
animation: ${0} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
`),mG)),SG=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiLinearProgress"}),{className:o,color:s="primary",value:i,valueBuffer:l,variant:a="indeterminate"}=r,c=te(r,pG),u=x({},r,{color:s,variant:a}),d=vG(u),f=Zc(),h={},g={bar1:{},bar2:{}};if((a==="determinate"||a==="buffer")&&i!==void 0){h["aria-valuenow"]=Math.round(i),h["aria-valuemin"]=0,h["aria-valuemax"]=100;let m=i-100;f&&(m=-m),g.bar1.transform=`translateX(${m}%)`}if(a==="buffer"&&l!==void 0){let m=(l||0)-100;f&&(m=-m),g.bar2.transform=`translateX(${m}%)`}return v.jsxs(yG,x({className:le(d.root,o),ownerState:u,role:"progressbar"},h,{ref:n},c,{children:[a==="buffer"?v.jsx(xG,{className:d.dashed,ownerState:u}):null,v.jsx(CG,{className:d.bar1,ownerState:u,style:g.bar1}),a==="determinate"?null:v.jsx(wG,{className:d.bar2,ownerState:u,style:g.bar2})]}))});function kG(e){return ze("MuiLink",e)}const PG=Ne("MuiLink",["root","underlineNone","underlineHover","underlineAlways","button","focusVisible"]),eO={primary:"primary.main",textPrimary:"text.primary",secondary:"secondary.main",textSecondary:"text.secondary",error:"error.main"},MG=e=>eO[e]||e,IG=({theme:e,ownerState:t})=>{const n=MG(t.color),r=Mc(e,`palette.${n}`,!1)||t.color,o=Mc(e,`palette.${n}Channel`);return"vars"in e&&o?`rgba(${o} / 0.4)`:bt(r,.4)},EG=["className","color","component","onBlur","onFocus","TypographyClasses","underline","variant","sx"],_G=e=>{const{classes:t,component:n,focusVisible:r,underline:o}=e,s={root:["root",`underline${oe(o)}`,n==="button"&&"button",r&&"focusVisible"]};return ve(s,kG,t)},TG=re(ot,{name:"MuiLink",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,t[`underline${oe(n.underline)}`],n.component==="button"&&t.button]}})(({theme:e,ownerState:t})=>x({},t.underline==="none"&&{textDecoration:"none"},t.underline==="hover"&&{textDecoration:"none","&:hover":{textDecoration:"underline"}},t.underline==="always"&&x({textDecoration:"underline"},t.color!=="inherit"&&{textDecorationColor:IG({theme:e,ownerState:t})},{"&:hover":{textDecorationColor:"inherit"}}),t.component==="button"&&{position:"relative",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none","&::-moz-focus-inner":{borderStyle:"none"},[`&.${PG.focusVisible}`]:{outline:"auto"}})),pi=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiLink"}),{className:o,color:s="primary",component:i="a",onBlur:l,onFocus:a,TypographyClasses:c,underline:u="always",variant:d="inherit",sx:f}=r,h=te(r,EG),{isFocusVisibleRef:g,onBlur:m,onFocus:C,ref:b}=Hm(),[y,w]=p.useState(!1),S=vt(n,b),k=E=>{m(E),g.current===!1&&w(!1),l&&l(E)},P=E=>{C(E),g.current===!0&&w(!0),a&&a(E)},M=x({},r,{color:s,component:i,focusVisible:y,underline:u,variant:d}),I=_G(M);return v.jsx(TG,x({color:s,className:le(I.root,o),classes:c,component:i,onBlur:k,onFocus:P,ref:S,ownerState:M,variant:d,sx:[...Object.keys(eO).includes(s)?[]:[{color:s}],...Array.isArray(f)?f:[f]]},h))}),uf=p.createContext({});function RG(e){return ze("MuiList",e)}Ne("MuiList",["root","padding","dense","subheader"]);const OG=["children","className","component","dense","disablePadding","subheader"],$G=e=>{const{classes:t,disablePadding:n,dense:r,subheader:o}=e;return ve({root:["root",!n&&"padding",r&&"dense",o&&"subheader"]},RG,t)},FG=re("ul",{name:"MuiList",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,!n.disablePadding&&t.padding,n.dense&&t.dense,n.subheader&&t.subheader]}})(({ownerState:e})=>x({listStyle:"none",margin:0,padding:0,position:"relative"},!e.disablePadding&&{paddingTop:8,paddingBottom:8},e.subheader&&{paddingTop:0})),LG=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiList"}),{children:o,className:s,component:i="ul",dense:l=!1,disablePadding:a=!1,subheader:c}=r,u=te(r,OG),d=p.useMemo(()=>({dense:l}),[l]),f=x({},r,{component:i,dense:l,disablePadding:a}),h=$G(f);return v.jsx(uf.Provider,{value:d,children:v.jsxs(FG,x({as:i,className:le(h.root,s),ref:n,ownerState:f},u,{children:[c,o]}))})});function DG(e){return ze("MuiListItemIcon",e)}const Bk=Ne("MuiListItemIcon",["root","alignItemsFlexStart"]),AG=["className"],jG=e=>{const{alignItems:t,classes:n}=e;return ve({root:["root",t==="flex-start"&&"alignItemsFlexStart"]},DG,n)},zG=re("div",{name:"MuiListItemIcon",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,n.alignItems==="flex-start"&&t.alignItemsFlexStart]}})(({theme:e,ownerState:t})=>x({minWidth:56,color:(e.vars||e).palette.action.active,flexShrink:0,display:"inline-flex"},t.alignItems==="flex-start"&&{marginTop:8})),Bi=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiListItemIcon"}),{className:o}=r,s=te(r,AG),i=p.useContext(uf),l=x({},r,{alignItems:i.alignItems}),a=jG(l);return v.jsx(zG,x({className:le(a.root,o),ownerState:l,ref:n},s))});function NG(e){return ze("MuiListItemText",e)}const hg=Ne("MuiListItemText",[" Line truncated
0% {
opacity: 1;
}
50% {
opacity: 0.4;
}
100% {
opacity: 1;
}
`)),K6=jo(Qk||(Qk=pg`
0% {
transform: translateX(-100%);
}
50% {
/* +0.5s of delay between each loop */
transform: translateX(100%);
}
100% {
transform: translateX(100%);
}
`)),q6=re("span",{name:"MuiSkeleton",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,t[n.variant],n.animation!==!1&&t[n.animation],n.hasChildren&&t.withChildren,n.hasChildren&&!n.width&&t.fitContent,n.hasChildren&&!n.height&&t.heightAuto]}})(({theme:e,ownerState:t})=>{const n=AH(e.shape.borderRadius)||"px",r=jH(e.shape.borderRadius);return x({display:"block",backgroundColor:e.vars?e.vars.palette.Skeleton.bg:Cl(e.palette.text.primary,e.palette.mode==="light"?.11:.13),height:"1.2em"},t.variant==="text"&&{marginTop:0,marginBottom:0,height:"auto",transformOrigin:"0 55%",transform:"scale(1, 0.60)",borderRadius:`${r}${n}/${Math.round(r/.6*10)/10}${n}`,"&:empty:before":{content:'"\\00a0"'}},t.variant==="circular"&&{borderRadius:"50%"},t.variant==="rounded"&&{borderRadius:(e.vars||e).shape.borderRadius},t.hasChildren&&{"& > *":{visibility:"hidden"}},t.hasChildren&&!t.width&&{maxWidth:"fit-content"},t.hasChildren&&!t.height&&{height:"auto"})},({ownerState:e})=>e.animation==="pulse"&&zs(Zk||(Zk=pg`
animation: ${0} 2s ease-in-out 0.5s infinite;
`),U6),({ownerState:e,theme:t})=>e.animation==="wave"&&zs(Jk||(Jk=pg`
position: relative;
overflow: hidden;
/* Fix bug in Safari https://bugs.webkit.org/show_bug.cgi?id=68196 */
-webkit-mask-image: -webkit-radial-gradient(white, black);
&::after {
animation: ${0} 2s linear 0.5s infinite;
background: linear-gradient(
90deg,
transparent,
${0},
transparent
);
content: '';
position: absolute;
transform: translateX(-100%); /* Avoid flash during server-side hydration */
bottom: 0;
left: 0;
right: 0;
top: 0;
}
`),K6,(t.vars||t).palette.action.hover)),X6=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiSkeleton"}),{animation:o="pulse",className:s,component:i="span",height:l,style:a,variant:c="text",width:u}=r,d=te(r,W6),f=x({},r,{animation:o,component:i,variant:c,hasChildren:!!d.children}),h=G6(f);return v.jsx(q6,x({as:i,ref:n,className:le(h.root,s),ownerState:f},d,{style:x({width:u,height:l},a)}))});function Y6(e={}){const{autoHideDuration:t=null,disableWindowBlurListener:n=!1,onClose:r,open:o,resumeHideDuration:s}=e,i=pr();p.useEffect(()=>{if(!o)return;function b(y){y.defaultPrevented||(y.key==="Escape"||y.key==="Esc")&&(r==null||r(y,"escapeKeyDown"))}return document.addEventListener("keydown",b),()=>{document.removeEventListener("keydown",b)}},[o,r]);const l=Ke((b,y)=>{r==null||r(b,y)}),a=Ke(b=>{!r||b==null||i.start(b,()=>{l(null,"timeout")})});p.useEffect(()=>(o&&a(t),i.clear),[o,t,a,i]);const c=b=>{r==null||r(b,"clickaway")},u=i.clear,d=p.useCallback(()=>{t!=null&&a(s??t*.5)},[t,s,a]),f=b=>y=>{const w=b.onBlur;w==null||w(y),d()},h=b=>y=>{const w=b.onFocus;w==null||w(y),u()},g=b=>y=>{const w=b.onMouseEnter;w==null||w(y),u()},m=b=>y=>{const w=b.onMouseLeave;w==null||w(y),d()};return p.useEffect(()=>{if(!n&&o)return window.addEventListener("focus",d),window.addEventListener("blur",u),()=>{window.removeEventListener("focus",d),window.removeEventListener("blur",u)}},[n,o,d,u]),{getRootProps:(b={})=>{const y=x({},sg(e),sg(b));return x({role:"presentation"},b,y,{onBlur:f(y),onFocus:h(y),onMouseEnter:g(y),onMouseLeave:m(y)})},onClickAway:c}}function Q6(e){return ze("MuiSnackbarContent",e)}Ne("MuiSnackbarContent",["root","message","action"]);const Z6=["action","className","message","role"],J6=e=>{const{classes:t}=e;return ve({root:["root"],action:["action"],message:["message"]},Q6,t)},eU=re(Gs,{name:"MuiSnackbarContent",slot:"Root",overridesResolver:(e,t)=>t.root})(({theme:e})=>{const t=e.palette.mode==="light"?.8:.98,n=nH(e.palette.background.default,t);return x({},e.typography.body2,{color:e.vars?e.vars.palette.SnackbarContent.color:e.palette.getContrastText(n),backgroundColor:e.vars?e.vars.palette.SnackbarContent.bg:n,display:"flex",alignItems:"center",flexWrap:"wrap",padding:"6px 16px",borderRadius:(e.vars||e).shape.borderRadius,flexGrow:1,[e.breakpoints.up("sm")]:{flexGrow:"initial",minWidth:288}})}),tU=re("div",{name:"MuiSnackbarContent",slot:"Message",overridesResolver:(e,t)=>t.message})({padding:"8px 0"}),nU=re("div",{name:"MuiSnackbarContent",slot:"Action",overridesResolver:(e,t)=>t.action})({display:"flex",alignItems:"center",marginLeft:"auto",paddingLeft:16,marginRight:-8}),rU=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiSnackbarContent"}),{action:o,className:s,message:i,role:l="alert"}=r,a=te(r,Z6),c=r,u=J6(c);return v.jsxs(eU,x({role:l,square:!0,elevation:6,className:le(u.root,s),ownerState:c,ref:n},a,{children:[v.jsx(tU,{className:u.message,ownerState:c,children:i}),o?v.jsx(nU,{className:u.action,ownerState:c,children:o}):null]}))});function oU(e){return ze("MuiSnackbar",e)}Ne("MuiSnackbar",["root","anchorOriginTopCenter","anchorOriginBottomCenter","anchorOriginTopRight","anchorOriginBottomRight","anchorOriginTopLeft","anchorOriginBottomLeft"]);const sU=["onEnter","onExited"],iU=["action","anchorOrigin","autoHideDuration","children","className","ClickAwayListenerProps","ContentProps","disableWindowBlurListener","message","onBlur","onClose","onFocus","onMouseEnter","onMouseLeave","open","resumeHideDuration","TransitionComponent","transitionDuration","TransitionProps"],lU=e=>{const{classes:t,anchorOrigin:n}=e,r={root:["root",`anchorOrigin${oe(n.vertical)}${oe(n.horizontal)}`]};return ve(r,oU,t)},eP=re("div",{name:"MuiSnackbar",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,t[`anchorOrigin${oe(n.anchorOrigin.vertical)}${oe(n.anchorOrigin.horizontal)}`]]}})(({theme:e,ownerState:t})=>{const n={left:"50%",right:"auto",transform:"translateX(-50%)"};return x({zIndex:(e.vars||e).zIndex.snackbar,position:"fixed",display:"flex",left:8,right:8,justifyContent:"center",alignItems:"center"},t.anchorOrigin.vertical==="top"?{top:8}:{bottom:8},t.anchorOrigin.horizontal==="left"&&{justifyContent:"flex-start"},t.anchorOrigin.horizontal==="right"&&{justifyContent:"flex-end"},{[e.breakpoints.up("sm")]:x({},t.anchorOrigin.vertical==="top"?{top:24}:{bottom:24},t.anchorOrigin.horizontal==="center"&&n,t.anchorOrigin.horizontal==="left"&&{left:24,right:"auto"},t.anchorOrigin.horizontal==="right"&&{right:24,left:"auto"})})}),aU=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiSnackbar"}),o=tl(),s={enter:o.transitions.duration.enteringScreen,exit:o.transitions.duration.leavingScreen},{action:i,anchorOrigin:{vertical:l,horizontal:a}={vertical:"bottom",horizontal:"left"},autoHideDuration:c=null,children:u,className:d,ClickAwayListenerProps:f,ContentProps:h,disableWindowBlurListener:g=!1,message:m,open:C,TransitionComponent:b=$c,transitionDuration:y=s,TransitionProps:{onEnter:w,o Line truncated
${e.palette.mode==="light"?of(bt(e.palette.divider,1),.88):rf(bt(e.palette.divider,1),.68)}`,textAlign:"left",padding:16},t.variant==="head"&&{color:(e.vars||e).palette.text.primary,lineHeight:e.typography.pxToRem(24),fontWeight:e.typography.fontWeightMedium},t.variant==="body"&&{color:(e.vars||e).palette.text.primary},t.variant==="footer"&&{color:(e.vars||e).palette.text.secondary,lineHeight:e.typography.pxToRem(21),fontSize:e.typography.pxToRem(12)},t.size==="small"&&{padding:"6px 16px",[`&.${SU.paddingCheckbox}`]:{width:24,padding:"0 12px 0 16px","& > *":{padding:0}}},t.padding==="checkbox"&&{width:48,padding:"0 0 0 4px"},t.padding==="none"&&{padding:0},t.align==="left"&&{textAlign:"left"},t.align==="center"&&{textAlign:"center"},t.align==="right"&&{textAlign:"right",flexDirection:"row-reverse"},t.align==="justify"&&{textAlign:"justify"},t.stickyHeader&&{position:"sticky",top:0,zIndex:2,backgroundColor:(e.vars||e).palette.background.default})),hx=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiTableCell"}),{align:o="inherit",className:s,component:i,padding:l,scope:a,size:c,sortDirection:u,variant:d}=r,f=te(r,kU),h=p.useContext(xU),g=p.useContext(CU),m=g&&g.variant==="head";let C;i?C=i:C=m?"th":"td";let b=a;C==="td"?b=void 0:!b&&m&&(b="col");const y=d||g&&g.variant,w=x({},r,{align:o,component:C,padding:l||(h&&h.padding?h.padding:"normal"),size:c||(h&&h.size?h.size:"medium"),sortDirection:u,stickyHeader:y==="head"&&h&&h.stickyHeader,variant:y}),S=PU(w);let k=null;return u&&(k=u==="asc"?"ascending":"descending"),v.jsx(MU,x({as:C,ref:n,className:le(S.root,s),"aria-sort":k,scope:b,ownerState:w},f))});function IU(e){return ze("MuiToolbar",e)}Ne("MuiToolbar",["root","gutters","regular","dense"]);const EU=["className","component","disableGutters","variant"],_U=e=>{const{classes:t,disableGutters:n,variant:r}=e;return ve({root:["root",!n&&"gutters",r]},IU,t)},TU=re("div",{name:"MuiToolbar",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.root,!n.disableGutters&&t.gutters,t[n.variant]]}})(({theme:e,ownerState:t})=>x({position:"relative",display:"flex",alignItems:"center"},!t.disableGutters&&{paddingLeft:e.spacing(2),paddingRight:e.spacing(2),[e.breakpoints.up("sm")]:{paddingLeft:e.spacing(3),paddingRight:e.spacing(3)}},t.variant==="dense"&&{minHeight:48}),({theme:e,ownerState:t})=>t.variant==="regular"&&e.mixins.toolbar),RU=p.forwardRef(function(t,n){const r=We({props:t,name:"MuiToolbar"}),{className:o,component:s="div",disableGutters:i=!1,variant:l="regular"}=r,a=te(r,EU),c=x({},r,{component:s,disableGutters:i,variant:l}),u=_U(c);return v.jsx(TU,x({as:s,className:le(u.root,o),ref:n,ownerState:c},a))}),sO=Qe(v.jsx("path",{d:"M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"}),"KeyboardArrowLeft"),iO=Qe(v.jsx("path",{d:"M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"}),"KeyboardArrowRight"),OU=["backIconButtonProps","count","disabled","getItemAriaLabel","nextIconButtonProps","onPageChange","page","rowsPerPage","showFirstButton","showLastButton","slots","slotProps"],$U=p.forwardRef(function(t,n){var r,o,s,i,l,a,c,u;const{backIconButtonProps:d,count:f,disabled:h=!1,getItemAriaLabel:g,nextIconButtonProps:m,onPageChange:C,page:b,rowsPerPage:y,showFirstButton:w,showLastButton:S,slots:k={},slotProps:P={}}=t,M=te(t,OU),I=Zc(),E=ee=>{C(ee,0)},T=ee=>{C(ee,b-1)},D=ee=>{C(ee,b+1)},$=ee=>{C(ee,Math.max(0,Math.ceil(f/y)-1))},L=(r=k.firstButton)!=null?r:gr,A=(o=k.lastButton)!=null?o:gr,R=(s=k.nextButton)!=null?s:gr,_=(i=k.previousButton)!=null?i:gr,O=(l=k.firstButtonIcon)!=null?l:I6,F=(a=k.lastButtonIcon)!=null?a:E6,j=(c=k.nextButtonIcon)!=null?c:iO,z=(u=k.previousButtonIcon)!=null?u:sO,H=I?A:L,B=I?R:_,G=I?_:R,V=I?L:A,Z=I?P.lastButton:P.firstButton,Q=I?P.nextButton:P.previousButton,U=I?P.previousButton:P.nextButton,K=I?P.firstButton:P.lastButton;return v.jsxs("div",x({ref:n},M,{children:[w&&v.jsx(H,x({onClick:E,disabled:h||b===0,"aria-label":g("first",b),title:g("first",b)},Z,{children:I?v.jsx(F,x({},P.lastButtonIcon)):v.jsx(O,x({},P.firstButtonIcon))})),v.jsx(B,x({onClick:T,disabled:h||b===0,color:"inherit","aria-label":g("previous",b),title:g("previous",b)},Q??d,{children:I?v.jsx(j,x({},P.nextButtonIcon)):v.jsx(z,x({},P.previousButtonIcon))})),v.jsx(G,x({onClick:D,disabled:h||(f!==-1?b>=Math.ceil(f/y)-1:!1),color:"inherit","aria-label":g("next",b),title:g("next",b)},U??m,{children:I?v.jsx(z,x({},P.previousButtonIcon)):v.jsx(j,x({},P.nextButtonIcon))})),S&&v.jsx(V,x({onClick:$,disabled:h||b>=Math.ceil(f/y)-1,"aria-label":g("last",b),title:g("last",b)},K,{children:I?v.jsx(O,x({},P.firstButtonIcon)):v.jsx(F,x({},P.lastButtonIcon))}))]}))});function FU(e){return ze("MuiTablePagination",e)}const jl=Ne("MuiTablePagination",["root","toolbar","spacer","selectLabel","selectRoot","select","selectIcon","input","menuItem","displayedRows","actions"]);var nP;const LU=["ActionsComponent","backIconButtonProps","className","colSpan","component","count","disabled","getItemAriaLabel","labelDisplayedRows","labe Line truncated
`));return e}const pO=p.createContext(void 0),Te=()=>{const e=p.useContext(pO);if(!e)throw new Error("MUI X: useGridRootProps should only be used inside the DataGrid, DataGridPro or DataGridPremium component.");return e},O8=parseInt(p.version,10),at=e=>{if(O8>=19){const t=n=>e(n,n.ref??null);return t.displayName=e.displayName??e.name,t}return p.forwardRef(e)};function $8(e,...t){const n=new URL(`https://mui.com/production-error/?code=${e}`);return t.forEach(r=>n.searchParams.append("args[]",r)),`Minified MUI error #${e}; visit ${n} for the full message.`}function F8(e,t){return tg(e,t)}function L8(e,t){Array.isArray(e.__emotion_styles)&&(e.__emotion_styles=t(e.__emotion_styles))}const lP=[];function zl(e){return lP[0]=e,Kc(lP)}function gl(e){if(typeof e!="object"||e===null)return!1;const t=Object.getPrototypeOf(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)}function gO(e){if(p.isValidElement(e)||og.isValidElementType(e)||!gl(e))return e;const t={};return Object.keys(e).forEach(n=>{t[n]=gO(e[n])}),t}function gg(e,t,n={clone:!0}){const r=n.clone?{...e}:e;return gl(e)&&gl(t)&&Object.keys(t).forEach(o=>{p.isValidElement(t[o])||og.isValidElementType(t[o])?r[o]=t[o]:gl(t[o])&&Object.prototype.hasOwnProperty.call(e,o)&&gl(e[o])?r[o]=gg(e[o],t[o],n):n.clone?r[o]=gl(t[o])?gO(t[o]):t[o]:r[o]=t[o]}),r}const D8=e=>{const t=Object.keys(e).map(n=>({key:n,val:e[n]}))||[];return t.sort((n,r)=>n.val-r.val),t.reduce((n,r)=>({...n,[r.key]:r.val}),{})};function A8(e){const{values:t={xs:0,sm:600,md:900,lg:1200,xl:1536},unit:n="px",step:r=5,...o}=e,s=D8(t),i=Object.keys(s);function l(f){return`@media (min-width:${typeof t[f]=="number"?t[f]:f}${n})`}function a(f){return`@media (max-width:${(typeof t[f]=="number"?t[f]:f)-r/100}${n})`}function c(f,h){const g=i.indexOf(h);return`@media (min-width:${typeof t[f]=="number"?t[f]:f}${n}) and (max-width:${(g!==-1&&typeof t[i[g]]=="number"?t[i[g]]:h)-r/100}${n})`}function u(f){return i.indexOf(f)+1<i.length?c(f,i[i.indexOf(f)+1]):l(f)}function d(f){const h=i.indexOf(f);return h===0?l(i[1]):h===i.length-1?a(i[h]):c(f,i[i.indexOf(f)+1]).replace("@media","@media not all and")}return{keys:i,values:s,up:l,down:a,between:c,only:u,not:d,unit:n,...o}}function aP(e,t){if(!e.containerQueries)return t;const n=Object.keys(t).filter(r=>r.startsWith("@container")).sort((r,o)=>{var i,l;const s=/min-width:\s*([0-9.]+)/;return+(((i=r.match(s))==null?void 0:i[1])||0)-+(((l=o.match(s))==null?void 0:l[1])||0)});return n.length?n.reduce((r,o)=>{const s=t[o];return delete r[o],r[o]=s,r},{...t}):t}function j8(e,t){return t==="@"||t.startsWith("@")&&(e.some(n=>t.startsWith(`@${n}`))||!!t.match(/^@\d/))}function z8(e,t){const n=t.match(/^@([^/]+)?\/?(.+)?$/);if(!n)return null;const[,r,o]=n,s=Number.isNaN(+r)?r||0:+r;return e.containerQueries(o).up(s)}function N8(e){const t=(s,i)=>s.replace("@media",i?`@container ${i}`:"@container");function n(s,i){s.up=(...l)=>t(e.breakpoints.up(...l),i),s.down=(...l)=>t(e.breakpoints.down(...l),i),s.between=(...l)=>t(e.breakpoints.between(...l),i),s.only=(...l)=>t(e.breakpoints.only(...l),i),s.not=(...l)=>{const a=t(e.breakpoints.not(...l),i);return a.includes("not all and")?a.replace("not all and ","").replace("min-width:","width<").replace("max-width:","width>").replace("and","or"):a}}const r={},o=s=>(n(r,s),r);return n(o),{...e,containerQueries:o}}const H8={borderRadius:4};function Pd(e,t){return t?gg(e,t,{clone:!1}):e}const nb={xs:0,sm:600,md:900,lg:1200,xl:1536},cP={keys:["xs","sm","md","lg","xl"],up:e=>`@media (min-width:${nb[e]}px)`},B8={containerQueries:e=>({up:t=>{let n=typeof t=="number"?t:nb[t]||t;return typeof n=="number"&&(n=`${n}px`),e?`@container ${e} (min-width:${n})`:`@container (min-width:${n})`}})};function Hs(e,t,n){const r=e.theme||{};if(Array.isArray(t)){const s=r.breakpoints||cP;return t.reduce((i,l,a)=>(i[s.up(s.keys[a])]=n(t[a]),i),{})}if(typeof t=="object"){const s=r.breakpoints||cP;return Object.keys(t).reduce((i,l)=>{if(j8(s.keys,l)){const a=z8(r.containerQueries?r:B8,l);a&&(i[a]=n(t[l],l))}else if(Object.keys(s.values||nb).includes(l)){const a=s.up(l);i[a]=n(t[l],l)}else{const a=l;i[a]=t[a]}return i},{})}return n(t)}function V8(e={}){var n;return((n=e.keys)==null?void 0:n.reduce((r,o)=>{const s=e.up(o);return r[s]={},r},{}))||{}}function uP(e,t){return e.reduce((n,r)=>{const o=n[r];return(!o||Object.keys(o).length===0)&&delete n[r],n},t)}function mO(e){if(typeof e!="string")throw new Error($8(7));return e.charAt(0).toUpperCase()+e.slice(1)}function rb(e,t,n=!0){if(!t||typeof t!="string")return null;if(e&&e.vars&&n){const r=`vars.${t}`.split(".").reduce((o,s)=>o&&o[s]?o[s]:null,e);if(r!=null)return r}return t.split(".").reduce((r,o)=>r&&r[o]!=null?r[o]:null,e)}function mg(e,t,n,r=n){let o;return typeof e=="function"?o=e(n):Array.isArray(e)?o=e[n]||r:o=rb(e,n)||r,t&&(o=t(o,r,e)),o}function pn(e){const{prop:t,cssProperty:n=e.prop,themeKey:r,transform:o}=e,s=i=>{if(i[t]==nul Line truncated
* @license React
* use-sync-external-store-shim.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Fc=p;function r7(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var o7=typeof Object.is=="function"?Object.is:r7,s7=Fc.useState,i7=Fc.useEffect,l7=Fc.useLayoutEffect,a7=Fc.useDebugValue;function c7(e,t){var n=t(),r=s7({inst:{value:n,getSnapshot:t}}),o=r[0].inst,s=r[1];return l7(function(){o.value=n,o.getSnapshot=t,yv(o)&&s({inst:o})},[e,n,t]),i7(function(){return yv(o)&&s({inst:o}),e(function(){yv(o)&&s({inst:o})})},[e]),a7(n),n}function yv(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!o7(e,n)}catch{return!0}}function u7(e,t){return t()}var d7=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?u7:c7;EO.useSyncExternalStore=Fc.useSyncExternalStore!==void 0?Fc.useSyncExternalStore:d7;IO.exports=EO;var LC=IO.exports;function _O(e){return e.acceptsApiRef}function pP(e,t){return _O(t)?t(e):t(e.current.state)}function xv(e,t,n,r){return _O(t)?t(e,n):t(e.current.state,r)}const TO=Object.is,DC=MO,f7=(e,t)=>e===t?!0:e.length===t.length&&e.every((n,r)=>n===t[r]),h7=(e,t)=>{let n=Object.is;return t instanceof Array?n=f7:t instanceof Object&&(n=DC),n(e,t)},RO=()=>({state:null,equals:null,selector:null,args:void 0}),yg=[],OO=()=>null,he=(e,t,n=TO)=>{const r=zo(RO),o=r.current.selector!==null,[s,i]=p.useState(o?null:pP(e,t));r.current.state=s,r.current.equals=n,r.current.selector=t;const l=p.useCallback(()=>(r.current.subscription||(r.current.subscription=e.current.store.subscribe(()=>{const c=pP(e,r.current.selector);r.current.equals(r.current.state,c)||(r.current.state=c,i(c))})),null),yg),a=p.useCallback(()=>()=>{r.current.subscription&&(r.current.subscription(),r.current.subscription=void 0)},yg);return LC.useSyncExternalStore(a,l,OO),s},df=(e,t,n=void 0,r=TO)=>{const o=zo(RO),s=o.current.selector!==null,[i,l]=p.useState(s?null:xv(e,t,n,e.current.instanceId));o.current.state=i,o.current.equals=r,o.current.selector=t;const a=o.current.args;if(o.current.args=n,s&&!h7(a,n)){const d=xv(e,o.current.selector,o.current.args,e.current.instanceId);o.current.equals(o.current.state,d)||(o.current.state=d,l(d))}const c=p.useCallback(()=>(o.current.subscription||(o.current.subscription=e.current.store.subscribe(()=>{const d=xv(e,o.current.selector,o.current.args,e.current.instanceId);o.current.equals(o.current.state,d)||(o.current.state=d,l(d))})),null),yg),u=p.useCallback(()=>()=>{o.current.subscription&&(o.current.subscription(),o.current.subscription=void 0)},yg);return LC.useSyncExternalStore(u,c,OO),i},p7=kO({memoize:wO,memoizeOptions:{maxSize:1,equalityCheck:Object.is}}),gP=new WeakMap;function _o(e){return"current"in e&&"instanceId"in e.current}const To={id:"default"},Be=(e,t,n,r,o,s,...i)=>{if(i.length>0)throw new Error("Unsupported number of selectors");let l;if(e&&t&&n&&r&&o&&s)l=(a,c)=>{const u=_o(a),d=c??(u?a.current.instanceId:To),f=u?a.current.state:a,h=e(f,d),g=t(f,d),m=n(f,d),C=r(f,d),b=o(f,d);return s(h,g,m,C,b)};else if(e&&t&&n&&r&&o)l=(a,c)=>{const u=_o(a),d=c??(u?a.current.instanceId:To),f=u?a.current.state:a,h=e(f,d),g=t(f,d),m=n(f,d),C=r(f,d);return o(h,g,m,C)};else if(e&&t&&n&&r)l=(a,c)=>{const u=_o(a),d=c??(u?a.current.instanceId:To),f=u?a.current.state:a,h=e(f,d),g=t(f,d),m=n(f,d);return r(h,g,m)};else if(e&&t&&n)l=(a,c)=>{const u=_o(a),d=c??(u?a.current.instanceId:To),f=u?a.current.state:a,h=e(f,d),g=t(f,d);return n(h,g)};else if(e&&t)l=(a,c)=>{const u=_o(a),d=c??(u?a.current.instanceId:To),f=u?a.current.state:a,h=e(f,d);return t(h)};else throw new Error("Missing arguments");return l.acceptsApiRef=!0,l},Uf=(e,t,n,r,o,s,...i)=>{if(i.length>0)throw new Error("Unsupported number of selectors");let l;if(e&&t&&n&&r&&o&&s)l=(a,c,u)=>{const d=_o(a),f=u??(d?a.current.instanceId:To),h=d?a.current.state:a,g=e(h,c,f),m=t(h,c,f),C=n(h,c,f),b=r(h,c,f),y=o(h,c,f);return s(g,m,C,b,y,c)};else if(e&&t&&n&&r&&o)l=(a,c,u)=>{const d=_o(a),f=u??(d?a.current.instanceId:To),h=d?a.current.state:a,g=e(h,c,f),m=t(h,c,f),C=n(h,c,f),b=r(h,c,f);return o(g,m,C,b,c)};else if(e&&t&&n&&r)l=(a,c,u)=>{const d=_o(a),f=u??(d?a.current.instanceId:To),h=d?a.current.state:a,g=e(h,c,f),m=t(h,c,f),C=n(h,c,f);return r(g,m,C,c)};else if(e&&t&&n)l=(a,c,u)=>{const d=_o(a),f=u??(d?a.current.instanceId:To),h=d?a.current.state:a,g=e(h,c,f),m=t(h,c,f);return n(g,m,c)};else if(e&&t)l=(a,c,u)=>{const d=_o(a),f=u??(d?a.current.instanceId:To),h=d?a.current.state:a,g=e(h,c,f);return t(g,c)};else throw new Error("Missing arguments");return l.acceptsApiRef=!0,l},ft=(...e)=>{const t=(n,r)=>{const o=_o(n),s=o?n.current.instanceId:r??To,i=o?n.current.state:n,l=gP.get(s),a=l??new Map,c=a==null?void 0:a.get(e);if(a&&c)return c(i,s);const u=p7(...e);return l||gP.set(s,a),a.set(e,u),u(i,s)};return t.acceptsApiRef=!0,t},kn=e=>e.dimensions,cb=Be(kn,e=>e.columnsTotalWidth),AC=e=>e.dimensions.rowHeight,g7=e=>e.dimensions.contentSize.height,m7=e=>e.dimensions.hasScrollX,b7=e=>e.dimensions.hasScrollY,$O=e=>e.dimensions.columnsTotalWidth<e.dimensions.viewportOuterSize.width,v7=e=>e.dimensions.headerHeight,y7=e=>e.dimLine truncated
${o.map((l,a)=>`const shouldApply${a} = !shouldApplyFilter || shouldApplyFilter(${JSON.stringify(l.item.field)});`).join(`
`)}
const result$$ = {
${o.map((l,a)=>` ${JSON.stringify(String(l.item.id))}: !shouldApply${a} ? false : appliers[${a}].fn(row),`).join(`
`)}
};
return result$$;`.replaceAll("$$",String(SP)));return SP+=1,(l,a)=>s(o,l,a)},XO=e=>e.quickFilterExcludeHiddenColumns??!0,sK=(e,t)=>{var l;const n=((l=e.quickFilterValues)==null?void 0:l.filter(Boolean))??[];if(n.length===0)return null;const r=XO(e)?uu(t):$s(t),o=[],{ignoreDiacritics:s}=t.current.rootProps,i=VO(t);return r.forEach(a=>{const c=t.current.getColumn(a),u=c==null?void 0:c.getApplyQuickFilterFn;u&&o.push({column:c,appliers:n.map(d=>{const f=s?hf(d):d;return{fn:u(f,c,i)}})})}),function(c,u){const d={};e:for(let f=0;f<n.length;f+=1){const h=n[f];for(let g=0;g<o.length;g+=1){const{column:m,appliers:C}=o[g],{field:b}=m;if(u&&!u(b))continue;const y=C[f];let w=t.current.getRowValue(c,m);if(y.fn===null)continue;if(s&&(w=hf(w)),y.fn(w,c,m,i)){d[h]=!0;continue e}}d[h]=!1}return d}},iK=(e,t,n)=>{const r=oK(e,t,n),o=sK(e,t);return function(i,l,a){a.passingFilterItems=(r==null?void 0:r(i,l))??null,a.passingQuickFilterValues=(o==null?void 0:o(i,l))??null}},kP=e=>e!=null,lK=(e,t,n)=>(e.cleanedFilterItems||(e.cleanedFilterItems=n.filter(r=>qO(r,t)!==null)),e.cleanedFilterItems),aK=(e,t,n,r,o)=>{const s=lK(o,r,n.items),i=e.filter(kP),l=t.filter(kP);if(i.length>0){const a=u=>i.some(d=>d[u.id]);if((n.logicOperator??ff().logicOperator)===Jn.And){if(!s.every(a))return!1}else if(!s.some(a))return!1}if(l.length>0&&n.quickFilterValues!=null){const a=u=>l.some(d=>d[u]);if((n.quickFilterLogicOperator??ff().quickFilterLogicOperator)===Jn.And){if(!n.quickFilterValues.every(a))return!1}else if(!n.quickFilterValues.some(a))return!1}return!0},cK=e=>{if(!e)return null;const t=new RegExp(xg(e),"i");return(n,r,o,s)=>{let i=s.current.getRowFormattedValue(r,o);return s.current.ignoreDiacritics&&(i=hf(i)),i!=null?t.test(i.toString()):!1}},PP=(e,t)=>n=>{if(!n.value)return null;const r=e?n.value:n.value.trim(),o=new RegExp(xg(r),"i");return s=>{if(s==null)return t;const i=o.test(String(s));return t?!i:i}},MP=(e,t)=>n=>{if(!n.value)return null;const r=e?n.value:n.value.trim(),o=new Intl.Collator(void 0,{sensitivity:"base",usage:"search"});return s=>{if(s==null)return t;const i=o.compare(r,s.toString())===0;return t?!i:i}},IP=e=>()=>t=>{const n=t===""||t==null;return e?!n:n},uK=(e=!1)=>[{value:"contains",getApplyFilterFn:PP(e,!1),InputComponent:Jr},{value:"doesNotContain",getApplyFilterFn:PP(e,!0),InputComponent:Jr},{value:"equals",getApplyFilterFn:MP(e,!1),InputComponent:Jr},{value:"doesNotEqual",getApplyFilterFn:MP(e,!0),InputComponent:Jr},{value:"startsWith",getApplyFilterFn:t=>{if(!t.value)return null;const n=e?t.value:t.value.trim(),r=new RegExp(`^${xg(n)}.*$`,"i");return o=>o!=null?r.test(o.toString()):!1},InputComponent:Jr},{value:"endsWith",getApplyFilterFn:t=>{if(!t.value)return null;const n=e?t.value:t.value.trim(),r=new RegExp(`.*${xg(n)}$`,"i");return o=>o!=null?r.test(o.toString()):!1},InputComponent:Jr},{value:"isEmpty",getApplyFilterFn:IP(!1),requiresFilterValue:!1},{value:"isNotEmpty",getApplyFilterFn:IP(!0),requiresFilterValue:!1},{value:"isAnyOf",getApplyFilterFn:t=>{if(!Array.isArray(t.value)||t.value.length===0)return null;const n=e?t.value:t.value.map(o=>o.trim()),r=new Intl.Collator(void 0,{sensitivity:"base",usage:"search"});return o=>o!=null?n.some(s=>r.compare(s,o.toString()||"")===0):!1},InputComponent:NO}],Fo={width:100,minWidth:50,maxWidth:1/0,hideable:!0,sortable:!0,resizable:!0,filterable:!0,groupable:!0,pinnable:!0,aggregable:!0,editable:!1,sortComparator:U7,type:"string",align:"left",filterOperators:uK(),renderEditCell:L7,getApplyQuickFilterFn:cK},dK=["open","target","onClose","children","position","className","onExited"],fK=e=>{const{classes:t}=e;return ve({root:["menu"]},et,t)},hK=re(oa,{name:"MuiDataGrid",slot:"Menu",overridesResolver:(e,t)=>t.menu})(({theme:e})=>({zIndex:e.zIndex.modal,[`& .${N.menuList}`]:{outline:0}})),pK={"bottom-start":"top left","bottom-end":"top right"};function HC(e){var m;const{open:t,target:n,onClose:r,children:o,position:s,className:i,onExited:l}=e,a=te(e,dK),c=qe(),u=Te(),d=fK(u),f=p.useRef(null);Et(()=>{var C,b;t?f.current=document.activeElement instanceof HTMLElement?document.activeElement:null:((b=(C=f.current)==null?void 0:C.focus)==null||b.call(C),f.current=null)},[t]),p.useEffect(()=>{const C=t?"menuOpen":"menuClose";c.current.publishEvent(C,{target:n})},[c,t,n]);const h=C=>b=>{C&&C(),l&&l(b)},g=C=>{C.target&&(n===C.target||n!=null&&n.contains(C.target))||r(C)};return v.jsx(hK,x({as:u.slots.basePopper,className:le(d.root,i),ownerState:u,open:t,anchorEl:n,transition:!0,placement:s},a,(m=u.slotProps)==null?void 0:m.basePopper,{children:({TransitionProps:C,placement:b})=>v.jsx(CC,{onClickAway:g,mouseEvent:"onMouseDown",children:v.jsx($c,x({},C,{style:{transformOrigin:pK[b]},onExited:h(C==null?void 0:C.onExited),children:v.jsx(Gs,{children:o})}))})}))}const gK=["api","colDef","id","hasFocus","isEditable","field","value","formattedValue","row","rowNode","cellMode","tabIndex","position","focusElementRef"],mK=e=>typeof e.getActions=="function";function bK(e){var _;const{col Line truncated
`))}const db=(e,t,n)=>{const r=t?t(e):e.id;return CK(r,e,n),r},vp=({rows:e,getRowId:t,loading:n,rowCount:r})=>{const o={type:"full",rows:[]},s={},i={};for(let l=0;l<e.length;l+=1){const a=e[l],c=db(a,t);s[c]=a,i[c]=c,o.rows.push(c)}return{rowsBeforePartialUpdates:e,loadingPropBeforePartialUpdates:n,rowCountPropBeforePartialUpdates:r,updates:o,dataRowIdToIdLookup:i,dataRowIdToModelLookup:s}},YO=({tree:e,rowCountProp:t=0})=>{const n=e[jn];return Math.max(t,n.children.length+(n.footerId==null?0:1))},QO=({apiRef:e,rowCountProp:t=0,loadingProp:n,previousTree:r,previousTreeDepths:o,previousGroupsToFetch:s})=>{const i=e.current.caches.rows,{tree:l,treeDepths:a,dataRowIds:c,groupingName:u,groupsToFetch:d=[]}=e.current.applyStrategyProcessor("rowTreeCreation",{previousTree:r,previousTreeDepths:o,updates:i.updates,dataRowIdToIdLookup:i.dataRowIdToIdLookup,dataRowIdToModelLookup:i.dataRowIdToModelLookup,previousGroupsToFetch:s}),f=e.current.unstable_applyPipeProcessors("hydrateRows",{tree:l,treeDepths:a,dataRowIdToIdLookup:i.dataRowIdToIdLookup,dataRowIds:c,dataRowIdToModelLookup:i.dataRowIdToModelLookup});return e.current.caches.rows.updates={type:"partial",actions:{insert:[],modify:[],remove:[]},idToActionLookup:{}},x({},f,{totalRowCount:Math.max(t,f.dataRowIds.length),totalTopLevelRowCount:YO({tree:f.tree,rowCountProp:t}),groupingName:u,loading:n,groupsToFetch:d})},Dc=e=>e.type==="skeletonRow"||e.type==="footer"||e.type==="group"&&e.isAutoGenerated||e.type==="pinnedRow"&&e.isAutoGenerated,BC=(e,t,n)=>{const r=e[t];if(r.type!=="group")return[];const o=[];for(let s=0;s<r.children.length;s+=1){const i=r.children[s];(!n||!Dc(e[i]))&&o.push(i);const l=BC(e,i,n);for(let a=0;a<l.length;a+=1)o.push(l[a])}return!n&&r.footerId!=null&&o.push(r.footerId),o},EP=({previousCache:e,getRowId:t,updates:n,groupKeys:r})=>{if(e.updates.type==="full")throw new Error("MUI X: Unable to prepare a partial update if a full update is not applied yet.");const o=new Map;n.forEach(u=>{const d=db(u,t,"A row was provided without id when calling updateRows():");o.has(d)?o.set(d,x({},o.get(d),u)):o.set(d,u)});const s={type:"partial",actions:{insert:[...e.updates.actions.insert??[]],modify:[...e.updates.actions.modify??[]],remove:[...e.updates.actions.remove??[]]},idToActionLookup:x({},e.updates.idToActionLookup),groupKeys:r},i=x({},e.dataRowIdToModelLookup),l=x({},e.dataRowIdToIdLookup),a={insert:{},modify:{},remove:{}};o.forEach((u,d)=>{const f=s.idToActionLookup[d];if(u._action==="delete"){if(f==="remove"||!i[d])return;f!=null&&(a[f][d]=!0),s.actions.remove.push(d),delete i[d],delete l[d];return}const h=i[d];if(h){f==="remove"?(a.remove[d]=!0,s.actions.modify.push(d)):f==null&&s.actions.modify.push(d),i[d]=x({},h,u);return}f==="remove"?(a.remove[d]=!0,s.actions.insert.push(d)):f==null&&s.actions.insert.push(d),i[d]=u,l[d]=d});const c=Object.keys(a);for(let u=0;u<c.length;u+=1){const d=c[u],f=a[d];Object.keys(f).length>0&&(s.actions[d]=s.actions[d].filter(h=>!f[h]))}return{dataRowIdToModelLookup:i,dataRowIdToIdLookup:l,updates:s,rowsBeforePartialUpdates:e.rowsBeforePartialUpdates,loadingPropBeforePartialUpdates:e.loadingPropBeforePartialUpdates,rowCountPropBeforePartialUpdates:e.rowCountPropBeforePartialUpdates}},ZO="var(--DataGrid-overlayHeight, calc(var(--height) * 2))";function _P(e,t,n){const r=[];return t.forEach(o=>{const s=db(o,n,"A row was provided without id when calling updateRows():"),i=e.current.getRowNode(s);if((i==null?void 0:i.type)==="pinnedRow"){const l=e.current.caches.pinnedRows,a=l.idLookup[s];a&&(l.idLookup[s]=x({},a,o))}else r.push(o)}),r}const JO=(e,t,n)=>typeof e=="number"&&e>0?e:t,wK="__tree_data_group__",e2="__row_group_by_columns_group__",fb="__detail_panel_toggle__";let Je=function(e){return e[e.NONE=0]="NONE",e[e.LEFT=1]="LEFT",e[e.RIGHT=2]="RIGHT",e[e.VIRTUAL=3]="VIRTUAL",e}({});const SK=["id","value","formattedValue","api","field","row","rowNode","colDef","cellMode","isEditable","hasFocus","tabIndex","hideDescendantCount"],kK=e=>{const{classes:t}=e;return ve({root:["booleanCell"]},et,t)};function PK(e){const{value:t,rowNode:n}=e,r=te(e,SK),o=qe(),s=Te(),i={classes:s.classes},l=kK(i),c=he(o,la)>0&&n.type==="group"&&s.treeData===!1,u=p.useMemo(()=>t?s.slots.booleanCellTrueIcon:s.slots.booleanCellFalseIcon,[s.slots.booleanCellFalseIcon,s.slots.booleanCellTrueIcon,t]);return c&&t===void 0?null:v.jsx(u,x({fontSize:"small",className:l.root,titleAccess:o.current.getLocaleText(t?"booleanCellTrueLabel":"booleanCellFalseLabel"),"data-value":!!t},r))}const MK=p.memo(PK),IK=e=>e.field!==e2&&Dc(e.rowNode)?"":v.jsx(MK,x({},e)),EK=["id","value","formattedValue","api","field","row","rowNode","colDef","cellMode","isEditable","tabIndex","className","hasFocus","isValidating","isProcessingProps","error","onValueChange"],_K=e=>{const{classes:t}=e;return ve({root:["editBooleanCell"]},et,t)};function TK(e){var b;const{id:t,value:n,field:r,className:o,hasFocus:s,onValueChange:i}=e,l=te(e,EK),a=qe(),c=p.useRef(null),u=gt(),[d,f]=p.useState(n Line truncated
`))},oq=-1,Xf=e=>e.pagination,h2=Be(Xf,e=>e.enabled&&e.paginationMode==="client"),Un=Be(Xf,e=>e.paginationModel),Va=Be(Xf,e=>e.rowCount),rd=Be(Xf,e=>e.meta),sq=Be(Un,e=>e.page),p2=Be(Un,e=>e.pageSize),g2=Be(Un,Va,(e,t)=>u2(t,e.pageSize,e.page)),XC=ft(h2,Un,mn,la,ol,i2,(e,t,n,r,o,s)=>{var g;if(!e)return null;const i=s.length,l=Math.min(t.pageSize*t.page,i-1),a=t.pageSize===oq?i-1:Math.min(l+t.pageSize-1,i-1);if(l===-1||a===-1)return null;if(r<2)return{firstRowIndex:l,lastRowIndex:a};const c=s[l],u=a-l+1,d=o.findIndex(m=>m.id===c.id);let f=d,h=0;for(;f<o.length&&h<=u;){const m=o[f],C=(g=n[m.id])==null?void 0:g.depth;C===void 0?f+=1:((h<u||C>0)&&(f+=1),C===0&&(h+=1))}return{firstRowIndex:d,lastRowIndex:f-1}}),iq=ft(ol,XC,(e,t)=>t?e.slice(t.firstRowIndex,t.lastRowIndex+1):[]),m2=ft(nc,XC,(e,t)=>t?e.slice(t.firstRowIndex,t.lastRowIndex+1):[]),Yf=ft(h2,XC,iq,ol,(e,t,n,r)=>e?{rows:n,range:t,rowToIndexMap:n.reduce((o,s,i)=>(o.set(s.model,i),o),new Map)}:{rows:r,range:r.length===0?null:{firstRowIndex:0,lastRowIndex:r.length-1},rowToIndexMap:r.reduce((o,s,i)=>(o.set(s.model,i),o),new Map)}),lq=["field","colDef"],aq=e=>{const{classes:t}=e;return ve({root:["checkboxInput"]},et,t)},cq=at(function(t,n){var I;const r=te(t,lq),[,o]=p.useState(!1),s=qe(),i=Te(),l={classes:i.classes},a=aq(l),c=he(s,a2),u=he(s,_r),d=he(s,nc),f=he(s,m2),h=p.useMemo(()=>typeof i.isRowSelectable!="function"?u:u.filter(E=>i.keepNonExistentRowsSelected?!0:s.current.getRow(E)?i.isRowSelectable(s.current.getRowParams(E)):!1),[s,i.isRowSelectable,u,i.keepNonExistentRowsSelected]),g=p.useMemo(()=>(!i.pagination||!i.checkboxSelectionVisibleOnly||i.paginationMode==="server"?d:f).reduce((T,D)=>(T[D]=!0,T),{}),[i.pagination,i.paginationMode,i.checkboxSelectionVisibleOnly,f,d]),m=p.useMemo(()=>h.filter(E=>g[E]).length,[h,g]),C=m>0&&m<Object.keys(g).length,b=m>0,y=E=>{const T={value:E.target.checked};s.current.publishEvent("headerSelectionCheckboxChange",T)},w=c!==null&&c.field===t.field?0:-1;p.useLayoutEffect(()=>{const E=s.current.getColumnHeaderElement(t.field);w===0&&E&&(E.tabIndex=-1)},[w,s,t.field]);const S=p.useCallback(E=>{E.key===" "&&s.current.publishEvent("headerSelectionCheckboxChange",{value:!b})},[s,b]),k=p.useCallback(()=>{o(E=>!E)},[]);p.useEffect(()=>s.current.subscribeEvent("rowSelectionChange",k),[s,k]);const P=i.indeterminateCheckboxAction==="select"?b&&!C:b,M=s.current.getLocaleText(P?"checkboxSelectionUnselectAllRows":"checkboxSelectionSelectAllRows");return v.jsx(i.slots.baseCheckbox,x({indeterminate:C,checked:P,onChange:y,className:a.root,inputProps:{"aria-label":M,name:"select_all_rows"},tabIndex:w,onKeyDown:S,disabled:!KC(i)},(I=i.slotProps)==null?void 0:I.baseCheckbox,r,{ref:n}))}),Qf=(e,t)=>Lc in t?t[Lc]:e.props.getRowId?e.props.getRowId(t):t.id,Wr="__check__",pu=x({},t2,{type:"custom",field:Wr,width:50,resizable:!1,sortable:!1,filterable:!1,aggregable:!1,disableColumnMenu:!0,disableReorder:!0,disableExport:!0,getApplyQuickFilterFn:void 0,display:"flex",valueGetter:(e,t,n,r)=>{const o=Wi(r),s=Qf(r.current.state,t);return o[s]!==void 0},renderHeader:e=>v.jsx(cq,x({},e)),renderCell:e=>v.jsx(YK,x({},e))}),uq=["item","applyValue","type","apiRef","focusElementRef","InputProps","isFilterActive","clearButton","tabIndex","disabled"];function RP(e,t){if(e==null)return"";const n=new Date(e);return Number.isNaN(n.getTime())?"":t==="date"?n.toISOString().substring(0,10):t==="datetime-local"?(n.setMinutes(n.getMinutes()-n.getTimezoneOffset()),n.toISOString().substring(0,19)):n.toISOString().substring(0,10)}function va(e){var w;const{item:t,applyValue:n,type:r,apiRef:o,focusElementRef:s,InputProps:i,clearButton:l,tabIndex:a,disabled:c}=e,u=te(e,uq),d=pr(),[f,h]=p.useState(()=>RP(t.value,r)),[g,m]=p.useState(!1),C=gt(),b=Te(),y=p.useCallback(S=>{d.clear();const k=S.target.value;h(k),m(!0),d.start(b.filterDebounceMs,()=>{const P=new Date(k);n(x({},t,{value:Number.isNaN(P.getTime())?void 0:P})),m(!1)})},[n,t,b.filterDebounceMs,d]);return p.useEffect(()=>{const S=RP(t.value,r);h(S)},[t.value,r]),v.jsx(b.slots.baseTextField,x({fullWidth:!0,id:C,label:o.current.getLocaleText("filterPanelInputLabel"),placeholder:o.current.getLocaleText("filterPanelInputPlaceholder"),value:f,onChange:y,variant:"standard",type:r||"text",InputLabelProps:{shrink:!0},inputRef:s,InputProps:x({},g||l?{endAdornment:g?v.jsx(b.slots.loadIcon,{fontSize:"small",color:"action"}):l}:{},{disabled:c},i,{inputProps:x({max:r==="datetime-local"?"9999-12-31T23:59":"9999-12-31",tabIndex:a},i==null?void 0:i.inputProps)})},u,(w=b.slotProps)==null?void 0:w.baseTextField))}function ya(e,t,n,r){if(!e.value)return null;const o=new Date(e.value);n?o.setSeconds(0,0):(o.setMinutes(o.getMinutes()+o.getTimezoneOffset()),o.setHours(0,0,0,0));const s=o.getTime();return i=>{if(!i)return!1;if(r)return t(i.getTime(),s);const l=new Date(i);return n?l.setSeconds(0,0):l.setHours(0,0,0,0),t(l.getTime(),s)}}const b2=e=>[{value:"is",getApplyFilterFn:t=>ya(t,(n,r)=>n===r,e),InputComponent:va,InputComponentPro Line truncated
`))}const gq=(e,t,n,r)=>{if(!e)return"";const o=Qf(r.current.state,t);return y2({value:e,columnType:"date",rowId:o,field:n.field}),e.toLocaleDateString()},mq=(e,t,n,r)=>{if(!e)return"";const o=Qf(r.current.state,t);return y2({value:e,columnType:"dateTime",rowId:o,field:n.field}),e.toLocaleString()},bq=x({},Fo,{type:"date",sortComparator:jO,valueFormatter:gq,filterOperators:b2(),renderEditCell:v2,pastedValueParser:e=>new Date(e)}),vq=x({},Fo,{type:"dateTime",sortComparator:jO,valueFormatter:mq,filterOperators:b2(!0),renderEditCell:v2,pastedValueParser:e=>new Date(e)}),ui=e=>e==null?null:Number(e),yq=e=>e==null||Number.isNaN(e)||e===""?null:t=>ui(t)===ui(e),xq=()=>[{value:"=",getApplyFilterFn:e=>e.value==null||Number.isNaN(e.value)?null:t=>ui(t)===e.value,InputComponent:Jr,InputComponentProps:{type:"number"}},{value:"!=",getApplyFilterFn:e=>e.value==null||Number.isNaN(e.value)?null:t=>ui(t)!==e.value,InputComponent:Jr,InputComponentProps:{type:"number"}},{value:">",getApplyFilterFn:e=>e.value==null||Number.isNaN(e.value)?null:t=>t==null?!1:ui(t)>e.value,InputComponent:Jr,InputComponentProps:{type:"number"}},{value:">=",getApplyFilterFn:e=>e.value==null||Number.isNaN(e.value)?null:t=>t==null?!1:ui(t)>=e.value,InputComponent:Jr,InputComponentProps:{type:"number"}},{value:"<",getApplyFilterFn:e=>e.value==null||Number.isNaN(e.value)?null:t=>t==null?!1:ui(t)<e.value,InputComponent:Jr,InputComponentProps:{type:"number"}},{value:"<=",getApplyFilterFn:e=>e.value==null||Number.isNaN(e.value)?null:t=>t==null?!1:ui(t)<=e.value,InputComponent:Jr,InputComponentProps:{type:"number"}},{value:"isEmpty",getApplyFilterFn:()=>e=>e==null,requiresFilterValue:!1},{value:"isNotEmpty",getApplyFilterFn:()=>e=>e!=null,requiresFilterValue:!1},{value:"isAnyOf",getApplyFilterFn:e=>!Array.isArray(e.value)||e.value.length===0?null:t=>t!=null&&e.value.includes(Number(t)),InputComponent:NO,InputComponentProps:{type:"number"}}],Cq=x({},Fo,{type:"number",align:"right",headerAlign:"right",sortComparator:AO,valueParser:e=>e===""?null:Number(e),valueFormatter:e=>q7(e)?e.toLocaleString():e||"",filterOperators:xq(),getApplyQuickFilterFn:yq});function Ac(e){return(e==null?void 0:e.type)==="singleSelect"}function Ql(e,t){if(e)return typeof e.valueOptions=="function"?e.valueOptions(x({field:e.field},t)):e.valueOptions}function Sg(e,t,n){if(t===void 0)return;const r=t.find(o=>{const s=n(o);return String(s)===String(e)});return n(r)}const wq=["id","value","formattedValue","api","field","row","rowNode","colDef","cellMode","isEditable","tabIndex","className","hasFocus","isValidating","isProcessingProps","error","onValueChange","initialOpen"],Sq=["MenuProps"];function kq(e){return!!e.key}function Pq(e){var $,L;const t=Te(),{id:n,value:r,field:o,row:s,colDef:i,hasFocus:l,error:a,onValueChange:c,initialOpen:u=t.editMode===us.Cell}=e,d=te(e,wq),f=qe(),h=p.useRef(null),g=p.useRef(null),[m,C]=p.useState(u),y=((($=t.slotProps)==null?void 0:$.baseSelect)||{}).native??!1,w=((L=t.slotProps)==null?void 0:L.baseSelect)||{},{MenuProps:S}=w,k=te(w,Sq);if(Et(()=>{var A;l&&((A=g.current)==null||A.focus())},[l]),!Ac(i))return null;const P=Ql(i,{id:n,row:s});if(!P)return null;const M=i.getOptionValue,I=i.getOptionLabel,E=async A=>{if(!Ac(i)||!P)return;C(!1);const R=A.target,_=Sg(R.value,P,M);c&&await c(A,_),await f.current.setEditCellValue({id:n,field:o,value:_},A)},T=(A,R)=>{if(t.editMode===us.Row){C(!1);return}if(R==="backdropClick"||A.key==="Escape"){const _=f.current.getCellParams(n,o);f.current.publishEvent("cellEditStop",x({},_,{reason:A.key==="Escape"?wo.escapeKeyDown:wo.cellFocusOut}))}},D=A=>{kq(A)&&A.key==="Enter"||C(!0)};return!P||!i?null:v.jsx(t.slots.baseSelect,x({ref:h,inputRef:g,value:r,onChange:E,open:m,onOpen:D,MenuProps:x({onClose:T},S),error:a,native:y,fullWidth:!0},d,k,{children:P.map(A=>{var _;const R=M(A);return p.createElement(t.slots.baseSelectOption,x({},((_=t.slotProps)==null?void 0:_.baseSelectOption)||{},{native:y,key:R,value:R}),I(A))})}))}const Mq=e=>v.jsx(Pq,x({},e)),Iq=["item","applyValue","type","apiRef","focusElementRef","placeholder","tabIndex","label","variant","isFilterActive","clearButton","InputLabelProps"],Eq=({column:e,OptionComponent:t,getOptionLabel:n,getOptionValue:r,isSelectNative:o,baseSelectOptionProps:s})=>["",...Ql(e)||[]].map(l=>{const a=r(l);let c=n(l);return c===""&&(c=" "),p.createElement(t,x({},s,{native:o,key:a,value:a}),c)}),_q=re("div")({display:"flex",alignItems:"flex-end",width:"100%","& button":{margin:"auto 0px 5px 5px"}});function OP(e){var M,I,E,T,D;const{item:t,applyValue:n,type:r,apiRef:o,focusElementRef:s,placeholder:i,tabIndex:l,label:a,variant:c="standard",clearButton:u}=e,d=te(e,Iq),f=t.value??"",h=gt(),g=gt(),m=Te(),C=((I=(M=m.slotProps)==null?void 0:M.baseSelect)==null?void 0:I.native)??!1;let b=null;if(t.field){const $=o.current.getColumn(t.field);Ac($)&&(b=$)}const y=b==null?void 0:b.getOptionValue,w=b==null?void 0:b.getOptionLabel,S=p.useMemo(()=>Ql(b),[b]),k=p.useCallback($=>{let L=$.target.value Line truncated
`));return e}const Gi=(e,t)=>Yf(e),ZC=(e,t)=>he(e,Yf),oX=typeof navigator<"u"?navigator.userAgent.toLowerCase():"empty",sX=oX.includes("firefox"),vb=e=>e.virtualization;Be(vb,e=>e.enabled);const _2=Be(vb,e=>e.enabledForColumns),iX=Be(vb,e=>e.enabledForRows),Jf=Be(vb,e=>e.renderContext),lX=ft(e=>e.virtualization.renderContext.firstColumnIndex,e=>e.virtualization.renderContext.lastColumnIndex,(e,t)=>({firstColumnIndex:e,lastColumnIndex:t})),mx={firstRowIndex:0,lastRowIndex:0,firstColumnIndex:0,lastColumnIndex:0},aX=(e,t)=>{const{disableVirtualization:n,autoHeight:r}=t;return x({},e,{virtualization:{enabled:!n,enabledForColumns:!n,enabledForRows:!n&&!r,renderContext:mx}})};function cX(e,t){const n=s=>{e.current.setState(i=>x({},i,{virtualization:x({},i.virtualization,{enabled:s,enabledForColumns:s,enabledForRows:s&&!t.autoHeight})}))};Xe(e,{unstable_setVirtualization:n,unstable_setColumnVirtualization:s=>{e.current.setState(i=>x({},i,{virtualization:x({},i.virtualization,{enabledForColumns:s})}))}},"public"),p.useEffect(()=>{n(!t.disableVirtualization)},[t.disableVirtualization,t.autoHeight])}const JC=e=>e.rowSpanning,T2=Be(JC,e=>e.hiddenCells),uX=Be(JC,e=>e.spannedCells),dX=Be(JC,e=>e.hiddenCellOriginMap),jc=e=>e.listViewColumn,fX=PO(cr,Jf,Yf,qt,to,(e,t,n,r,o)=>{if(!e)return!1;const s=o[e.id];if(!s)return!1;const i=n.rowToIndexMap.get(s),l=r.slice(t.firstColumnIndex,t.lastColumnIndex).findIndex(c=>c.field===e.field);return!(i!==void 0&&l!==-1&&i>=t.firstRowIndex&&i<=t.lastRowIndex)}),R2=ft(fX,qt,Yf,to,cr,(e,t,n,r,o)=>{if(!e)return null;const s=r[o.id];if(!s)return null;const i=n.rowToIndexMap.get(s);if(i===void 0)return null;const l=t.findIndex(a=>a.field===o.field);return l===-1?null:x({},o,{rowIndex:i,columnIndex:l})});function Wa(e,t){return Math.round(e*10**t)/10**t}const Pg=typeof window<"u"&&/jsdom|HappyDOM/.test(window.navigator.userAgent),Sv=50;var ln=function(e){return e[e.NONE=0]="NONE",e[e.UP=1]="UP",e[e.DOWN=2]="DOWN",e[e.LEFT=3]="LEFT",e[e.RIGHT=4]="RIGHT",e}(ln||{});const FP={top:0,left:0},hX=Object.freeze(new Map),pX=(e,t,n,r,o)=>({direction:ln.NONE,buffer:$2(e,ln.NONE,t,n,r,o)}),gX=()=>{var ge;const e=yo(),t=Te(),{unstable_listView:n}=t,r=he(e,()=>n?[jc(e.current.state)]:qt(e)),o=he(e,iX)&&!Pg,s=he(e,_2)&&!Pg,i=he(e,cu),l=du(e),a=n?Cg:l,c=i.bottom.length>0,[u,d]=p.useState(hX),f=fs(),h=he(e,Wi),g=ZC(e),m=e.current.mainElementRef,C=e.current.virtualScrollerRef,b=e.current.virtualScrollbarVerticalRef,y=e.current.virtualScrollbarHorizontalRef,w=he(e,nK),S=p.useRef(!1),k=he(e,AC),P=he(e,g7),M=he(e,cb),I=he(e,mX),E=he(e,FO),T=he(e,$O),D=p.useRef(null),$=p.useCallback(q=>{if(m.current=q,!q)return;const me=q.getBoundingClientRect();let ae={width:Wa(me.width,1),height:Wa(me.height,1)};if((!D.current||ae.width!==D.current.width&&ae.height!==D.current.height)&&(D.current=ae,e.current.publishEvent("resize",ae)),typeof ResizeObserver>"u")return;const ce=new ResizeObserver(ye=>{const ne=ye[0];if(!ne)return;const Oe={width:Wa(ne.contentRect.width,1),height:Wa(ne.contentRect.height,1)};Oe.width===ae.width&&Oe.height===ae.height||(e.current.publishEvent("resize",Oe),ae=Oe)});if(ce.observe(q),I2>=19)return()=>{m.current=null,ce.disconnect()}},[e,m]),L=p.useRef(((ge=t.initialState)==null?void 0:ge.scroll)??FP),A=p.useRef(!1),R=p.useRef(FP),_=p.useRef(mx),O=he(e,Jf),F=he(e,R2),j=pr(),z=p.useRef(void 0),H=zo(()=>pX(f,t.rowBufferPx,t.columnBufferPx,k*15,Sv*6)).current,B=p.useCallback(q=>{if(jP(q,e.current.state.virtualization.renderContext))return;const me=q.firstRowIndex!==_.current.firstRowIndex||q.lastRowIndex!==_.current.lastRowIndex;e.current.setState(ce=>x({},ce,{virtualization:x({},ce.virtualization,{renderContext:q})})),kn(e.current.state).isReady&&me&&(_.current=q,e.current.publishEvent("renderedRowsIntervalChange",q)),R.current=L.current},[e]),G=Ke(()=>{const q=C.current;if(!q)return;const me=kn(e.current.state),ae=Math.ceil(me.minimumSize.height-me.viewportOuterSize.height),ce=Math.ceil(me.minimumSize.width-me.viewportInnerSize.width),ye={top:Ar(q.scrollTop,0,ae),left:f?Ar(q.scrollLeft,-ce,0):Ar(q.scrollLeft,0,ce)},ne=ye.left-L.current.left,Oe=ye.top-L.current.top,_e=ne!==0||Oe!==0;L.current=ye;const Pe=_e?yX(ne,Oe):ln.NONE,He=Math.abs(L.current.top-R.current.top),De=Math.abs(L.current.left-R.current.left),we=He>=k||De>=Sv,Ae=H.direction!==Pe;if(!(we||Ae))return O;if(Ae)switch(Pe){case ln.NONE:case ln.LEFT:case ln.RIGHT:z.current=void 0;break;default:z.current=O;break}H.direction=Pe,H.buffer=$2(f,Pe,t.rowBufferPx,t.columnBufferPx,k*15,Sv*6);const be=LP(e,t,o,s),ue=DP(be,L.current,H);return jP(ue,O)||(cm.flushSync(()=>{B(ue)}),j.start(1e3,G)),ue}),V=()=>{if(!kn(e.current.state).isReady&&(o||s))return;const q=LP(e,t,o,s),me=DP(q,L.current,H);z.current=void 0,B(me)},Z=Ke(()=>{if(A.current){A.current=!1;return}const q=G();e.current.publishEvent("scrollPositionChange",{top:L.current.top,left:L.current.left,renderContext:q})}),Q=Ke(q=>{e.current.publishEvent("virtualScrollerWheel",{},q)}),U=Ke(q=>{e.current. Line truncated
`));return e},EX=Rt("div")({position:"absolute",top:"var(--DataGrid-headersTotalHeight)",left:0,width:"calc(100% - (var(--DataGrid-hasScrollY) * var(--DataGrid-scrollbarSize)))"}),_X=Rt("div",{name:"MuiDataGrid",slot:"Main",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.main,n.hasPinnedRight&&t["main--hasPinnedRight"],n.loadingOverlayVariant==="skeleton"&&t["main--hasSkeletonLoadingOverlay"]]}})({flexGrow:1,position:"relative",overflow:"hidden",display:"flex",flexDirection:"column"}),TX=at((e,t)=>{var i;const{ownerState:n}=e,r=Te(),s=ew().hooks.useGridAriaAttributes();return v.jsxs(_X,x({ownerState:n,className:e.className,tabIndex:-1},s,(i=r.slotProps)==null?void 0:i.main,{ref:t,children:[v.jsx(EX,{role:"presentation","data-id":"gridPanelAnchor"}),e.children]}))}),RX=()=>ve({root:["topContainer"]},et,{}),OX=Rt("div")({position:"sticky",zIndex:40,top:0});function $X(e){const t=RX();return v.jsx(OX,x({},e,{className:le(t.root,N["container--top"]),role:"presentation"}))}const FX=()=>ve({root:["bottomContainer"]},et,{}),LX=Rt("div")({position:"sticky",zIndex:40,bottom:"calc(var(--DataGrid-hasScrollX) * var(--DataGrid-scrollbarSize))"});function DX(e){const t=FX();return v.jsx(LX,x({},e,{className:le(t.root,N["container--bottom"]),role:"presentation"}))}const AX=(e,t)=>{const{classes:n}=e;return ve({root:["virtualScrollerContent",t&&"virtualScrollerContent--overflowed"]},et,n)},jX=Rt("div",{name:"MuiDataGrid",slot:"VirtualScrollerContent",overridesResolver:(e,t)=>{const{ownerState:n}=e;return[t.virtualScrollerContent,n.overflowedContent&&t["virtualScrollerContent--overflowed"]]}})({}),zX=at(function(t,n){var l;const r=Te(),o=!r.autoHeight&&((l=t.style)==null?void 0:l.minHeight)==="auto",s=AX(r,o),i={classes:r.classes,overflowedContent:o};return v.jsx(jX,x({},t,{ownerState:i,className:le(s.root,t.className),ref:n}))}),NX=Rt("div")({display:"flex",flexDirection:"row",width:"var(--DataGrid-rowWidth)",boxSizing:"border-box"}),L2=Rt("div")({position:"sticky",height:"100%",boxSizing:"border-box",borderTop:"1px solid var(--rowBorderColor)",backgroundColor:"var(--DataGrid-pinnedBackground)"}),HX=Rt(L2)({left:0,borderRight:"1px solid var(--rowBorderColor)"}),BX=Rt(L2)({right:0,borderLeft:"1px solid var(--rowBorderColor)"}),VX=Rt("div")({flexGrow:1,borderTop:"1px solid var(--rowBorderColor)"});function WX({rowsLength:e}){const t=qe(),{viewportOuterSize:n,minimumSize:r,hasScrollX:o,hasScrollY:s,scrollbarSize:i,leftPinnedWidth:l,rightPinnedWidth:a}=he(t,kn),c=o?i:0,u=n.height-r.height>0;return c===0&&!u?null:v.jsxs(NX,{className:N.filler,role:"presentation",style:{height:c,"--rowBorderColor":e===0?"transparent":"var(--DataGrid-rowBorderColor)"},children:[l>0&&v.jsx(HX,{className:N["filler--pinnedLeft"],style:{width:l}}),v.jsx(VX,{}),a>0&&v.jsx(BX,{className:N["filler--pinnedRight"],style:{width:a+(s?i:0)}})]})}const GX=Ks(WX),UX=["className"],KX=e=>{const{classes:t}=e;return ve({root:["virtualScrollerRenderZone"]},et,t)},qX=Rt("div",{name:"MuiDataGrid",slot:"VirtualScrollerRenderZone",overridesResolver:(e,t)=>t.virtualScrollerRenderZone})({position:"absolute",display:"flex",flexDirection:"column"}),XX=at(function(t,n){const{className:r}=t,o=te(t,UX),s=qe(),i=Te(),l=KX(i),a=he(s,()=>{const c=Jf(s);return gu(s.current.state).positions[c.firstRowIndex]??0});return v.jsx(qX,x({className:le(l.root,r),ownerState:i,style:{transform:`translate3d(0, ${a}px, 0)`}},o,{ref:n}))}),YX={includeHeaders:!0,includeOutliers:!1,outliersFactor:1.5,expand:!1,disableColumnVirtualization:!0},Cn=e=>e.editRows,D2=Uf(Cn,(e,{rowId:t,editMode:n})=>n===us.Row&&!!e[t]),QX=Uf(Cn,(e,{rowId:t,field:n})=>{var r;return((r=e[t])==null?void 0:r[n])??null}),zc=e=>e.preferencePanel,ZX=Uf(zc,(e,t)=>!!(e.open&&e.labelId===t));var Bs=function(e){return e.filters="filters",e.columns="columns",e}(Bs||{});const JX=(e,t)=>{const{classes:n}=e,r={root:["scrollbar",`scrollbar--${t}`],content:["scrollbarContent"]};return ve(r,et,n)},A2=Rt("div")({position:"absolute",display:"inline-block",zIndex:60,"&:hover":{zIndex:70},"--size":"calc(max(var(--DataGrid-scrollbarSize), 14px))"}),eY=Rt(A2)({width:"var(--size)",height:"calc(var(--DataGrid-hasScrollY) * (100% - var(--DataGrid-topContainerHeight) - var(--DataGrid-bottomContainerHeight) - var(--DataGrid-hasScrollX) * var(--DataGrid-scrollbarSize)))",overflowY:"auto",overflowX:"hidden",outline:0,"& > div":{width:"var(--size)"},top:"var(--DataGrid-topContainerHeight)",right:"0px"}),tY=Rt(A2)({width:"100%",height:"var(--size)",overflowY:"hidden",overflowX:"auto",outline:0,"& > div":{height:"var(--size)"},bottom:"0px"}),zP=at(function(t,n){const r=yo(),o=Te(),s=p.useRef(!1),i=p.useRef(0),l=p.useRef(null),a=p.useRef(null),c=JX(o,t.position),u=he(r,kn),d=t.position==="vertical"?"height":"width",f=t.position==="vertical"?"scrollTop":"scrollLeft",h=t.position==="vertical"?"top":"left",g=t.position==="vertical"?u.hasScrollX:u.hasScrollY,m=u.minimumSize[d]+(g?u.scrollbarSize:0),b=(t.position==="vertical"?u.viewportInnerSize.hei Line truncated
& .${N["columnHeader--withLeftBorder"]},
& .${N["columnHeader--withRightBorder"]},
& .${N["columnHeader--siblingFocused"]},
& .${N["virtualScroller--hasScrollX"]} .${N["columnHeader--lastUnpinned"]},
& .${N["virtualScroller--hasScrollX"]} .${N["columnHeader--last"]}
`]:{[`& .${N.columnSeparator}`]:{opacity:0},"@media (hover: none)":{[`& .${N["columnSeparator--resizable"]}`]:{opacity:1}},[`& .${N["columnSeparator--resizable"]}:hover`]:{opacity:1}},[`&.${N["root--noToolbar"]} [aria-rowindex="1"] [aria-colindex="1"]`]:{borderTopLeftRadius:"calc(var(--unstable_DataGrid-radius) - 1px)"},[`&.${N["root--noToolbar"]} [aria-rowindex="1"] .${N["columnHeader--last"]}`]:{borderTopRightRadius:n?"calc(var(--unstable_DataGrid-radius) - 1px)":void 0},[`& .${N.columnHeaderCheckbox}, & .${N.cellCheckbox}`]:{padding:0,justifyContent:"center",alignItems:"center"},[`& .${N.columnHeader}`]:{position:"relative",display:"flex",alignItems:"center"},[`& .${N["virtualScroller--hasScrollX"]} .${N["columnHeader--last"]}`]:{overflow:"hidden"},[`& .${N["columnHeader--sorted"]} .${N.iconButtonContainer}, & .${N["columnHeader--filtered"]} .${N.iconButtonContainer}`]:{visibility:"visible",width:"auto"},[`& .${N.columnHeader}:not(.${N["columnHeader--sorted"]}) .${N.sortButton}`]:{opacity:0,transition:e.transitions.create(["opacity"],{duration:e.transitions.duration.shorter})},[`& .${N.columnHeaderTitleContainer}`]:{display:"flex",alignItems:"center",gap:e.spacing(.25),minWidth:0,flex:1,whiteSpace:"nowrap",overflow:"hidden"},[`& .${N.columnHeaderTitleContainerContent}`]:{overflow:"hidden",display:"flex",alignItems:"center"},[`& .${N["columnHeader--filledGroup"]} .${N.columnHeaderTitleContainer}`]:{borderBottomWidth:"1px",borderBottomStyle:"solid",boxSizing:"border-box"},[`& .${N.sortIcon}, & .${N.filterIcon}`]:{fontSize:"inherit"},[`& .${N["columnHeader--sortable"]}`]:{cursor:"pointer"},[`& .${N["columnHeader--alignCenter"]} .${N.columnHeaderTitleContainer}`]:{justifyContent:"center"},[`& .${N["columnHeader--alignRight"]} .${N.columnHeaderDraggableContainer}, & .${N["columnHeader--alignRight"]} .${N.columnHeaderTitleContainer}`]:{flexDirection:"row-reverse"},[`& .${N["columnHeader--alignCenter"]} .${N.menuIcon}`]:{marginLeft:"auto"},[`& .${N["columnHeader--alignRight"]} .${N.menuIcon}`]:{marginRight:"auto",marginLeft:-5},[`& .${N["columnHeader--moving"]}`]:{backgroundColor:(e.vars||e).palette.action.hover},[`& .${N["columnHeader--pinnedLeft"]}, & .${N["columnHeader--pinnedRight"]}`]:{position:"sticky",zIndex:40,background:"var(--DataGrid-pinnedBackground)"},[`& .${N.columnSeparator}`]:{position:"absolute",overflow:"hidden",zIndex:30,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",maxWidth:PY,color:r},[`& .${N.columnHeaders}`]:{width:"var(--DataGrid-rowWidth)"},"@media (hover: hover)":{[`& .${N.columnHeader}:hover`]:{[`& .${N.menuIcon}`]:{width:"auto",visibility:"visible"},[`& .${N.iconButtonContainer}`]:{visibility:"visible",width:"auto"}},[`& .${N.columnHeader}:not(.${N["columnHeader--sorted"]}):hover .${N.sortButton}`]:{opacity:.5}},"@media (hover: none)":{[`& .${N.columnHeader} .${N.menuIcon}`]:{width:"auto",visibility:"visible"},[`& .${N.columnHeader}:focus,
& .${N["columnHeader--siblingFocused"]}`]:{[`.${N["columnSeparator--resizable"]}`]:{color:(e.vars||e).palette.primary.main}}},[`& .${N["columnSeparator--sideLeft"]}`]:{left:Fh},[`& .${N["columnSeparator--sideRight"]}`]:{right:Fh},[`& .${N["columnHeader--withRightBorder"]} .${N["columnSeparator--sideLeft"]}`]:{left:Fh-.5},[`& .${N["columnHeader--withRightBorder"]} .${N["columnSeparator--sideRight"]}`]:{right:Fh-.5},[`& .${N["columnSeparator--resizable"]}`]:{cursor:"col-resize",touchAction:"none",[`&.${N["columnSeparator--resizing"]}`]:{color:(e.vars||e).palette.primary.main},"@media (hover: none)":{[`& .${N.iconSeparator} rect`]:BP},"@media (hover: hover)":{"&:hover":{color:(e.vars||e).palette.primary.main,[`& .${N.iconSeparator} rect`]:BP}},"& svg":{pointerEvents:"none"}},[`& .${N.iconSeparator}`]:{color:"inherit",transition:e.transitions.create(["color","width"],{duration:e.transitions.duration.shortest})},[`& .${N.menuIcon}`]:{width:0,visibility:"hidden",fontSize:20,marginRight:-5,display:"flex",alignItems:"center"},[`.${N.menuOpen}`]:{visibility:"visible",width:"auto"},[`& .${N.headerFilterRow}`]:{[`& .${N.columnHeader}`]:{boxSizing:"border-box",borderBottom:"1px solid var(--DataGrid-rowBorderColor)"}},[`& .${N["row--borderBottom"]} .${N.columnHeader},
& .${N["row--borderBottom"]} .${N.filler},
& .${N["row--borderBottom"]} .${N.scrollbarFiller}`]:{borderBottom:"1px solid var(--DataGrid-rowBorderColor)"},[`& .${N["row--borderBottom"]} .${N.cell}`]:{borderBottom:"1px solid var(--rowBorderColor)"},[`.${N.row}`]:{display:"flex",width:"var(--DataGrid-rowWidth)",breakInside:"avoid","--rowBorderColor":"var(--DataGrid-rowBorderColor)",[`&.${N["row--firstVisible"]}`]:{"--rowBorderColor":"transparent"},"&:hover":{backgroundColor:(e.vars||e).palette.action.hover,"@media (hover: none)":{backgroundColor:"transparent"}},[`&.${N.rowSkeleton}:hover`]:{backgroundColor:"transparent"},"&.Mui-selected":P},[`& .${N["container--top"]}, & .${N["container--bottom"]}`]:{"[role=row]":{background:"var(--DataGrid-containerBackground)"}},[`& .${N.cell}`]:{flex:"0 0 auto",height:"var(--height)",width:"var(--width)",lineHeight:"calc(var(--height) - 1px)",boxSizing:"border-box",borderTop:"1px solid var(--rowBorderColor)",overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis","&.Mui-selected":P},[`& .${N["virtualScrollerContent--overflowed"]} .${N["row--lastVisible"]} .${N.cell}`]:{borderTopColor:"transparent"},[`& .${N["pinnedRows--top"]} :first-of-type`]:{[`& .${N.cell}, .${N.scrollbarFiller}`]:{borderTop:"none"}},[`&.${N["root--disableUserSelection"]}`]:{userSelect:"none"},[`& .${N["row--dynamicHeight"]} > .${N.cell}`]:{whiteSpace:"initial",lineHeight:"inherit"},[`& .${N.cellEmpty}`]:{flex:1,padding:0,height:"unset"},[`& .${N.cell}.${N["cell--selectionMode"]}`]:{cursor:"default"},[`& .${N.cell}.${N["cell--editing"]}`]:{padding:1,display:"flex",boxShadow:e.shadows[2],backgroundColor:(e.vars||e).palette.background.paper,"&:focus-within":{outline:`${Ca}px solid ${(e.vars||e).palette.primary.main}`,outlineOffset:Ca*-1}},[`& .${N["row--editing"]}`]:{boxShadow:e.shadows[2]},[`& .${N["row--editing"]} .${N.cell}`]:{boxShadow:e.shadows[0],backgroundColor:(e.vars||e).palette.background.paper},[`& .${N.editBooleanCell}`]:{display:"flex",height:"100%",width:"100%",alignItems:"center",justifyContent:"center"},[`& .${N.booleanCell}[data-value="true"]`]:{color:(e.vars||e).palette.text.secondary},[`& .${N.booleanCell}[data-value="false"]`]:{color:(e.vars||e).palette.text.disabled},[`& .${N.actionsCell}`]:{display:"inline-flex",alignItems:"center",gridGap:e.spacing(1)},[`& .${N.rowReorderCell}`]:{display:"inline-flex",flex:1,alignItems:"center",justifyContent:"center",opacity:(e.vars||e).palette.action.disabledOpacity},[`& .${N["rowReorderCell--draggable"]}`]:{cursor:"move",opacity:1},[`& .${N.rowReorderCellContainer}`]:{padding:0,display:"flex",alignItems:"stretch"},[`.${N.withBorderColor}`]:{borderColor:r},[`& .${N["cell--withLeftBorder"]}, & .${N["columnHeader--withLeftBorder"]}`]:{borderLeftColor:"var(--DataGrid-rowBorderColor)",borderLeftWidth:"1px",borderLeftStyle:"solid"},[`& .${N["cell--withRightBorder"]}, & .${N["columnHeader--withRightBorder"]}`]:{borderRightColor:"var(--DataGrid-rowBorderColor)",borderRightWidth:"1px",borderRightStyle:"solid"},[`& .${N["cell--flex"]}`]:{display:"flex",alignItems:"center",lineHeight:"inherit"},[`& .${N["cell--textLeft"]}`]:{textAlign:"left",justifyContent:"flex-start"},[`& .${N["cell--textRight"]}`]:{textAlign:"right",justifyContent:"flex-end"},[`& .${N["cell--textCenter"]}`]:{textAlign:"center",justifyContent:"center"},[`& .${N["cell--pinnedLeft"]}, & .${N["cell--pinnedRight"]}`]:{position:"sticky",zIndex:30,background:"var(--DataGrid-pinnedBackground)","&.Mui-selected":{backgroundColor:y}},[`& .${N.virtualScrollerContent} .${N.row}`]:{"&:hover":b,"&.Mui-selected":w,"&.Mui-selected:hover":k},[`& .${N.cellOffsetLeft}`]:{flex:"0 0 auto",display:"inline-block"},[`& .${N.cellSkeleton}`]:{flex:"0 0 auto",height:"100%",display:"inline-flex",alignItems:"center"},[`& .${N.columnHeaderDraggableContainer}`]:{display:"flex",width:"100%",height:"100%"},[`& .${N.rowReorderCellPlaceholder}`]:{display:"none"},[`& .${N["columnHeader--dragging"]}, & .${N["row--dragging"]}`]:{background:(e.vars||e).palette.background.paper,padding:"0 12px",borderRadius:"var(--unstable_DataGrid-radius)",opacity:(e.vars||e).palette.action.disabledOpacity},[`& .${N["row--dragging"]}`]:{background:(e.vars||e).palette.background.paper,padding:"0 12px",borderRadius:"var(--unstable_DataGrid-radius)",opacity:(e.vars||e).palette.action.disabledOpacity,[`& .${N.rowReorderCellPlaceholder}`]:{display:"flex"}},[`& .${N.treeDataGroupingCell}`]:{display:"flex",alignItems:"center",width:"100%"},[`& .${N.treeDataGroupingCellToggle}`]:{flex:"0 0 28px",alignSelf:"stretch",marginRight:e.spacing(2)},[`& .${N.treeDataGroupingCellLoadingContainer}, .${N.groupingCriteriaCellLoadingContainer}`]:{display:"flex",alignItems:"center",justifyContent:"center",height:"100%"},[`& .${N.groupingCriteriaCell}`]:{display:"flex",alignItems:"center",width:"100%"},[`& .${N.groupingCriteriaCellToggle}`]:{flex:"0 0 28px",alignSelf:"stretch",marginRight:e.spacing(2)},[`.${N.scrollbarFiller}`]:{minWidth:"calc(var(--DataGrid-hasScrollY) * var(--DataGrid-scrollbarS Line truncated
& .${Rn.input}::-webkit-search-cancel-button,
& .${Rn.input}::-webkit-search-results-button,
& .${Rn.input}::-webkit-search-results-decoration`]:{display:"none"}})),eJ=re("div",{name:"MuiDataGrid",slot:"ColumnsManagementFooter",overridesResolver:(e,t)=>t.columnsManagementFooter})(({theme:e})=>({padding:e.spacing(.5,1,.5,3),display:"flex",justifyContent:"space-between",borderTop:`1px solid ${e.palette.divider}`})),tJ=re("div")(({theme:e})=>({padding:e.spacing(.5,0),color:e.palette.grey[500]})),nJ=e=>{const{classes:t}=e;return ve({root:["toolbarFilterList"]},et,t)},rJ=re("ul",{name:"MuiDataGrid",slot:"ToolbarFilterList",overridesResolver:(e,t)=>t.toolbarFilterList})(({theme:e})=>({margin:e.spacing(1,1,.5),padding:e.spacing(0,1)})),oJ=at(function(t,n){var y,w,S;const{slotProps:r={}}=t,o=r.button||{},s=r.tooltip||{},i=r.badge||{},l=qe(),a=Te(),c=he(l,UC),u=he(l,hs),d=he(l,zc),f=nJ(a),h=gt(),g=gt(),m=p.useMemo(()=>{if(d.open)return l.current.getLocaleText("toolbarFiltersTooltipHide");if(c.length===0)return l.current.getLocaleText("toolbarFiltersTooltipShow");const k=M=>u[M.field].filterOperators.find(I=>I.value===M.operator).label||l.current.getLocaleText(`filterOperator${oe(M.operator)}`).toString(),P=M=>{const{getValueAsString:I}=u[M.field].filterOperators.find(E=>E.value===M.operator);return I?I(M.value):M.value};return v.jsxs("div",{children:[l.current.getLocaleText("toolbarFiltersTooltipActive")(c.length),v.jsx(rJ,{className:f.root,ownerState:a,children:c.map((M,I)=>x({},u[M.field]&&v.jsx("li",{children:`${u[M.field].headerName||M.field}
${k(M)}
${M.value!=null?P(M):""}`},I)))})]})},[l,a,d.open,c,u,f]),C=k=>{var I;const{open:P,openedPanelValue:M}=d;P&&M===Bs.filters?l.current.hidePreferences():l.current.showPreferences(Bs.filters,g,h),(I=o.onClick)==null||I.call(o,k)};if(a.disableColumnFilter)return null;const b=d.open&&d.panelId===g;return v.jsx(a.slots.baseTooltip,x({title:m,enterDelay:1e3},(y=a.slotProps)==null?void 0:y.baseTooltip,s,{children:v.jsx(a.slots.baseButton,x({id:h,size:"small","aria-label":l.current.getLocaleText("toolbarFiltersLabel"),"aria-controls":b?g:void 0,"aria-expanded":b,"aria-haspopup":!0,startIcon:v.jsx(a.slots.baseBadge,x({badgeContent:c.length,color:"primary"},(w=a.slotProps)==null?void 0:w.baseBadge,i,{children:v.jsx(a.slots.openFilterButtonIcon,{})}))},(S=a.slotProps)==null?void 0:S.baseButton,o,{onClick:C,onPointerUp:k=>{var P;d.open&&k.stopPropagation(),(P=o.onPointerUp)==null||P.call(o,k)},ref:n,children:l.current.getLocaleText("toolbarFilters")}))}))}),sJ=at(function(t,n){var y,w;const{children:r,slotProps:o={}}=t,s=o.button||{},i=o.tooltip||{},l=qe(),a=Te(),c=gt(),u=gt(),[d,f]=p.useState(!1),h=p.useRef(null),g=vt(n,h),m=S=>{var k;f(P=>!P),(k=s.onClick)==null||k.call(s,S)},C=()=>f(!1),b=S=>{S.key==="Tab"&&S.preventDefault(),U2(S.key)&&C()};return r==null?null:v.jsxs(p.Fragment,{children:[v.jsx(a.slots.baseTooltip,x({title:l.current.getLocaleText("toolbarExportLabel"),enterDelay:1e3},(y=a.slotProps)==null?void 0:y.baseTooltip,i,{children:v.jsx(a.slots.baseButton,x({size:"small",startIcon:v.jsx(a.slots.exportIcon,{}),"aria-expanded":d,"aria-label":l.current.getLocaleText("toolbarExportLabel"),"aria-haspopup":"menu","aria-controls":d?u:void 0,id:c},(w=a.slotProps)==null?void 0:w.baseButton,s,{onClick:m,ref:g,children:l.current.getLocaleText("toolbarExport")}))})),v.jsx(HC,{open:d,target:h.current,onClose:C,position:"bottom-start",children:v.jsx(Jm,{id:u,className:N.menuList,"aria-labelledby":c,onKeyDown:b,autoFocusItem:d,children:p.Children.map(r,S=>p.isValidElement(S)?p.cloneElement(S,{hideMenu:C}):S)})})]})}),iJ=["hideMenu","options"],lJ=["hideMenu","options"],aJ=["csvOptions","printOptions","excelOptions"];function cJ(e){const t=qe(),{hideMenu:n,options:r}=e,o=te(e,iJ);return v.jsx(cn,x({onClick:()=>{t.current.exportDataAsCsv(r),n==null||n()}},o,{children:t.current.getLocaleText("toolbarExportCSV")}))}function uJ(e){const t=qe(),{hideMenu:n,options:r}=e,o=te(e,lJ);return v.jsx(cn,x({onClick:()=>{t.current.exportDataAsPrint(r),n==null||n()}},o,{children:t.current.getLocaleText("toolbarExportPrint")}))}at(function(t,n){const r=t,{csvOptions:o={},printOptions:s={},excelOptions:i}=r,l=te(r,aJ),c=qe().current.unstable_applyPipeProcessors("exportMenu",[],{excelOptions:i,csvOptions:o,printOptions:s}).sort((u,d)=>u.componentName>d.componentName?1:-1);return c.length===0?null:v.jsx(sJ,x({},l,{ref:n,children:c.map((u,d)=>p.cloneElement(u.component,{key:d}))}))});const dJ=["quickFilterParser","quickFilterFormatter","debounceMs","className"],fJ=e=>{const{classes:t}=e;return ve({root:["toolbarQuickFilter"]},et,t)},hJ=re($o,{name:"MuiDataGrid",slot:"ToolbarQuickFilter",overridesResolver:(e,t)=>t.toolbarQuickFilter})(({theme:e})=>({width:"auto",paddingBottom:e.spacing(.5),"& input":{marginLeft:e.spacing(.5)},"& .MuiInput-underline:before":{borderBottom:`1px solid ${(e.vars||e).palette.divider}`},'& input[type="search"]::-webkit-search-decoration,\n & input[type="search"]::-webkit-search-cancel-button,\n & input[type="search"]::-webkit-search-results-button,\n & input[type="search"]::-webkit-search-results-decoration':{display:"none"}})),pJ=e=>e.split(" ").filter(t=>t!==""),gJ=e=>e.join(" ");function mJ(e){var b,y;const t=qe(),n=Te(),r=fJ(n),o=he(t,r2),{quickFilterParser:s=pJ,quickFilterFormatter:i=gJ,debounceMs:l=n.filterDebounceMs,className:a}=e,c=te(e,dJ),[u,d]=p.useState(()=>i(o??[])),f=p.useRef(o);p.useEffect(()=>{is(f.current,o)||(f.current=o,d(w=>is(s(w),o)?w:i(o??[])))},[o,i,s]);const h=p.useCallback(w=>{const S=s(w);f.current=S,t.current.setQuickFilterValues(S)},[t,s]),g=p.useMemo(()=>Qc(h,l),[h,l]);p.useEffect(()=>g.clear,[g]);const m=p.useCallback(w=>{const S=w.target.value;d(S),g(S)},[g]),C=p.useCallback(()=>{d(""),h("")},[h]);return v.jsx(hJ,x({as:n.slots.baseTextField,ownerState:n,variant:"standard",value:u,onChange:m,className:le(r.root,a),placeholder:t.current.getLocaleText("toolbarQuickFilterPlaceholder"),"aria-label":t.current.getLocaleText("toolbarQuickFilterLabel"),type:"search"},c,{InputProps:x({startAdornment:v.jsx(n.slots.quickFilterIcon,{fontSize:"small"}),endAdornment:v.jsx(n.slots.baseIconButton,x({"aria-label":t.current.getLocaleText("toolbarQuickFilterDeleteIconLabel"),size:"small",sx:[u?{visibility:"visible"}:{visibility:"hidden"}],onClick:C},(b=n.slotProps)==null?void 0:b.baseIconButton,{children:v.jsx(n.slots.quickFilterClearIcon,{fontSize:"small"})}))},c.InputProps)},(y=n.slotProps)==null?void 0:y.baseTextField))}const bJ=["className","selectedRowCount"],vJ=e=>{const{classes:t} Line truncated
`,"\r",'"'].some(o=>n.includes(o))?`"${r}"`:r}return n}const Y2=(e,t)=>{var s,i;const{csvOptions:n,ignoreValueFormatter:r}=t;let o;if(r){const l=e.colDef.type;l==="number"?o=String(e.value):l==="date"||l==="dateTime"?o=(s=e.value)==null?void 0:s.toISOString():typeof((i=e.value)==null?void 0:i.toString)=="function"?o=e.value.toString():o=e.value}else o=e.formattedValue;return vx(o,n)};class yx{constructor(t){this.options=void 0,this.rowString="",this.isEmpty=!0,this.options=t}addValue(t){this.isEmpty||(this.rowString+=this.options.csvOptions.delimiter),typeof this.options.sanitizeCellValue=="function"?this.rowString+=this.options.sanitizeCellValue(t,this.options.csvOptions):this.rowString+=t,this.isEmpty=!1}getRowString(){return this.rowString}}const cee=({id:e,columns:t,getCellParams:n,csvOptions:r,ignoreValueFormatter:o})=>{const s=new yx({csvOptions:r});return t.forEach(i=>{const l=n(e,i.field);s.addValue(Y2(l,{ignoreValueFormatter:o,csvOptions:r}))}),s.getRowString()};function uee(e){const{columns:t,rowIds:n,csvOptions:r,ignoreValueFormatter:o,apiRef:s}=e,i=n.reduce((d,f)=>`${d}${cee({id:f,columns:t,getCellParams:s.current.getCellParams,ignoreValueFormatter:o,csvOptions:r})}\r
`,"").trim();if(!r.includeHeaders)return i;const l=t.filter(d=>d.field!==pu.field),a=[];if(r.includeColumnGroupsHeaders){const d=s.current.getAllGroupDetails();let f=0;const h=l.reduce((g,m)=>{const C=s.current.getColumnGroupPath(m.field);return g[m.field]=C,f=Math.max(f,C.length),g},{});for(let g=0;g<f;g+=1){const m=new yx({csvOptions:r,sanitizeCellValue:vx});a.push(m),l.forEach(C=>{const b=(h[C.field]||[])[g],y=d[b];m.addValue(y?y.headerName||y.groupId:"")})}}const c=new yx({csvOptions:r,sanitizeCellValue:vx});return l.forEach(d=>{c.addValue(d.headerName||d.field)}),a.push(c),`${`${a.map(d=>d.getRowString()).join(`\r
`)}\r
`}${i}`.trim()}function iM(e){const t=document.createElement("span");t.style.whiteSpace="pre",t.style.userSelect="all",t.style.opacity="0px",t.textContent=e,document.body.appendChild(t);const n=document.createRange();n.selectNode(t);const r=window.getSelection();r.removeAllRanges(),r.addRange(n);try{document.execCommand("copy")}finally{document.body.removeChild(t)}}function dee(e){navigator.clipboard?navigator.clipboard.writeText(e).catch(()=>{iM(e)}):iM(e)}function fee(e){var t;return!!((t=window.getSelection())!=null&&t.toString()||e&&(e.selectionEnd||0)-(e.selectionStart||0)>0)}const hee=(e,t)=>{const n=t.ignoreValueFormatterDuringExport,r=(typeof n=="object"?n==null?void 0:n.clipboardExport:n)||!1,o=t.clipboardCopyCellDelimiter,s=p.useCallback(i=>{if(!tZ(i)||fee(i.target))return;let l="";if(e.current.getSelectedRows().size>0)l=e.current.getDataAsCsv({includeHeaders:!1,delimiter:o,shouldAppendQuotes:!1,escapeFormulas:!1});else{const c=cr(e);if(c){const u=e.current.getCellParams(c.id,c.field);l=Y2(u,{csvOptions:{delimiter:o,shouldAppendQuotes:!1,escapeFormulas:!1},ignoreValueFormatter:r})}}l=e.current.unstable_applyPipeProcessors("clipboardCopy",l),l&&(dee(l),e.current.publishEvent("clipboardCopy",l))},[e,r,o]);c2(e,()=>e.current.rootElementRef.current,"keydown",s),St(e,"clipboardCopy",t.onClipboardCopy)},pee=e=>x({},e,{columnMenu:{open:!1}}),gee=e=>{const t=Mn(e,"useGridColumnMenu"),n=p.useCallback(i=>{const l=xp(e.current.state),a={open:!0,field:i};(a.open!==l.open||a.field!==l.field)&&(e.current.setState(u=>u.columnMenu.open&&u.columnMenu.field===i?u:(t.debug("Opening Column Menu"),x({},u,{columnMenu:{open:!0,field:i}}))),e.current.hidePreferences())},[e,t]),r=p.useCallback(()=>{const i=xp(e.current.state);if(i.field){const c=hs(e),u=no(e),d=$s(e);let f=i.field;if(c[f]||(f=d[0]),u[f]===!1){const h=d.filter(m=>m===f?!0:u[m]!==!1),g=h.indexOf(f);f=h[g+1]||h[g-1]}e.current.setColumnHeaderFocus(f)}const l={open:!1,field:void 0};(l.open!==i.open||l.field!==i.field)&&e.current.setState(c=>(t.debug("Hiding Column Menu"),x({},c,{columnMenu:l})))},[e,t]),o=p.useCallback(i=>{t.debug("Toggle Column Menu");const l=xp(e.current.state);!l.open||l.field!==i?n(i):r()},[e,t,n,r]);Xe(e,{showColumnMenu:n,hideColumnMenu:r,toggleColumnMenu:o},"public"),Ee(e,"columnResizeStart",r),Ee(e,"virtualScrollerWheel",e.current.hideColumnMenu),Ee(e,"virtualScrollerTouchMove",e.current.hideColumnMenu)},mee=(e,t,n)=>{var o,s,i;const r=Ia({apiRef:n,columnsToUpsert:t.columns,initialState:(o=t.initialState)==null?void 0:o.columns,columnVisibilityModel:t.columnVisibilityModel??((i=(s=t.initialState)==null?void 0:s.columns)==null?void 0:i.columnVisibilityModel)??{},keepOnlyColumnsToUpsert:!0});return x({},e,{columns:r,pinnedColumns:e.pinnedColumns??Cg})};function bee(e,t){var T,D;const n=Mn(e,"useGridColumns"),r=p.useRef(t.columns);e.current.registerControlState({stateId:"visibleColumns",propModel:t.columnVisibilityModel,propOnChange:t.onColumnVisibilityModelChange,stateSelector:no,changeEvent:"columnVisibilityModelChange"});const o=p.useCallback($=>{n.debug("Updating columns state."),e.current.setState(lM($)),e.current.publishEvent("columnsChange",$.orderedFields)},[n,e]),s=p.useCallback($=>hs(e)[$],[e]),i=p.useCallback(()=>lo(e),[e]),l=p.useCallback(()=>qt(e),[e]),a=p.useCallback(($,L=!0)=>(L?qt(e):lo(e)).findIndex(R=>R.field===$),[e]),c=p.useCallback($=>{const L=a($);return rl(e)[L]},[e,a]),u=p.useCallback($=>{var A,R;no(e)!==$&&(e.current.setState(_=>x({},_,{columns:Ia({apiRef:e,columnsToUpsert:[],initialState:void 0,columnVisibilityModel:$,keepOnlyColumnsToUpsert:!1})})),(R=(A=e.current).updateRenderContext)==null||R.call(A),e.current.forceUpdate())},[e]),d=p.useCallback($=>{const L=Ia({apiRef:e,columnsToUpsert:$,initialState:void 0,keepOnlyColumnsToUpsert:!1});o(L)},[e,o]),f=p.useCallback(($,L)=>{const A=no(e),R=A[$]??!0;if(L!==R){const _=x({},A,{[$]:L});e.current.setColumnVisibilityModel(_)}},[e]),h=p.useCallback($=>$s(e).findIndex(A=>A===$),[e]),g=p.useCallback(($,L)=>{const A=$s(e),R=h($);if(R===L)return;n.debug(`Moving column ${$} to index ${L}`);const _=[...A],O=_.splice(R,1)[0];_.splice(L,0,O),o(x({},ls(e.current.state),{orderedFields:_}));const F={column:e.current.getColumn($),targetIndex:e.current.getColumnIndexRelativeToVisibleColumns($),oldIndex:R};e.current.publishEvent("columnIndexChange",F)},[e,n,o,h]),m=p.useCallback(($,L)=>{n.debug(`Updating column ${$} width to ${L}`);const A=ls(e.current.state),R=A.lookup[$],_=x({},R,{width:L,hasBeenResized:!0});o(gx(x({},A,{lookup:x({},A.lookup,{[$]:_})}),e.current.getRootDimensions())),e.current.publishEvent("columnWidthChange",{element:e.current.getColumnHeaderElement($),colDef:_,width:L})},[e,n,o]),C={getColumn:s,getAllColumns:i,getColumnIndex:a,getColumnPosition:c,getVisibleColumns:l,getColumnIndexRelativeToVisibleColumns:h,updateColumns:d,setColumnVisibilityModel:u,setColumnVisibility:f,setColumnWidth:m},b={setColumnIndex:g};Xe(e,C,"public"),Xe(e,b,t.signature===io.DataGrid?"prLine truncated
`);G.appendChild(w.createTextNode(Z)),w.head.appendChild(G)}}else if(B.getAttribute("href")){const G=w.createElement(B.tagName);for(let V=0;V<B.attributes.length;V+=1){const Z=B.attributes[V];Z&&G.setAttribute(Z.nodeName,Z.nodeValue||"")}A.push(new Promise(V=>{G.addEventListener("load",()=>V())})),w.head.appendChild(G)}}}Promise.all(A).then(()=>{C.contentWindow.print()})},[e,o,t]),f=p.useCallback(C=>{var b,y;o.current.body.removeChild(C),e.current.restoreState(s.current||{}),(y=(b=s.current)==null?void 0:b.columns)!=null&&y.columnVisibilityModel||e.current.setColumnVisibilityModel(i.current),e.current.setState(w=>x({},w,{virtualization:a.current})),e.current.setRows(l.current),s.current=null,i.current={},l.current=[]},[e]),g={exportDataAsPrint:p.useCallback(async C=>{if(r.debug("Export data as Print"),!e.current.rootElementRef.current)throw new Error("MUI X: No grid root element available.");if(s.current=e.current.exportState(),i.current=no(e),l.current=e.current.getSortedRows().filter(y=>!y[Lc]),t.pagination){const w={page:0,pageSize:WC(e)};e.current.setState(S=>x({},S,{pagination:x({},S.pagination,{paginationModel:Cp(S.pagination,"DataGridPro",w)})}))}a.current=e.current.state.virtualization,e.current.unstable_setVirtualization(!1),await c(C==null?void 0:C.fields,C==null?void 0:C.allColumns,C==null?void 0:C.includeCheckboxes),u((C==null?void 0:C.getRowsToExport)??Z2),await See();const b=kee(C==null?void 0:C.fileName);b.onload=()=>{d(b,C),b.contentWindow.matchMedia("print").addEventListener("change",w=>{w.matches===!1&&f(b)})},o.current.body.appendChild(b)},[t,r,e,d,f,c,u])};Xe(e,g,"public");const m=p.useCallback((C,b)=>{var y;return(y=b.printOptions)!=null&&y.disableToolbarButton?C:[...C,{component:v.jsx(uJ,{options:b.printOptions}),componentName:"printExport"}]},[]);Bt(e,"exportMenu",m)},Mee=(e,t,n)=>{var o,s;const r=t.filterModel??((s=(o=t.initialState)==null?void 0:o.filter)==null?void 0:s.filterModel)??ff();return x({},e,{filter:x({filterModel:NC(r,t.disableMultipleColumnsFiltering,n)},BO),visibleRowsLookup:{}})},Iee=e=>e.filteredRowsLookup;function aM(e,t){return e.current.applyStrategyProcessor("visibleRowsLookupCreation",{tree:t.rows.tree,filteredRowsLookup:t.filter.filteredRowsLookup})}function Eee(){return wO(Object.values)}const _ee=(e,t)=>{var E,T,D;const n=Mn(e,"useGridFilter");e.current.registerControlState({stateId:"filter",propModel:t.filterModel,propOnChange:t.onFilterModelChange,stateSelector:_n,changeEvent:"filterModelChange"});const r=p.useCallback(()=>{e.current.setState($=>{const L=_n($,e.current.instanceId),A=e.current.getFilterState(L),R=x({},$,{filter:x({},$.filter,A)}),_=aM(e,R);return x({},R,{visibleRowsLookup:_})}),e.current.publishEvent("filteredRowsSet")},[e]),o=p.useCallback(($,L)=>L==null||L.filterable===!1||t.disableColumnFilter?$:[...$,"columnMenuFilterItem"],[t.disableColumnFilter]),s=p.useCallback(()=>{r(),e.current.forceUpdate()},[e,r]),i=p.useCallback($=>{const L=_n(e),A=[...L.items],R=A.findIndex(_=>_.id===$.id);R===-1?A.push($):A[R]=$,e.current.setFilterModel(x({},L,{items:A}),"upsertFilterItem")},[e]),l=p.useCallback($=>{const L=_n(e),A=[...L.items];$.forEach(R=>{const _=A.findIndex(O=>O.id===R.id);_===-1?A.push(R):A[_]=R}),e.current.setFilterModel(x({},L,{items:A}),"upsertFilterItems")},[e]),a=p.useCallback($=>{const L=_n(e),A=L.items.filter(R=>R.id!==$.id);A.length!==L.items.length&&e.current.setFilterModel(x({},L,{items:A}),"deleteFilterItem")},[e]),c=p.useCallback(($,L,A)=>{if(n.debug("Displaying filter panel"),$){const R=_n(e),_=R.items.filter(z=>{var V;if(z.value!==void 0)return!(Array.isArray(z.value)&&z.value.length===0);const B=(V=e.current.getColumn(z.field).filterOperators)==null?void 0:V.find(Z=>Z.value===z.operator);return!(typeof(B==null?void 0:B.requiresFilterValue)>"u"?!0:B==null?void 0:B.requiresFilterValue)});let O;const F=_.find(z=>z.field===$),j=e.current.getColumn($);F?O=_:t.disableMultipleColumnsFiltering?O=[px({field:$,operator:j.filterOperators[0].value},e)]:O=[..._,px({field:$,operator:j.filterOperators[0].value},e)],e.current.setFilterModel(x({},R,{items:O}))}e.current.showPreferences(Bs.filters,L,A)},[e,n,t.disableMultipleColumnsFiltering]),u=p.useCallback(()=>{n.debug("Hiding filter panel"),e.current.hidePreferences()},[e,n]),d=p.useCallback($=>{const L=_n(e);L.logicOperator!==$&&e.current.setFilterModel(x({},L,{logicOperator:$}),"changeLogicOperator")},[e]),f=p.useCallback($=>{const L=_n(e);is(L.quickFilterValues,$)||e.current.setFilterModel(x({},L,{quickFilterValues:[...$]}))},[e]),h=p.useCallback(($,L)=>{_n(e)!==$&&(n.debug("Setting filter model"),e.current.updateControlState("filter",wP($,t.disableMultipleColumnsFiltering,e),L),e.current.unstable_applyFilters())},[e,n,t.disableMultipleColumnsFiltering]),g=p.useCallback($=>{const L=NC($,t.disableMultipleColumnsFiltering,e),A=t.filterMode==="client"?iK(L,e,t.disableEval):null,R=e.current.applyStrategyProcessor("filtering",{isRowMatchingFilters:A,filterModel:L??ff()});return x({},R,{fil Line truncated
`));const _=_P(e,R,t.getRowId),O=EP({updates:_,getRowId:t.getRowId,previousCache:e.current.caches.rows});a({cache:O,throttle:!0})},[t.signature,t.getRowId,a,e]),d=p.useCallback((R,_)=>{const O=_P(e,R,t.getRowId),F=EP({updates:O,getRowId:t.getRowId,previousCache:e.current.caches.rows,groupKeys:_??[]});a({cache:F,throttle:!1})},[t.getRowId,a,e]),f=p.useCallback(R=>{R!==t.loading&&(n.debug(`Setting loading to ${R}`),e.current.setState(_=>x({},_,{rows:x({},_.rows,{loading:R})})),e.current.caches.rows.loadingPropBeforePartialUpdates=R)},[t.loading,e,n]),h=p.useCallback(()=>{const R=nd(e),_=to(e);return new Map(R.map(O=>[O,_[O]??{}]))},[e]),g=p.useCallback(()=>Kf(e),[e]),m=p.useCallback(()=>nd(e),[e]),C=p.useCallback(R=>{const _=e.current.getRow(R),{rowToIndexMap:O}=Gi(e);return O.get(_)},[e]),b=p.useCallback((R,_)=>{const O=e.current.getRowNode(R);if(!O)throw new Error(`MUI X: No row with id #${R} found.`);if(O.type!=="group")throw new Error("MUI X: Only group nodes can be expanded or collapsed.");const F=x({},O,{childrenExpanded:_});e.current.setState(j=>x({},j,{rows:x({},j.rows,{tree:x({},j.rows.tree,{[R]:F})})})),e.current.forceUpdate(),e.current.publishEvent("rowExpansionChange",F)},[e]),y=p.useCallback(R=>mn(e)[R]??null,[e]),w=p.useCallback(({skipAutoGeneratedRows:R=!0,groupId:_,applySorting:O,applyFiltering:F})=>{const j=mn(e);let z;if(O){const H=j[_];if(!H)return[];const B=fu(e);z=[];const G=B.findIndex(V=>V===_)+1;for(let V=G;V<B.length&&j[B[V]].depth>H.depth;V+=1){const Z=B[V];(!R||!Dc(j[Z]))&&z.push(Z)}}else z=BC(j,_,R);if(F){const H=hu(e);z=z.filter(B=>H[B]!==!1)}return z},[e]),S=p.useCallback((R,_)=>{const O=e.current.getRowNode(R);if(!O)throw new Error(`MUI X: No row with id #${R} found.`);if(O.parent!==jn)throw new Error("MUI X: The row reordering do not support reordering of grouped rows yet.");if(O.type!=="leaf")throw new Error("MUI X: The row reordering do not support reordering of footer or grouping rows.");e.current.setState(F=>{const j=mn(F,e.current.instanceId)[jn],z=j.children,H=z.findIndex(G=>G===R);if(H===-1||H===_)return F;n.debug(`Moving row ${R} to index ${_}`);const B=[...z];return B.splice(_,0,B.splice(H,1)[0]),x({},F,{rows:x({},F.rows,{tree:x({},F.rows.tree,{[jn]:x({},j,{children:B})})})})}),e.current.publishEvent("rowsSet")},[e,n]),k=p.useCallback((R,_)=>{if(t.signature===io.DataGrid&&_.length>1)throw new Error(["MUI X: You cannot replace rows using `apiRef.current.unstable_replaceRows` on the DataGrid.","You need to upgrade to DataGridPro or DataGridPremium component to unlock this feature."].join(`
`));if(_.length===0)return;if(la(e)>1)throw new Error("`apiRef.current.unstable_replaceRows` is not compatible with tree data and row grouping");const F=x({},mn(e)),j=x({},to(e)),z=x({},bP(e)),H=F[jn],B=[...H.children],G=new Set;for(let Z=0;Z<_.length;Z+=1){const Q=_[Z],U=db(Q,t.getRowId,"A row was provided without id when calling replaceRows()."),[K]=B.splice(R+Z,1,U);G.has(K)||(delete j[K],delete z[K],delete F[K]);const ee={id:U,depth:0,parent:jn,type:"leaf",groupingKey:null};j[U]=Q,z[U]=U,F[U]=ee,G.add(U)}F[jn]=x({},H,{children:B});const V=B.filter(Z=>{var Q;return((Q=F[Z])==null?void 0:Q.type)==="leaf"});e.current.caches.rows.dataRowIdToModelLookup=j,e.current.caches.rows.dataRowIdToIdLookup=z,e.current.setState(Z=>x({},Z,{rows:x({},Z.rows,{dataRowIdToModelLookup:j,dataRowIdToIdLookup:z,dataRowIds:V,tree:F})})),e.current.publishEvent("rowsSet")},[e,t.signature,t.getRowId]),P={getRow:i,setLoading:f,getRowId:l,getRowModels:h,getRowsCount:g,getAllRowIds:m,setRows:c,updateRows:u,getRowNode:y,getRowIndexRelativeToVisibleRows:C,unstable_replaceRows:k},M={setRowIndex:S,setRowChildrenExpansion:b,getRowGroupChildren:w},I={updateServerRows:d},E=p.useCallback(()=>{n.info("Row grouping pre-processing have changed, regenerating the row tree");let R;e.current.caches.rows.rowsBeforePartialUpdates===t.rows?R=x({},e.current.caches.rows,{updates:{type:"full",rows:nd(e)}}):R=vp({rows:t.rows,getRowId:t.getRowId,loading:t.loading,rowCount:t.rowCount}),a({cache:R,throttle:!1})},[n,e,t.rows,t.getRowId,t.loading,t.rowCount,a]),T=zo(()=>t.unstable_dataSource),D=p.useCallback(R=>{if(t.unstable_dataSource&&t.unstable_dataSource!==T.current){T.current=t.unstable_dataSource;return}R==="rowTreeCreation"&&E()},[E,T,t.unstable_dataSource]),$=p.useCallback(()=>{e.current.getActiveStrategy("rowTree")!==z7(e)&&E()},[e,E]);Ee(e,"activeStrategyProcessorChange",D),Ee(e,"strategyAvailabilityChange",$);const L=p.useCallback(()=>{e.current.setState(R=>{const _=e.current.unstable_applyPipeProcessors("hydrateRows",{tree:mn(R,e.current.instanceId),treeDepths:vP(R,e.current.instanceId),dataRowIds:nd(R,e.current.instanceId),dataRowIdToModelLookup:to(R,e.current.instanceId),dataRowIdToIdLookup:bP(R,e.current.instanceId)});return x({},R,{rows:x({},R.rows,_,{totalTopLevelRowCount:YO({tree:_.tree,rowCountProp:t.rowCount})})})}),e.current.publishEvent("rowsSet"),e.current.forceUpdate()},[e,t.rowCount]);iw(e,"hydrateRows",L),Xe(e,P,"public"),Xe(e,M,t.signature===io.DataGrid?"private":"public"),Xe(e,I,"private");const A=p.useRef(!0);p.useEffect(()=>{var j;if(A.current){A.current=!1;return}let R=!1;t.rowCount!==o.current&&(R=!0,o.current=t.rowCount);const _=e.current.caches.rows.rowsBeforePartialUpdates===t.rows,O=e.current.caches.rows.loadingPropBeforePartialUpdates===t.loading,F=e.current.caches.rows.rowCountPropBeforePartialUpdates===t.rowCount;_&&(O||(e.current.setState(z=>x({},z,{rows:x({},z.rows,{loading:t.loading})})),e.current.caches.rows.loadingPropBeforePartialUpdates=t.loading,e.current.forceUpdate()),F||(e.current.setState(z=>x({},z,{rows:x({},z.rows,{totalRowCount:Math.max(t.rowCount||0,z.rows.totalRowCount),totalTopLevelRowCount:Math.max(t.rowCount||0,z.rows.totalTopLevelRowCount)})})),e.current.caches.rows.rowCountPropBeforePartialUpdates=t.rowCount,e.current.forceUpdate()),!R)||(n.debug(`Updating all rows, new length ${(j=t.rows)==null?void 0:j.length}`),a({cache:vp({rows:t.rows,getRowId:t.getRowId,loading:t.loading,rowCount:t.rowCount}),throttle:!1}))},[t.rows,t.rowCount,t.getRowId,t.loading,n,a,e])},Qee=e=>{const t={[jn]:x({},xK(),{children:e})};for(let n=0;n<e.length;n+=1){const r=e[n];t[r]={id:r,depth:0,parent:jn,type:"leaf",groupingKey:null}}return{groupingName:Zl,tree:t,treeDepths:{0:e.length},dataRowIds:e}},Zee=({previousTree:e,actions:t})=>{const n=x({},e),r={};for(let i=0;i<t.remove.length;i+=1){const l=t.remove[i];r[l]=!0,delete n[l]}for(let i=0;i<t.insert.length;i+=1){const l=t.insert[i];n[l]={id:l,depth:0,parent:jn,type:"leaf",groupingKey:null}}const o=n[jn];let s=[...o.children,...t.insert];return Object.values(r).length&&(s=s.filter(i=>!r[i])),n[jn]=x({},o,{children:s}),{groupingName:Zl,tree:n,treeDepths:{0:s.length},dataRowIds:s}},Jee=e=>e.updates.type==="full"?Qee(e.updates.rows):Zee({previousTree:e.previousTree,actions:e.updates.actions}),ete=e=>{Tg(e,Zl,"rowTreeCreation",Jee)};class Ev extends Error{}function tte(e,t){var g;const n=p.useCallback(m=>({field:m,colDef:e.current.getColumn(m)}),[e]),r=p.useCallback(m=>{const C=e.current.getRow(m);if(!C)throw new Ev(`No row with id #${m} found`);return{id:m,columns:e.current.getAllColumns(),row:C}},[e]),o=p.useCallback((m,C,b,{cellMode:y,colDef:w,hasFocus:S,rowNode:k,tabIndex:P})=>{const M=b[C],I=w!=null&&w.valueGetter?w.valueGetter(M,b,w,e):M,E={id:m,field:C,row:b,rowNode:k,colDef:w,cellMode:y,hasFocus:S,tabIndex:P,value:I,formattedValue:I,isEditable:!1,api:e.current};return w&&w.valueFormatter&&(E.formattedValue=w.valueFormatter(I,b,w,e)),E.isEditable=w&&e.current.isCellEdita Line truncated
`));_r(e.current.state)!==U&&(n.debug("Setting selection model"),e.current.setState(ee=>x({},ee,{rowSelection:t.rowSelection?U:[]})),e.current.forceUpdate())},[e,n,t.rowSelection,t.signature,u]),m=p.useCallback(U=>_r(e.current.state).includes(U),[e]),C=p.useCallback(U=>{if(t.rowSelection===!1||c&&!c(e.current.getRowParams(U)))return!1;const K=mn(e)[U];return!((K==null?void 0:K.type)==="footer"||(K==null?void 0:K.type)==="pinnedRow")},[e,t.rowSelection,c]),b=p.useCallback(()=>VK(e),[e]),y=p.useCallback((U,K=!0,ee=!1)=>{var de,se,ge,q,me,ae;if(e.current.isRowSelectable(U))if(i.current=U,ee){n.debug(`Setting selection for row ${U}`);const ce=[],ye=ne=>{ce.push(ne)};K&&(ye(U),o&&Nu(e,d,U,((de=t.rowSelectionPropagation)==null?void 0:de.descendants)??!1,((se=t.rowSelectionPropagation)==null?void 0:se.parents)??!1,ye)),e.current.setRowSelectionModel(ce)}else{n.debug(`Toggling selection for row ${U}`);const ce=_r(e.current.state),ye=new Set(ce);ye.delete(U);const ne=Pe=>{ye.add(Pe)},Oe=Pe=>{ye.delete(Pe)};K?(ne(U),o&&Nu(e,d,U,((ge=t.rowSelectionPropagation)==null?void 0:ge.descendants)??!1,((q=t.rowSelectionPropagation)==null?void 0:q.parents)??!1,ne)):o&&TP(e,d,U,((me=t.rowSelectionPropagation)==null?void 0:me.descendants)??!1,((ae=t.rowSelectionPropagation)==null?void 0:ae.parents)??!1,Oe),(ye.size<2||u)&&e.current.setRowSelectionModel(Array.from(ye))}},[e,n,o,d,(z=t.rowSelectionPropagation)==null?void 0:z.descendants,(H=t.rowSelectionPropagation)==null?void 0:H.parents,u]),w=p.useCallback((U,K=!0,ee=!1)=>{n.debug("Setting selection for several rows");const de=U.filter(q=>e.current.isRowSelectable(q));let se;if(ee){if(K){if(se=new Set(de),o){const me=ae=>{se.add(ae)};de.forEach(ae=>{var ce,ye;Nu(e,d,ae,((ce=t.rowSelectionPropagation)==null?void 0:ce.descendants)??!1,((ye=t.rowSelectionPropagation)==null?void 0:ye.parents)??!1,me)})}}else se=new Set;const q=Wi(e);if(se.size===Object.keys(q).length&&Array.from(se).every(me=>q[me]===me))return}else{se=new Set(Object.values(Wi(e)));const q=ae=>{se.add(ae)},me=ae=>{se.delete(ae)};de.forEach(ae=>{var ce,ye,ne,Oe;K?(se.add(ae),o&&Nu(e,d,ae,((ce=t.rowSelectionPropagation)==null?void 0:ce.descendants)??!1,((ye=t.rowSelectionPropagation)==null?void 0:ye.parents)??!1,q)):(me(ae),o&&TP(e,d,ae,((ne=t.rowSelectionPropagation)==null?void 0:ne.descendants)??!1,((Oe=t.rowSelectionPropagation)==null?void 0:Oe.parents)??!1,me))})}(se.size<2||u)&&e.current.setRowSelectionModel(Array.from(se))},[n,o,u,e,d,(B=t.rowSelectionPropagation)==null?void 0:B.descendants,(G=t.rowSelectionPropagation)==null?void 0:G.parents]),S=p.useCallback(U=>{var de,se;if(!f||!o||U.length===0)return U;const K=new Set(U),ee=ge=>{K.add(ge)};for(const ge of U)Nu(e,d,ge,((de=t.rowSelectionPropagation)==null?void 0:de.descendants)??!1,((se=t.rowSelectionPropagation)==null?void 0:se.parents)??!1,ee,K);return Array.from(K)},[e,d,(V=t.rowSelectionPropagation)==null?void 0:V.descendants,(Z=t.rowSelectionPropagation)==null?void 0:Z.parents,f,o]),k=p.useCallback(({startId:U,endId:K},ee=!0,de=!1)=>{if(!e.current.getRow(U)||!e.current.getRow(K))return;n.debug(`Expanding selection from row ${U} to row ${K}`);const se=nc(e),ge=se.indexOf(U),q=se.indexOf(K),[me,ae]=ge>q?[q,ge]:[ge,q],ce=se.slice(me,ae+1);e.current.selectRows(ce,ee,de)},[e,n]),P={selectRow:y,setRowSelectionModel:g,getSelectedRows:b,isRowSelected:m,isRowSelectable:C},M={selectRows:w,selectRowRange:k,getPropagatedRowSelectionModel:S};Xe(e,P,"public"),Xe(e,M,t.signature===io.DataGrid?"private":"public");const I=p.useRef(!0),E=p.useCallback((U=!1)=>{var ae;if(I.current)return;const K=_r(e.current.state),ee=to(e),de=hu(e),se=x({},Wi(e)),ge=ce=>t.filterMode==="server"?!ee[ce]:!ee[ce]||de[ce]===!1;let q=!1;K.forEach(ce=>{var ne;if(ge(ce)){if(t.keepNonExistentRowsSelected)return;delete se[ce],q=!0;return}if(!((ne=t.rowSelectionPropagation)!=null&&ne.parents))return;const ye=d[ce];if(ye.type==="group"){if(ye.isAutoGenerated){delete se[ce],q=!0;return}ye.children.every(_e=>de[_e]===!1)||(delete se[ce],q=!0)}});const me=f&&((ae=t.rowSelectionPropagation)==null?void 0:ae.parents)&&Object.keys(se).length>0;if(q||me&&!U){const ce=Object.values(se);me?e.current.selectRows(ce,!0,!0):e.current.setRowSelectionModel(ce)}},[e,f,(Q=t.rowSelectionPropagation)==null?void 0:Q.parents,t.keepNonExistentRowsSelected,t.filterMode,d]),T=p.useCallback((U,K)=>{const ee=K.metaKey||K.ctrlKey,de=!l&&!ee&&!eZ(K),se=!u||de,ge=e.current.isRowSelected(U);se?e.current.selectRow(U,de?!0:!ge,!0):e.current.selectRow(U,!ge,!1)},[e,u,l]),D=p.useCallback((U,K)=>{var se;if(a)return;const ee=(se=K.target.closest(`.${N.cell}`))==null?void 0:se.getAttribute("data-field");if(ee===pu.field||ee===fb)return;if(ee){const ge=e.current.getColumn(ee);if((ge==null?void 0:ge.type)===ub)return}mn(e)[U.id].type!=="pinnedRow"&&(K.shiftKey&&u?h(U.id):T(U.id,K))},[a,u,e,h,T]),$=p.useCallback((U,K)=>{var ee;u&&K.shiftKey&&((ee=window.getSelection())==null||ee.removeAllRanges())},[u]),L=p.useCallback((U,K)=>{u&&K.nativeEv Line truncated
`)),r.current=!0),$.width===0&&!r.current&&!Pg&&(n.error(["The parent DOM element of the Data Grid has an empty width.","Please make sure that this element has an intrinsic width.","The grid displays with a width of 0px.","","More details: https://mui.com/r/x-data-grid-no-dimensions."].join(`
`)),r.current=!0),a.current||!M){a.current=!1,k();return}M()},[k,t.autoHeight,M,n]);St(e,"rootMount",T),St(e,"resize",D),St(e,"debouncedResize",t.onResize)}function uM(e,t){const n=(r,o)=>e.style.setProperty(r,o);n("--DataGrid-hasScrollX",`${Number(t.hasScrollX)}`),n("--DataGrid-hasScrollY",`${Number(t.hasScrollY)}`),n("--DataGrid-scrollbarSize",`${t.scrollbarSize}px`),n("--DataGrid-rowWidth",`${t.rowWidth}px`),n("--DataGrid-columnsTotalWidth",`${t.columnsTotalWidth}px`),n("--DataGrid-leftPinnedWidth",`${t.leftPinnedWidth}px`),n("--DataGrid-rightPinnedWidth",`${t.rightPinnedWidth}px`),n("--DataGrid-headerHeight",`${t.headerHeight}px`),n("--DataGrid-headersTotalHeight",`${t.headersTotalHeight}px`),n("--DataGrid-topContainerHeight",`${t.topContainerHeight}px`),n("--DataGrid-bottomContainerHeight",`${t.bottomContainerHeight}px`),n("--height",`${t.rowHeight}px`)}function t$(e,t,n,r){const o=JO(e.rowHeight,Cx.rowHeight);return{rowHeight:Math.floor(o*n),headerHeight:Math.floor(e.columnHeaderHeight*n),groupHeaderHeight:Math.floor((e.columnGroupHeaderHeight??e.columnHeaderHeight)*n),headerFilterHeight:Math.floor((e.headerFilterHeight??e.columnHeaderHeight)*n),columnsTotalWidth:e$(t),headersTotalHeight:bb(t,e),leftPinnedWidth:r.left.reduce((s,i)=>s+i.computedWidth,0),rightPinnedWidth:r.right.reduce((s,i)=>s+i.computedWidth,0)}}const dM=new WeakMap;function pte(e,t){if(t!==void 0)return t;if(e===null)return 0;const n=dM.get(e);if(n!==void 0)return n;const o=Ft(e).createElement("div");o.style.width="99px",o.style.height="99px",o.style.position="absolute",o.style.overflow="scroll",o.className="scrollDiv",e.appendChild(o);const s=o.offsetWidth-o.clientWidth;return e.removeChild(o),dM.set(e,s),s}function fM(e,t){return e.width===t.width&&e.height===t.height}const gte=typeof globalThis.ResizeObserver<"u"?globalThis.ResizeObserver:class{observe(){}unobserve(){}disconnect(){}},mte=(e,t,n)=>{n.current.caches.rowsMeta={heights:new Map};const r=AC(n.current.state),o=Kf(n),s=Xf(n.current.state),i=Math.min(s.enabled?s.paginationModel.pageSize:o,o);return x({},e,{rowsMeta:{currentPageTotalHeight:i*r,positions:Array.from({length:i},(l,a)=>a*r),pinnedTopRowsTotalHeight:0,pinnedBottomRowsTotalHeight:0}})},bte=(e,t)=>{const{getRowHeight:n,getRowSpacing:r,getEstimatedRowHeight:o}=t,s=e.current.caches.rowsMeta.heights,i=p.useRef(-1),l=p.useRef(!1),a=p.useRef(!1),c=he(e,au),u=ZC(e),d=he(e,cu),f=he(e,AC),h=T=>{let D=s.get(T);return D===void 0&&(D={content:f,spacingTop:0,spacingBottom:0,detail:0,autoHeight:!1,needsFirstMeasurement:!0},s.set(T,D)),D},g=p.useCallback(T=>{const D=kn(e.current.state).rowHeight,$=e.current.getRowHeightEntry(T.id);if(!n)$.content=D,$.needsFirstMeasurement=!1;else{const L=n(x({},T,{densityFactor:c}));if(L==="auto"){if($.needsFirstMeasurement){const A=o?o(x({},T,{densityFactor:c})):D;$.content=A??D}l.current=!0,$.autoHeight=!0}else $.content=JO(L,D),$.needsFirstMeasurement=!1,$.autoHeight=!1}if(r){const L=e.current.getRowIndexRelativeToVisibleRows(T.id),A=r(x({},T,{isFirstVisible:L===0,isLastVisible:L===u.rows.length-1,indexRelativeToCurrentPage:L}));$.spacingTop=A.top??0,$.spacingBottom=A.bottom??0}else $.spacingTop=0,$.spacingBottom=0;return e.current.unstable_applyPipeProcessors("rowHeight",$,T),$},[e,u.rows,n,o,f,r,c]),m=p.useCallback(()=>{l.current=!1;const T=d.top.reduce((_,O)=>{const F=g(O);return _+F.content+F.spacingTop+F.spacingBottom+F.detail},0),D=d.bottom.reduce((_,O)=>{const F=g(O);return _+F.content+F.spacingTop+F.spacingBottom+F.detail},0),$=[],L=u.rows.reduce((_,O)=>{$.push(_);const F=g(O),j=F.content+F.spacingTop+F.spacingBottom+F.detail;return _+j},0);l.current||(i.current=1/0);const A=T!==e.current.state.rowsMeta.pinnedTopRowsTotalHeight||D!==e.current.state.rowsMeta.pinnedBottomRowsTotalHeight||L!==e.current.state.rowsMeta.currentPageTotalHeight,R={currentPageTotalHeight:L,positions:$,pinnedTopRowsTotalHeight:T,pinnedBottomRowsTotalHeight:D};e.current.setState(_=>x({},_,{rowsMeta:R})),A&&e.current.updateDimensions(),a.current=!0},[e,d,u.rows,g]),C=T=>{var D;return((D=s.get(T))==null?void 0:D.content)??f},b=(T,D)=>{const $=e.current.getRowHeightEntry(T),L=$.content!==D;$.needsFirstMeasurement=!1,$.content=D,a.current&&(a.current=!L)},y=T=>{var D;return((D=s.get(T))==null?void 0:D.autoHeight)??!1},w=()=>i.current,S=T=>{l.current&&T>i.current&&(i.current=T)},k=()=>{s.clear(),m()},P=zo(()=>new gte(T=>{var D;for(let $=0;$<T.length;$+=1){const L=T[$],A=L.borderBoxSize&&L.borderBoxSize.length>0?L.borderBoxSize[0].blockSize:L.contentRect.height,R=L.target.__mui_id;if(((D=R2(e))==null?void 0:D.id)===R&&A===0)return;e.current.unstable_storeRowHeightMeasurement(R,A)}a.current||requestAnimationFrame(()=>{e.current.requestPipeProcessorsApplication("rowHeight")})})).current,M=(T,D)=>(T.__mui_id=D,P.observe(T),()=>P.unobserve(T));iw(e,"rowHeight",m),Et(()=>{m()},[m]);const I={unstable_getRowHeight:C,unstable_setLastMeasuredRowIndex:S,unstable_storeRowHeightMeasurement:b,resetRowHeights:k},E={hydrateRowsMet Line truncated
`));n[e.field]=t;return}const{groupId:r,children:o}=e;o.forEach(s=>{n$(s,[...t,r],n)})},wx=e=>{if(!e)return{};const t={};return e.forEach(n=>{n$(n,[],t)}),t},Sx=(e,t,n)=>{const r=a=>t[a]??[],o=[],s=Math.max(...e.map(a=>r(a).length)),i=(a,c,u)=>is(r(a).slice(0,u+1),r(c).slice(0,u+1)),l=(a,c)=>!!(n!=null&&n.left&&n.left.includes(a)&&!n.left.includes(c)||n!=null&&n.right&&!n.right.includes(a)&&n.right.includes(c));for(let a=0;a<s;a+=1){const c=e.reduce((u,d)=>{const f=r(d)[a]??null;if(u.length===0)return[{columnFields:[d],groupId:f}];const h=u[u.length-1],g=h.columnFields[h.columnFields.length-1];return h.groupId!==f||!i(g,d,a)||l(g,d)?[...u,{columnFields:[d],groupId:f}]:[...u.slice(0,u.length-1),{columnFields:[...h.columnFields,d],groupId:f}]},[]);o.push(c)}return o},Cte=["groupId","children"],lw=e=>{let t={};return e.forEach(n=>{if(HO(n))return;const{groupId:r,children:o}=n,s=te(n,Cte);if(!r)throw new Error("MUI X: An element of the columnGroupingModel does not have either `field` or `groupId`.");const i=x({},s,{groupId:r}),l=lw(o);if(l[r]!==void 0||t[r]!==void 0)throw new Error(`MUI X: The groupId ${r} is used multiple times in the columnGroupingModel.`);t=x({},t,l,{[r]:i})}),x({},t)},wte=(e,t,n)=>{if(!t.columnGroupingModel)return e;const r=$s(n),o=uu(n),s=lw(t.columnGroupingModel??[]),i=wx(t.columnGroupingModel??[]),l=Sx(r,i,n.current.state.pinnedColumns??{}),a=o.length===0?0:Math.max(...o.map(c=>{var u;return((u=i[c])==null?void 0:u.length)??0}));return x({},e,{columnGrouping:{lookup:s,unwrappedGroupingModel:i,headerStructure:l,maxDepth:a}})},Ste=(e,t)=>{const n=p.useCallback(l=>x2(e)[l]??[],[e]),r=p.useCallback(()=>C2(e),[e]);Xe(e,{getColumnGroupPath:n,getAllGroupDetails:r},"public");const s=p.useCallback(()=>{const l=wx(t.columnGroupingModel??[]);e.current.setState(a=>{var f;const c=((f=a.columns)==null?void 0:f.orderedFields)??[],u=a.pinnedColumns??{},d=Sx(c,l,u);return x({},a,{columnGrouping:x({},a.columnGrouping,{headerStructure:d})})})},[e,t.columnGroupingModel]),i=p.useCallback(l=>{var m,C;const a=((C=(m=e.current).getPinnedColumns)==null?void 0:C.call(m))??{},c=$s(e),u=uu(e),d=lw(l??[]),f=wx(l??[]),h=Sx(c,f,a),g=u.length===0?0:Math.max(...u.map(b=>{var y;return((y=f[b])==null?void 0:y.length)??0}));e.current.setState(b=>x({},b,{columnGrouping:{lookup:d,unwrappedGroupingModel:f,headerStructure:h,maxDepth:g}}))},[e]);Ee(e,"columnIndexChange",s),Ee(e,"columnsChange",()=>{i(t.columnGroupingModel)}),Ee(e,"columnVisibilityModelChange",()=>{i(t.columnGroupingModel)}),p.useEffect(()=>{i(t.columnGroupingModel)},[i,t.columnGroupingModel])};function kte(){let e,t;const n=new Promise((r,o)=>{e=r,t=o});return n.resolve=e,n.reject=t,n}function hM(e,t){if(t!==void 0&&e.changedTouches){for(let n=0;n<e.changedTouches.length;n+=1){const r=e.changedTouches[n];if(r.identifier===t)return{x:r.clientX,y:r.clientY}}return!1}return{x:e.clientX,y:e.clientY}}function pM(e,t,n,r){let o=e;return r==="Right"?o+=t-n.left:o+=n.right-t,o}function Pte(e,t,n){return n==="Left"?e-t.left:t.right-e}function Mte(e){return e==="Right"?"Left":"Right"}function Ite(e,t){const n=e.classList.contains(N["columnSeparator--sideRight"])?"Right":"Left";return t?Mte(n):n}function gM(e){e.preventDefault(),e.stopImmediatePropagation()}function Ete(e){const t=p.useRef(void 0),n=()=>_2(e),r=he(e,n);return p.useEffect(()=>{t.current&&r===!1&&(t.current.resolve(),t.current=void 0)}),()=>{if(!t.current){if(n()===!1)return Promise.resolve();t.current=kte()}return t.current}}function _te(e,t){if(e.length<4)return e;const n=e.slice();n.sort((l,a)=>l-a);const r=n[Math.floor(n.length*.25)],o=n[Math.floor(n.length*.75)-1],s=o-r,i=s<5?5:s*t;return n.filter(l=>l>r-i&&l<o+i)}function Tte(e,t,n){const r={},o=e.current.rootElementRef.current;return o.classList.add(N.autosizing),n.forEach(s=>{const l=fQ(e.current,s.field).map(g=>g.getBoundingClientRect().width??0),a=t.includeOutliers?l:_te(l,t.outliersFactor);if(t.includeHeaders){const g=dQ(e.current,s.field);if(g){const m=g.querySelector(`.${N.columnHeaderTitle}`),C=g.querySelector(`.${N.columnHeaderTitleContainerContent}`),b=g.querySelector(`.${N.iconButtonContainer}`),y=g.querySelector(`.${N.menuIcon}`),w=m??C,S=window.getComputedStyle(g,null),k=parseInt(S.paddingLeft,10)+parseInt(S.paddingRight,10),M=w.scrollWidth+1+k+((b==null?void 0:b.clientWidth)??0)+((y==null?void 0:y.clientWidth)??0);a.push(M)}}const c=s.minWidth!==-1/0&&s.minWidth!==void 0,u=s.maxWidth!==1/0&&s.maxWidth!==void 0,d=c?s.minWidth:0,f=u?s.maxWidth:1/0,h=a.length===0?0:Math.max(...a);r[s.field]=Ar(h,d,f)}),o.classList.remove(N.autosizing),r}const Rte=e=>x({},e,{columnResize:{resizingColumnField:""}});function Ote(){return{colDef:void 0,initialColWidth:0,initialTotalWidth:0,previousMouseClickEvent:void 0,columnHeaderElement:void 0,headerFilterElement:void 0,groupHeaderElements:[],cellElements:[],leftPinnedCellsAfter:[],rightPinnedCellsBefore:[],fillerLeft:void 0,fillerRight:void 0,leftPinnedHeadersAfter:[],rightPinnedHeadersBefore:[]}}const $te Line truncated
* @kurkle/color v0.3.4
* https://github.com/kurkle/color#readme
* (c) 2024 Jukka Kurkela
* Released under the MIT License
*/function th(e){return e+.5|0}const Mi=(e,t,n)=>Math.max(Math.min(e,n),t);function sd(e){return Mi(th(e*2.55),0,255)}function Ui(e){return Mi(th(e*255),0,255)}function Ps(e){return Mi(th(e/2.55)/100,0,1)}function yM(e){return Mi(th(e*100),0,100)}const Vr={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Mx=[..."0123456789ABCDEF"],Zne=e=>Mx[e&15],Jne=e=>Mx[(e&240)>>4]+Mx[e&15],Lh=e=>(e&240)>>4===(e&15),ere=e=>Lh(e.r)&&Lh(e.g)&&Lh(e.b)&&Lh(e.a);function tre(e){var t=e.length,n;return e[0]==="#"&&(t===4||t===5?n={r:255&Vr[e[1]]*17,g:255&Vr[e[2]]*17,b:255&Vr[e[3]]*17,a:t===5?Vr[e[4]]*17:255}:(t===7||t===9)&&(n={r:Vr[e[1]]<<4|Vr[e[2]],g:Vr[e[3]]<<4|Vr[e[4]],b:Vr[e[5]]<<4|Vr[e[6]],a:t===9?Vr[e[7]]<<4|Vr[e[8]]:255})),n}const nre=(e,t)=>e<255?t(e):"";function rre(e){var t=ere(e)?Zne:Jne;return e?"#"+t(e.r)+t(e.g)+t(e.b)+nre(e.a,t):void 0}const ore=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function g$(e,t,n){const r=t*Math.min(n,1-n),o=(s,i=(s+e/30)%12)=>n-r*Math.max(Math.min(i-3,9-i,1),-1);return[o(0),o(8),o(4)]}function sre(e,t,n){const r=(o,s=(o+e/60)%6)=>n-n*t*Math.max(Math.min(s,4-s,1),0);return[r(5),r(3),r(1)]}function ire(e,t,n){const r=g$(e,1,.5);let o;for(t+n>1&&(o=1/(t+n),t*=o,n*=o),o=0;o<3;o++)r[o]*=1-t-n,r[o]+=t;return r}function lre(e,t,n,r,o){return e===o?(t-n)/r+(t<n?6:0):t===o?(n-e)/r+2:(e-t)/r+4}function ww(e){const n=e.r/255,r=e.g/255,o=e.b/255,s=Math.max(n,r,o),i=Math.min(n,r,o),l=(s+i)/2;let a,c,u;return s!==i&&(u=s-i,c=l>.5?u/(2-s-i):u/(s+i),a=lre(n,r,o,u,s),a=a*60+.5),[a|0,c||0,l]}function Sw(e,t,n,r){return(Array.isArray(t)?e(t[0],t[1],t[2]):e(t,n,r)).map(Ui)}function kw(e,t,n){return Sw(g$,e,t,n)}function are(e,t,n){return Sw(ire,e,t,n)}function cre(e,t,n){return Sw(sre,e,t,n)}function m$(e){return(e%360+360)%360}function ure(e){const t=ore.exec(e);let n=255,r;if(!t)return;t[5]!==r&&(n=t[6]?sd(+t[5]):Ui(+t[5]));const o=m$(+t[2]),s=+t[3]/100,i=+t[4]/100;return t[1]==="hwb"?r=are(o,s,i):t[1]==="hsv"?r=cre(o,s,i):r=kw(o,s,i),{r:r[0],g:r[1],b:r[2],a:n}}function dre(e,t){var n=ww(e);n[0]=m$(n[0]+t),n=kw(n),e.r=n[0],e.g=n[1],e.b=n[2]}function fre(e){if(!e)return;const t=ww(e),n=t[0],r=yM(t[1]),o=yM(t[2]);return e.a<255?`hsla(${n}, ${r}%, ${o}%, ${Ps(e.a)})`:`hsl(${n}, ${r}%, ${o}%)`}const xM={x:"dark",Z:"light",Y:"re",X:"blu",W:"gr",V:"medium",U:"slate",A:"ee",T:"ol",S:"or",B:"ra",C:"lateg",D:"ights",R:"in",Q:"turquois",E:"hi",P:"ro",O:"al",N:"le",M:"de",L:"yello",F:"en",K:"ch",G:"arks",H:"ea",I:"ightg",J:"wh"},CM={OiceXe:"f0f8ff",antiquewEte:"faebd7",aqua:"ffff",aquamarRe:"7fffd4",azuY:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"0",blanKedOmond:"ffebcd",Xe:"ff",XeviTet:"8a2be2",bPwn:"a52a2a",burlywood:"deb887",caMtXe:"5f9ea0",KartYuse:"7fff00",KocTate:"d2691e",cSO:"ff7f50",cSnflowerXe:"6495ed",cSnsilk:"fff8dc",crimson:"dc143c",cyan:"ffff",xXe:"8b",xcyan:"8b8b",xgTMnPd:"b8860b",xWay:"a9a9a9",xgYF:"6400",xgYy:"a9a9a9",xkhaki:"bdb76b",xmagFta:"8b008b",xTivegYF:"556b2f",xSange:"ff8c00",xScEd:"9932cc",xYd:"8b0000",xsOmon:"e9967a",xsHgYF:"8fbc8f",xUXe:"483d8b",xUWay:"2f4f4f",xUgYy:"2f4f4f",xQe:"ced1",xviTet:"9400d3",dAppRk:"ff1493",dApskyXe:"bfff",dimWay:"696969",dimgYy:"696969",dodgerXe:"1e90ff",fiYbrick:"b22222",flSOwEte:"fffaf0",foYstWAn:"228b22",fuKsia:"ff00ff",gaRsbSo:"dcdcdc",ghostwEte:"f8f8ff",gTd:"ffd700",gTMnPd:"daa520",Way:"808080",gYF:"8000",gYFLw:"adff2f",gYy:"808080",honeyMw:"f0fff0",hotpRk:"ff69b4",RdianYd:"cd5c5c",Rdigo:"4b0082",ivSy:"fffff0",khaki:"f0e68c",lavFMr:"e6e6fa",lavFMrXsh:"fff0f5",lawngYF:"7cfc00",NmoncEffon:"fffacd",ZXe:"add8e6",ZcSO:"f08080",Zcyan:"e0ffff",ZgTMnPdLw:"fafad2",ZWay:"d3d3d3",ZgYF:"90ee90",ZgYy:"d3d3d3",ZpRk:"ffb6c1",ZsOmon:"ffa07a",ZsHgYF:"20b2aa",ZskyXe:"87cefa",ZUWay:"778899",ZUgYy:"778899",ZstAlXe:"b0c4de",ZLw:"ffffe0",lime:"ff00",limegYF:"32cd32",lRF:"faf0e6",magFta:"ff00ff",maPon:"800000",VaquamarRe:"66cdaa",VXe:"cd",VScEd:"ba55d3",VpurpN:"9370db",VsHgYF:"3cb371",VUXe:"7b68ee",VsprRggYF:"fa9a",VQe:"48d1cc",VviTetYd:"c71585",midnightXe:"191970",mRtcYam:"f5fffa",mistyPse:"ffe4e1",moccasR:"ffe4b5",navajowEte:"ffdead",navy:"80",Tdlace:"fdf5e6",Tive:"808000",TivedBb:"6b8e23",Sange:"ffa500",SangeYd:"ff4500",ScEd:"da70d6",pOegTMnPd:"eee8aa",pOegYF:"98fb98",pOeQe:"afeeee",pOeviTetYd:"db7093",papayawEp:"ffefd5",pHKpuff:"ffdab9",peru:"cd853f",pRk:"ffc0cb",plum:"dda0dd",powMrXe:"b0e0e6",purpN:"800080",YbeccapurpN:"663399",Yd:"ff0000",Psybrown:"bc8f8f",PyOXe:"4169e1",saddNbPwn:"8b4513",sOmon:"fa8072",sandybPwn:"f4a460",sHgYF:"2e8b57",sHshell:"fff5ee",siFna:"a0522d",silver:"c0c0c0",skyXe:"87ceeb",UXe:"6a5acd",UWay:"708090",UgYy:"708090",snow:"fffafa",sprRggYF:"ff7f",stAlXe:"4682b4",tan:"d2b48c",teO:"8080",tEstN:"d8bfd8",tomato:"ff6347",Qe:"40e0d0",viTet:"ee82ee",JHt:"f5deb3",wEte:"ffffff",wEtesmoke:"f5f5f5",Lw:"ffff00",LwgYF:"9acd32"};function hre(){const e={},t=Object.keys(CM),n=Object.keys(xM);let r,o,s,i,l;for(r=0;r<t.length;r++){for(i=l=t[r]Line truncated
* Chart.js v4.5.1
* https://www.chartjs.org
* (c) 2025 Chart.js Contributors
* Released under the MIT License
*/function vs(){}const xre=(()=>{let e=0;return()=>e++})();function kt(e){return e==null}function On(e){if(Array.isArray&&Array.isArray(e))return!0;const t=Object.prototype.toString.call(e);return t.slice(0,7)==="[object"&&t.slice(-6)==="Array]"}function pt(e){return e!==null&&Object.prototype.toString.call(e)==="[object Object]"}function po(e){return(typeof e=="number"||e instanceof Number)&&isFinite(+e)}function Wo(e,t){return po(e)?e:t}function st(e,t){return typeof e>"u"?t:e}const Cre=(e,t)=>typeof e=="string"&&e.endsWith("%")?parseFloat(e)/100:+e/t,v$=(e,t)=>typeof e=="string"&&e.endsWith("%")?parseFloat(e)/100*t:+e;function Nt(e,t,n){if(e&&typeof e.call=="function")return e.apply(n,t)}function Mt(e,t,n,r){let o,s,i;if(On(e))for(s=e.length,o=0;o<s;o++)t.call(n,e[o],o);else if(pt(e))for(i=Object.keys(e),s=i.length,o=0;o<s;o++)t.call(n,e[i[o]],i[o])}function Fg(e,t){let n,r,o,s;if(!e||!t||e.length!==t.length)return!1;for(n=0,r=e.length;n<r;++n)if(o=e[n],s=t[n],o.datasetIndex!==s.datasetIndex||o.index!==s.index)return!1;return!0}function Lg(e){if(On(e))return e.map(Lg);if(pt(e)){const t=Object.create(null),n=Object.keys(e),r=n.length;let o=0;for(;o<r;++o)t[n[o]]=Lg(e[n[o]]);return t}return e}function y$(e){return["__proto__","prototype","constructor"].indexOf(e)===-1}function wre(e,t,n,r){if(!y$(e))return;const o=t[e],s=n[e];pt(o)&&pt(s)?mf(o,s,r):t[e]=Lg(s)}function mf(e,t,n){const r=On(t)?t:[t],o=r.length;if(!pt(e))return e;n=n||{};const s=n.merger||wre;let i;for(let l=0;l<o;++l){if(i=r[l],!pt(i))continue;const a=Object.keys(i);for(let c=0,u=a.length;c<u;++c)s(a[c],e,i,n)}return e}function Id(e,t){return mf(e,t,{merger:Sre})}function Sre(e,t,n){if(!y$(e))return;const r=t[e],o=n[e];pt(r)&&pt(o)?Id(r,o):Object.prototype.hasOwnProperty.call(t,e)||(t[e]=Lg(o))}const SM={"":e=>e,x:e=>e.x,y:e=>e.y};function kre(e){const t=e.split("."),n=[];let r="";for(const o of t)r+=o,r.endsWith("\\")?r=r.slice(0,-1)+".":(n.push(r),r="");return n}function Pre(e){const t=kre(e);return n=>{for(const r of t){if(r==="")break;n=n&&n[r]}return n}}function Jl(e,t){return(SM[t]||(SM[t]=Pre(t)))(e)}function Pw(e){return e.charAt(0).toUpperCase()+e.slice(1)}const bf=e=>typeof e<"u",Qi=e=>typeof e=="function",kM=(e,t)=>{if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0};function Mre(e){return e.type==="mouseup"||e.type==="click"||e.type==="contextmenu"}const $t=Math.PI,on=2*$t,Ire=on+$t,Dg=Number.POSITIVE_INFINITY,Ere=$t/180,Pn=$t/2,il=$t/4,PM=$t*2/3,x$=Math.log10,as=Math.sign;function Ed(e,t,n){return Math.abs(e-t)<n}function MM(e){const t=Math.round(e);e=Ed(e,t,e/1e3)?t:e;const n=Math.pow(10,Math.floor(x$(e))),r=e/n;return(r<=1?1:r<=2?2:r<=5?5:10)*n}function _re(e){const t=[],n=Math.sqrt(e);let r;for(r=1;r<n;r++)e%r===0&&(t.push(r),t.push(e/r));return n===(n|0)&&t.push(n),t.sort((o,s)=>o-s).pop(),t}function Tre(e){return typeof e=="symbol"||typeof e=="object"&&e!==null&&!(Symbol.toPrimitive in e||"toString"in e||"valueOf"in e)}function vf(e){return!Tre(e)&&!isNaN(parseFloat(e))&&isFinite(e)}function Rre(e,t){const n=Math.round(e);return n-t<=e&&n+t>=e}function Ore(e,t,n){let r,o,s;for(r=0,o=e.length;r<o;r++)s=e[r][n],isNaN(s)||(t.min=Math.min(t.min,s),t.max=Math.max(t.max,s))}function Rs(e){return e*($t/180)}function $re(e){return e*(180/$t)}function IM(e){if(!po(e))return;let t=1,n=0;for(;Math.round(e*t)/t!==e;)t*=10,n++;return n}function C$(e,t){const n=t.x-e.x,r=t.y-e.y,o=Math.sqrt(n*n+r*r);let s=Math.atan2(r,n);return s<-.5*$t&&(s+=on),{angle:s,distance:o}}function Ix(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}function Fre(e,t){return(e-t+Ire)%on-$t}function Io(e){return(e%on+on)%on}function yf(e,t,n,r){const o=Io(e),s=Io(t),i=Io(n),l=Io(s-o),a=Io(i-o),c=Io(o-s),u=Io(o-i);return o===s||o===i||r&&s===i||l>a&&c<u}function qn(e,t,n){return Math.max(t,Math.min(n,e))}function Lre(e){return qn(e,-32768,32767)}function Ii(e,t,n,r=1e-6){return e>=Math.min(t,n)-r&&e<=Math.max(t,n)+r}function Mw(e,t,n){n=n||(i=>e[i]<t);let r=e.length-1,o=0,s;for(;r-o>1;)s=o+r>>1,n(s)?o=s:r=s;return{lo:o,hi:r}}const kl=(e,t,n,r)=>Mw(e,n,r?o=>{const s=e[o][t];return s<n||s===n&&e[o+1][t]===n}:o=>e[o][t]<n),Dre=(e,t,n)=>Mw(e,n,r=>e[r][t]>=n);function Are(e,t,n){let r=0,o=e.length;for(;r<o&&e[r]<t;)r++;for(;o>r&&e[o-1]>n;)o--;return r>0||o<e.length?e.slice(r,o):e}const w$=["push","pop","shift","splice","unshift"];function jre(e,t){if(e._chartjs){e._chartjs.listeners.push(t);return}Object.defineProperty(e,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[t]}}),w$.forEach(n=>{const r="_onData"+Pw(n),o=e[n];Object.defineProperty(e,n,{configurable:!0,enumerable:!1,value(...s){const i=o.apply(this,s);return e._chartjs.listeners.forEach(l=>{typeof l[r]=="function"&&l[r](...s)}),i}})})}function EM(e,t){const n=e._chartjs;if(!n)return;const r=n.listeners,o=r.indexOf(t);o!==-1&&r.splice(o,1),!(r.length>0)&&(w$.forEach(s=>{delete e[s]}),delete e._chartjs)}function S$(e){const t=new Set(e);return t.size===e.lengtLine truncated
* Chart.js v4.5.1
* https://www.chartjs.org
* (c) 2025 Chart.js Contributors
* Released under the MIT License
*/class Uoe{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,n,r,o){const s=n.listeners[o],i=n.duration;s.forEach(l=>l({chart:t,initial:n.initial,numSteps:i,currentStep:Math.min(r-n.start,i)}))}_refresh(){this._request||(this._running=!0,this._request=k$.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(t=Date.now()){let n=0;this._charts.forEach((r,o)=>{if(!r.running||!r.items.length)return;const s=r.items;let i=s.length-1,l=!1,a;for(;i>=0;--i)a=s[i],a._active?(a._total>r.duration&&(r.duration=a._total),a.tick(t),l=!0):(s[i]=s[s.length-1],s.pop());l&&(o.draw(),this._notify(o,r,t,"progress")),s.length||(r.running=!1,this._notify(o,r,t,"complete"),r.initial=!1),n+=s.length}),this._lastDate=t,n===0&&(this._running=!1)}_getAnims(t){const n=this._charts;let r=n.get(t);return r||(r={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},n.set(t,r)),r}listen(t,n,r){this._getAnims(t).listeners[n].push(r)}add(t,n){!n||!n.length||this._getAnims(t).items.push(...n)}has(t){return this._getAnims(t).items.length>0}start(t){const n=this._charts.get(t);n&&(n.running=!0,n.start=Date.now(),n.duration=n.items.reduce((r,o)=>Math.max(r,o._duration),0),this._refresh())}running(t){if(!this._running)return!1;const n=this._charts.get(t);return!(!n||!n.running||!n.items.length)}stop(t){const n=this._charts.get(t);if(!n||!n.items.length)return;const r=n.items;let o=r.length-1;for(;o>=0;--o)r[o].cancel();n.items=[],this._notify(t,n,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}var Cs=new Uoe;const BM="transparent",Koe={boolean(e,t,n){return n>.5?t:e},color(e,t,n){const r=RM(e||BM),o=r.valid&&RM(t||BM);return o&&o.valid?o.mix(r,n).hexString():t},number(e,t,n){return e+(t-e)*n}};class qoe{constructor(t,n,r,o){const s=n[r];o=zh([t.to,o,s,t.from]);const i=zh([t.from,s,o]);this._active=!0,this._fn=t.fn||Koe[t.type||typeof i],this._easing=_d[t.easing]||_d.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=n,this._prop=r,this._from=i,this._to=o,this._promises=void 0}active(){return this._active}update(t,n,r){if(this._active){this._notify(!1);const o=this._target[this._prop],s=r-this._start,i=this._duration-s;this._start=r,this._duration=Math.floor(Math.max(i,t.duration)),this._total+=s,this._loop=!!t.loop,this._to=zh([t.to,n,o,t.from]),this._from=zh([t.from,o,n])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const n=t-this._start,r=this._duration,o=this._prop,s=this._from,i=this._loop,l=this._to;let a;if(this._active=s!==l&&(i||n<r),!this._active){this._target[o]=l,this._notify(!0);return}if(n<0){this._target[o]=s;return}a=n/r%2,a=i&&a>1?2-a:a,a=this._easing(Math.min(1,Math.max(0,a))),this._target[o]=this._fn(s,l,a)}wait(){const t=this._promises||(this._promises=[]);return new Promise((n,r)=>{t.push({res:n,rej:r})})}_notify(t){const n=t?"res":"rej",r=this._promises||[];for(let o=0;o<r.length;o++)r[o][n]()}}class j${constructor(t,n){this._chart=t,this._properties=new Map,this.configure(n)}configure(t){if(!pt(t))return;const n=Object.keys(un.animation),r=this._properties;Object.getOwnPropertyNames(t).forEach(o=>{const s=t[o];if(!pt(s))return;const i={};for(const l of n)i[l]=s[l];(On(s.properties)&&s.properties||[o]).forEach(l=>{(l===o||!r.has(l))&&r.set(l,i)})})}_animateOptions(t,n){const r=n.options,o=Yoe(t,r);if(!o)return[];const s=this._createAnimations(o,r);return r.$shared&&Xoe(t.options.$animations,r).then(()=>{t.options=r},()=>{}),s}_createAnimations(t,n){const r=this._properties,o=[],s=t.$animations||(t.$animations={}),i=Object.keys(n),l=Date.now();let a;for(a=i.length-1;a>=0;--a){const c=i[a];if(c.charAt(0)==="$")continue;if(c==="options"){o.push(...this._animateOptions(t,n));continue}const u=n[c];let d=s[c];const f=r.get(c);if(d)if(f&&d.active()){d.update(f,u,l);continue}else d.cancel();if(!f||!f.duration){t[c]=u;continue}s[c]=d=new qoe(f,t,c,u),o.push(d)}return o}update(t,n){if(this._properties.size===0){Object.assign(t,n);return}const r=this._createAnimations(t,n);if(r.length)return Cs.add(this._chart,r),!0}}function Xoe(e,t){const n=[],r=Object.keys(t);for(let o=0;o<r.length;o++){const s=e[r[o]];s&&s.active()&&n.push(s.wait())}return Promise.all(n)}function Yoe(e,t){if(!t)return;let n=e.options;if(!n){e.options=t;return}return n.$shared&&(e.options=n=Object.assign({},n,{$shared:!1,$animations:{}})),n}function VM(e,t){const n=e&&e.options||{},r=n.reverse,o=n.min===void 0?t:0,s=n.max===void 0?t:0;return{start:r?s:o,end:r?o:s}}function Qoe(e,t,n){if(n===!1)return!1;const r=VM(e,n),o=VM(t,n);return{top:o.end,right:r.end,bottom:o.start,left:r.start}}function Zoe(e){let t,n,r,o;return pt(e)?(t=e.top,n=e.right,r=e.bottom,o=e.left):t=n=r=o=e,{top:t,right:n,bottom:r,left:o,disabled:e===!1}}function z$(e,t){const n=[],r=e._getSortedDatasetMetas(t);let o,s;for(o=0,s=r.length;o<s;++o)n.pLine truncated
`)>-1?e.split(`
`):e}function Qie(e,t){const{element:n,datasetIndex:r,index:o}=t,s=e.getDatasetMeta(r).controller,{label:i,value:l}=s.getLabelAndValue(o);return{chart:e,label:i,parsed:s.getParsed(o),raw:e.data.datasets[r].data[o],formattedValue:l,dataset:s.getDataset(),dataIndex:o,datasetIndex:r,element:n}}function yI(e,t){const n=e.chart.ctx,{body:r,footer:o,title:s}=e,{boxWidth:i,boxHeight:l}=t,a=mr(t.bodyFont),c=mr(t.titleFont),u=mr(t.footerFont),d=s.length,f=o.length,h=r.length,g=Ao(t.padding);let m=g.height,C=0,b=r.reduce((S,k)=>S+k.before.length+k.lines.length+k.after.length,0);if(b+=e.beforeBody.length+e.afterBody.length,d&&(m+=d*c.lineHeight+(d-1)*t.titleSpacing+t.titleMarginBottom),b){const S=t.displayColors?Math.max(l,a.lineHeight):a.lineHeight;m+=h*S+(b-h)*a.lineHeight+(b-1)*t.bodySpacing}f&&(m+=t.footerMarginTop+f*u.lineHeight+(f-1)*t.footerSpacing);let y=0;const w=function(S){C=Math.max(C,n.measureText(S).width+y)};return n.save(),n.font=c.string,Mt(e.title,w),n.font=a.string,Mt(e.beforeBody.concat(e.afterBody),w),y=t.displayColors?i+2+t.boxPadding:0,Mt(r,S=>{Mt(S.before,w),Mt(S.lines,w),Mt(S.after,w)}),y=0,n.font=u.string,Mt(e.footer,w),n.restore(),C+=g.width,{width:C,height:m}}function Zie(e,t){const{y:n,height:r}=t;return n<r/2?"top":n>e.height-r/2?"bottom":"center"}function Jie(e,t,n,r){const{x:o,width:s}=r,i=n.caretSize+n.caretPadding;if(e==="left"&&o+s+i>t.width||e==="right"&&o-s-i<0)return!0}function ele(e,t,n,r){const{x:o,width:s}=n,{width:i,chartArea:{left:l,right:a}}=e;let c="center";return r==="center"?c=o<=(l+a)/2?"left":"right":o<=s/2?c="left":o>=i-s/2&&(c="right"),Jie(c,e,t,n)&&(c="center"),c}function xI(e,t,n){const r=n.yAlign||t.yAlign||Zie(e,n);return{xAlign:n.xAlign||t.xAlign||ele(e,t,n,r),yAlign:r}}function tle(e,t){let{x:n,width:r}=e;return t==="right"?n-=r:t==="center"&&(n-=r/2),n}function nle(e,t,n){let{y:r,height:o}=e;return t==="top"?r+=n:t==="bottom"?r-=o+n:r-=o/2,r}function CI(e,t,n,r){const{caretSize:o,caretPadding:s,cornerRadius:i}=e,{xAlign:l,yAlign:a}=n,c=o+s,{topLeft:u,topRight:d,bottomLeft:f,bottomRight:h}=rc(i);let g=tle(t,l);const m=nle(t,a,c);return a==="center"?l==="left"?g+=c:l==="right"&&(g-=c):l==="left"?g-=Math.max(u,f)+o:l==="right"&&(g+=Math.max(d,h)+o),{x:qn(g,0,r.width-t.width),y:qn(m,0,r.height-t.height)}}function Uh(e,t,n){const r=Ao(n.padding);return t==="center"?e.x+e.width/2:t==="right"?e.x+e.width-r.right:e.x+r.left}function wI(e){return Uo([],ws(e))}function rle(e,t,n){return aa(e,{tooltip:t,tooltipItems:n,type:"tooltip"})}function SI(e,t){const n=t&&t.dataset&&t.dataset.tooltip&&t.dataset.tooltip.callbacks;return n?e.override(n):e}const eF={beforeTitle:vs,title(e){if(e.length>0){const t=e[0],n=t.chart.data.labels,r=n?n.length:0;if(this&&this.options&&this.options.mode==="dataset")return t.dataset.label||"";if(t.label)return t.label;if(r>0&&t.dataIndex<r)return n[t.dataIndex]}return""},afterTitle:vs,beforeBody:vs,beforeLabel:vs,label(e){if(this&&this.options&&this.options.mode==="dataset")return e.label+": "+e.formattedValue||e.formattedValue;let t=e.dataset.label||"";t&&(t+=": ");const n=e.formattedValue;return kt(n)||(t+=n),t},labelColor(e){const n=e.chart.getDatasetMeta(e.datasetIndex).controller.getStyle(e.dataIndex);return{borderColor:n.borderColor,backgroundColor:n.backgroundColor,borderWidth:n.borderWidth,borderDash:n.borderDash,borderDashOffset:n.borderDashOffset,borderRadius:0}},labelTextColor(){return this.options.bodyColor},labelPointStyle(e){const n=e.chart.getDatasetMeta(e.datasetIndex).controller.getStyle(e.dataIndex);return{pointStyle:n.pointStyle,rotation:n.rotation}},afterLabel:vs,afterBody:vs,beforeFooter:vs,footer:vs,afterFooter:vs};function sr(e,t,n,r){const o=e[t].call(n,r);return typeof o>"u"?eF[t].call(n,r):o}class Fx extends sl{constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const n=this.chart,r=this.options.setContext(this.getContext()),o=r.enabled&&n.options.animation&&r.animations,s=new j$(this.chart,o);return o._cacheable&&(this._cachedAnimations=Object.freeze(s)),s}getContext(){return this.$context||(this.$context=rle(this.chart.getContext(),this,this._tooltipItems))}getTitle(t,n){const{callbacks:r}=n,o=sr(r,"beforeTitle",this,t),s=sr(r,"title",this,t),i=sr(r,"afterTitle",this,t);let l=[];return l=Uo(l,ws(o)),l=Uo(l,ws(s)),l=Uo(l,ws(i)),l}getBeforeBody(t,n){return Line truncated
https://github.com/highlightjs/highlight.js/issues/2277`),z=_,j=O),F===void 0&&(F=!0);const H={code:j,language:z};A("before:highlight",H);const B=H.result?H.result:d(H.language,H.code,F);return B.code=H.code,A("after:highlight",B),B}function d(_,O,F,j){const z=Object.create(null);function H(ie,be){return ie.keywords[be]}function B(){if(!ne.keywords){_e.addText(Pe);return}let ie=0;ne.keywordPatternRe.lastIndex=0;let be=ne.keywordPatternRe.exec(Pe),ue="";for(;be;){ue+=Pe.substring(ie,be.index);const Y=ae.case_insensitive?be[0].toLowerCase():be[0],xe=H(ne,Y);if(xe){const[Re,Ze]=xe;if(_e.addText(ue),ue="",z[Y]=(z[Y]||0)+1,z[Y]<=kae&&(He+=Ze),Re.startsWith("_"))ue+=be[0];else{const Me=ae.classNameAliases[Re]||Re;Z(be[0],Me)}}else ue+=be[0];ie=ne.keywordPatternRe.lastIndex,be=ne.keywordPatternRe.exec(Pe)}ue+=Pe.substring(ie),_e.addText(ue)}function G(){if(Pe==="")return;let ie=null;if(typeof ne.subLanguage=="string"){if(!t[ne.subLanguage]){_e.addText(Pe);return}ie=d(ne.subLanguage,Pe,!0,Oe[ne.subLanguage]),Oe[ne.subLanguage]=ie._top}else ie=h(Pe,ne.subLanguage.length?ne.subLanguage:null);ne.relevance>0&&(He+=ie.relevance),_e.__addSublanguage(ie._emitter,ie.language)}function V(){ne.subLanguage!=null?G():B(),Pe=""}function Z(ie,be){ie!==""&&(_e.startScope(be),_e.addText(ie),_e.endScope())}function Q(ie,be){let ue=1;const Y=be.length-1;for(;ue<=Y;){if(!ie._emit[ue]){ue++;continue}const xe=ae.classNameAliases[ie[ue]]||ie[ue],Re=be[ue];xe?Z(Re,xe):(Pe=Re,B(),Pe=""),ue++}}function U(ie,be){return ie.scope&&typeof ie.scope=="string"&&_e.openNode(ae.classNameAliases[ie.scope]||ie.scope),ie.beginScope&&(ie.beginScope._wrap?(Z(Pe,ae.classNameAliases[ie.beginScope._wrap]||ie.beginScope._wrap),Pe=""):ie.beginScope._multi&&(Q(ie.beginScope,be),Pe="")),ne=Object.create(ie,{parent:{value:ne}}),ne}function K(ie,be,ue){let Y=Nle(ie.endRe,ue);if(Y){if(ie["on:end"]){const xe=new $I(ie);ie["on:end"](be,xe),xe.isMatchIgnored&&(Y=!1)}if(Y){for(;ie.endsParent&&ie.parent;)ie=ie.parent;return ie}}if(ie.endsWithParent)return K(ie.parent,be,ue)}function ee(ie){return ne.matcher.regexIndex===0?(Pe+=ie[0],1):(Ae=!0,0)}function de(ie){const be=ie[0],ue=ie.rule,Y=new $I(ue),xe=[ue.__beforeBegin,ue["on:begin"]];for(const Re of xe)if(Re&&(Re(ie,Y),Y.isMatchIgnored))return ee(be);return ue.skip?Pe+=be:(ue.excludeBegin&&(Pe+=be),V(),!ue.returnBegin&&!ue.excludeBegin&&(Pe=be)),U(ue,ie),ue.returnBegin?0:be.length}function se(ie){const be=ie[0],ue=O.substring(ie.index),Y=K(ne,ie,ue);if(!Y)return zI;const xe=ne;ne.endScope&&ne.endScope._wrap?(V(),Z(be,ne.endScope._wrap)):ne.endScope&&ne.endScope._multi?(V(),Q(ne.endScope,ie)):xe.skip?Pe+=be:(xe.returnEnd||xe.excludeEnd||(Pe+=be),V(),xe.excludeEnd&&(Pe=be));do ne.scope&&_e.closeNode(),!ne.skip&&!ne.subLanguage&&(He+=ne.relevance),ne=ne.parent;while(ne!==Y.parent);return Y.starts&&U(Y.starts,ie),xe.returnEnd?0:be.length}function ge(){const ie=[];for(let be=ne;be!==ae;be=be.parent)be.scope&&ie.unshift(be.scope);ie.forEach(be=>_e.openNode(be))}let q={};function me(ie,be){const ue=be&&be[0];if(Pe+=ie,ue==null)return V(),0;if(q.type==="begin"&&be.type==="end"&&q.index===be.index&&ue===""){if(Pe+=O.slice(be.index,be.index+1),!o){const Y=new Error(`0 width match regex (${_})`);throw Y.languageName=_,Y.badRule=q.rule,Y}return 1}if(q=be,be.type==="begin")return de(be);if(be.type==="illegal"&&!F){const Y=new Error('Illegal lexeme "'+ue+'" for mode "'+(ne.scope||"<unnamed>")+'"');throw Y.mode=ne,Y}else if(be.type==="end"){const Y=se(be);if(Y!==zI)return Y}if(be.type==="illegal"&&ue==="")return Pe+=`
`,1;if(we>1e5&&we>be.index*3)throw new Error("potential infinite loop, way more iterations than matches");return Pe+=ue,ue.length}const ae=I(_);if(!ae)throw Bl(s.replace("{}",_)),new Error('Unknown language: "'+_+'"');const ce=xae(ae);let ye="",ne=j||ce;const Oe={},_e=new l.__emitter(l);ge();let Pe="",He=0,De=0,we=0,Ae=!1;try{if(ae.__emitTokens)ae.__emitTokens(O,_e);else{for(ne.matcher.considerAll();;){we++,Ae?Ae=!1:ne.matcher.considerAll(),ne.matcher.lastIndex=De;const ie=ne.matcher.exec(O);if(!ie)break;const be=O.substring(De,ie.index),ue=me(be,ie);De=ie.index+ue}me(O.substring(De))}return _e.finalize(),ye=_e.toHTML(),{language:_,value:ye,relevance:He,illegal:!1,_emitter:_e,_top:ne}}catch(ie){if(ie.message&&ie.message.includes("Illegal"))return{language:_,value:Vv(O),illegal:!0,relevance:0,_illegalBy:{message:ie.message,index:De,context:O.slice(De-100,De+100),mode:ie.mode,resultSoFar:ye},_emitter:_e};if(o)return{language:_,value:Vv(O),illegal:!1,relevance:0,errorRaised:ie,_emitter:_e,_top:ne};throw ie}}function f(_){const O={value:Vv(_),illegal:!1,relevance:0,_top:i,_emitter:new l.__emitter(l)};return O._emitter.addText(_),O}function h(_,O){O=O||l.languages||Object.keys(t);const F=f(_),j=O.filter(I).filter(T).map(V=>d(V,_,!1));j.unshift(F);const z=j.sort((V,Z)=>{if(V.relevance!==Z.relevance)return Z.relevance-V.relevance;if(V.language&&Z.language){if(I(V.language).supersetOf===Z.language)return 1;if(I(Z.language).supersetOf===V.language)return-1}return 0}),[H,B]=z,G=H;return G.secondBest=B,G}function g(_,O,F){const j=O&&n[O]||F;_.classList.add("hljs"),_.classList.add(`language-${j}`)}function m(_){let O=null;const F=c(_);if(a(F))return;if(A("before:highlightElement",{el:_,language:F}),_.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",_);return}if(_.children.length>0&&(l.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(_)),l.throwUnescapedHTML))throw new Sae("One of your code blocks includes unescaped HTML.",_.innerHTML);O=_;const j=O.textContent,z=F?u(j,{language:F,ignoreIllegals:!0}):h(j);_.innerHTML=z.value,_.dataset.highlighted="yes",g(_,F,z.language),_.result={language:z.language,re:z.relevance,relevance:z.relevance},z.secondBest&&(_.secondBest={language:z.secondBest.language,relevance:z.secondBest.relevance}),A("after:highlightElement",{el:_,result:z,text:j})}function C(_){l=jI(l,_)}const b=()=>{S(),Pa("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function y(){S(),Pa("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let w=!1;function S(){function _(){S()}if(document.readyState==="loading"){w||window.addEventListener("DOMContentLoaded",_,!1),w=!0;return}document.querySelectorAll(l.cssSelector).forEach(m)}function k(_,O){let F=null;try{F=O(e)}catch(j){if(Bl("Language definition for '{}' could not be registered.".replace("{}",_)),o)Bl(j);else throw j;F=i}F.name||(F.name=_),t[_]=F,F.rawDefinition=O.bind(null,e),F.aliases&&E(F.aliases,{languageName:_})}function P(_){delete t[_];for(const O of Object.keys(n))n[O]===_&&delete n[O]}function M(){return Object.keys(t)}function I(_){return _=(_||"").toLowerCase(),t[_]||t[n[_]]}function E(_,{languageName:O}){typeof _=="string"&&(_=[_]),_.forEach(F=>{n[F.toLowerCase()]=O})}function T(_){const O=I(_);return O&&!O.disableAutodetect}function D(_){_["before:highlightBlock"]&&!_["before:highlightElement"]&&(_["before:highlightElement"]=O=>{_["before:highlightBlock"](Object.assign({block:O.el},O))}),_["after:highlightBlock"]&&!_["after:highlightElement"]&&(_["after:highlightElement"]=O=>{_["after:highlightBlock"](Object.assign({block:O.el},O))})}function $(_){D(_),r.push(_)}function L(_){const O=r.indexOf(_);O!==-1&&r.splice(O,1)}function A(_,O){const F=_;r.forEach(function(j){j[F]&&j[F](O)})}function R(_){return Pa("10.7.0","highlightBlock will be removed entirely in v12.0"),Pa("10.7.0","Please use highlightElement now."),m(_)}Object.assign(e,{highlight:u,highlightAuto:h,highlightAll:S,highlightElement:m,highlightBlock:R,configure:C,initHighlighting:b,initHighlightingOnLoad:y,registerLanguage:k,unregisterLanguage:P,listLanguages:M,getLanguage:I,registerAliases:E,autoDetection:T,inherit:jI,addPlugin:$,removePlugin:L}),e.debugMode=function(){o=!1},e.safeMode=function(){o=!0},e.versionString=wae,e.regex={concat:ca,lookahead:cF,either:Gw,optional:jle,anyNumberOfTimes:Ale};for(const _ in qh)typeof qh[_]=="object"&&lF(qh[_]);return Object.assign(e,qh),e},Bc=vF({});Bc.newInstance=()=>vF({});var Pae=Bc;Bc.HighlightJS=Bc;Bc.default=Bc;const Pb=Ug(Pae);function Mae(e){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}Pb.registerLanguage("plaintext",Mae);function NI(e,t){return e.filter(t||Boolean).map(n=>`[${new Date(n.creaLine truncated
`)}function Iae({packageBase:e,repo:t,refetchInterval:n}){const[r,o]=p.useState(0),[s,i]=p.useState(null),l=p.useRef(null),a=p.useRef(null),c=p.useRef(!1),{data:u}=oo({queryKey:sn.logs(e,t),queryFn:()=>At.fetchLogs(e,t),enabled:!!e}),d=p.useMemo(()=>{if(!u||u.length===0)return[];const b={};for(const y of u){const w=`${y.version}-${y.process_id}`;b[w]?b[w].minCreated=Math.min(b[w].minCreated,y.created):b[w]={...y,minCreated:y.created}}return Object.values(b).sort((y,w)=>w.minCreated-y.minCreated).map(y=>({version:y.version,processId:y.process_id,created:y.minCreated,logs:NI(u,w=>w.version===y.version&&w.process_id===y.process_id)}))},[u]),[f,h]=p.useState(u);u!==f&&(h(u),o(0),c.current=!1);const g=d[r],{data:m}=oo({queryKey:g?sn.logsVersion(e,t,g.version,g.processId):["logs-none"],queryFn:()=>g?At.fetchLogs(e,t,g.version,g.processId):Promise.resolve([]),enabled:!!g&&!!n,refetchInterval:n}),C=p.useMemo(()=>m&&m.length>0?NI(m):(g==null?void 0:g.logs)??"",[m,g]);return p.useEffect(()=>{l.current&&C&&(l.current.textContent=C,delete l.current.dataset.highlighted,Pb.highlightElement(l.current))},[C]),p.useEffect(()=>{if(a.current&&C){const b=a.current;c.current?b.scrollTop+b.clientHeight>=b.scrollHeight-50&&(b.scrollTop=b.scrollHeight):(b.scrollTop=b.scrollHeight,c.current=!0)}},[C]),v.jsxs(Tt,{sx:{display:"flex",gap:1,mt:1},children:[v.jsxs(Tt,{children:[v.jsx(Sn,{size:"small",startIcon:v.jsx(iF,{}),onClick:b=>i(b.currentTarget)}),v.jsxs(eb,{anchorEl:s,open:!!s,onClose:()=>i(null),children:[d.map((b,y)=>v.jsx(cn,{selected:y===r,onClick:()=>{o(y),i(null),c.current=!1},children:v.jsx(ot,{variant:"body2",children:xu(b.created)})},`${b.version}-${b.processId}`)),d.length===0&&v.jsx(cn,{disabled:!0,children:"No logs available"})]})]}),v.jsxs(Tt,{sx:{flex:1,position:"relative"},children:[v.jsx(Tt,{ref:a,component:"pre",sx:{backgroundColor:"#f6f8fa",p:2,borderRadius:1,overflow:"auto",maxHeight:400,fontSize:"0.8rem",fontFamily:"monospace"},children:v.jsx("code",{ref:l,className:"language-plaintext"})}),v.jsx(Tt,{sx:{position:"absolute",top:8,right:8},children:v.jsx(Bw,{getText:()=>C})})]})]})}function Eae(e){const t=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:t.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:t.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}}Pb.registerLanguage("diff",Eae);function _ae({packageBase:e,repo:t}){const n=p.useRef(null),{data:r}=oo({queryKey:sn.changes(e,t),queryFn:()=>At.fetchChanges(e,t),enabled:!!e}),o=(r==null?void 0:r.changes)??"";return p.useEffect(()=>{n.current&&(n.current.textContent=o,delete n.current.dataset.highlighted,Pb.highlightElement(n.current))},[o]),v.jsxs(Tt,{sx:{position:"relative",mt:1},children:[v.jsx(Tt,{component:"pre",sx:{backgroundColor:"#f6f8fa",p:2,borderRadius:1,overflow:"auto",maxHeight:400,fontSize:"0.8rem",fontFamily:"monospace"},children:v.jsx("code",{ref:n,className:"language-diff"})}),v.jsx(Tt,{sx:{position:"absolute",top:8,right:8},children:v.jsx(Bw,{getText:()=>o})})]})}yu.register(Bg,Vg,Mp,cd,zw,jw);function Tae({events:e}){const t=e.filter(r=>{var o;return r.event==="package-updated"&&((o=r.data)==null?void 0:o.took)});if(t.length===0)return null;const n={labels:t.map(r=>xu(r.created)),datasets:[{label:"update duration, s",data:t.map(r=>r.data.took),cubicInterpolationMode:"monotone",tension:.4}]};return v.jsx(mle,{data:n,options:{responsive:!0}})}const Rae=[{field:"timestamp",headerName:"date",width:180,align:"right",headerAlign:"right"},{field:"event",headerName:"event",flex:1},{field:"message",headerName:"description",flex:2}];function Oae({packageBase:e,repo:t}){const{data:n=[]}=oo({queryKey:sn.events(t,e),queryFn:()=>At.fetchEvents(t,e,30),enabled:!!e}),r=n.map((o,s)=>({id:s,timestamp:xu(o.created),event:o.event,message:o.message??""}));return v.jsxs(Tt,{sx:{mt:1},children:[v.jsx(Tae,{events:n}),v.jsx(i$,{rows:r,columns:Rae,density:"compact",initialState:{sorting:{sortModel:[{field:"timestamp",sort:"desc"}]}},pageSizeOptions:[10,25],sx:{height:300,mt:1},disableRowSelectionOnClick:!0})]})}function Ep(e,t){const[n,r]=p.useState(()=>{try{const s=window.localStorage.getItem(e);return s?JSON.parse(s):t}catch{return t}}),o=p.useCallback(s=>{r(i=>{const l=s instanceof Function?s(i):s;return window.localStorage.setItem(e,JSON.stringify(l)),l})},[e]);return[n,o]}function yF(e,t=0){const[n,r]=Ep(`ahriman-${e}`,{enabled:t>0,interval:t}),[o,s]=p.useState(!1),i=n.enabled&&!o&&n.interval>0?n.interval:!1,l=p.useCallback(c=>{r(u=>({...u,enabled:c}))},[r]),a=p.useCallback(c=>{r({enabled:!0,interval:c})},[r]);return{enabled:n.enabled,interval:n.interval,paused:o,refetchInterval:i,setEnabled:l,setInterval:a,setPaused:s}}function qu(e){const t=[...new Set(e Line truncated
+28
View File
@@ -22,6 +22,22 @@ from ahriman.web.apispec import Schema, fields
from ahriman.web.schemas.repository_id_schema import RepositoryIdSchema from ahriman.web.schemas.repository_id_schema import RepositoryIdSchema
class AutoRefreshIntervalSchema(Schema):
"""
auto refresh interval schema
"""
interval = fields.Integer(required=True, metadata={
"description": "Auto refresh interval in milliseconds",
})
is_active = fields.Boolean(required=True, metadata={
"description": "Whether this interval is the default active one",
})
text = fields.String(required=True, metadata={
"description": "Human readable interval description",
})
class InfoSchema(Schema): class InfoSchema(Schema):
""" """
response service information schema response service information schema
@@ -30,9 +46,21 @@ class InfoSchema(Schema):
auth = fields.Boolean(dump_default=False, required=True, metadata={ auth = fields.Boolean(dump_default=False, required=True, metadata={
"description": "Whether authentication is enabled or not", "description": "Whether authentication is enabled or not",
}) })
autorefresh_intervals = fields.Nested(AutoRefreshIntervalSchema(many=True), dump_default=[], metadata={
"description": "Available auto refresh intervals",
})
docs_enabled = fields.Boolean(dump_default=False, metadata={
"description": "Whether API documentation is enabled",
})
index_url = fields.String(dump_default=None, load_default=None, metadata={
"description": "URL to the repository index page",
})
repositories = fields.Nested(RepositoryIdSchema(many=True), required=True, metadata={ repositories = fields.Nested(RepositoryIdSchema(many=True), required=True, metadata={
"description": "List of loaded repositories", "description": "List of loaded repositories",
}) })
username = fields.String(dump_default=None, load_default=None, metadata={
"description": "Currently authenticated username if any",
})
version = fields.String(required=True, metadata={ version = fields.String(required=True, metadata={
"description": "Service version", "description": "Service version",
"example": __version__, "example": __version__,
+2 -51
View File
@@ -21,10 +21,7 @@ import aiohttp_jinja2
from typing import Any, ClassVar from typing import Any, ClassVar
from ahriman.core.auth.helpers import authorized_userid
from ahriman.core.utils import pretty_interval
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
from ahriman.web.apispec import aiohttp_apispec
from ahriman.web.views.base import BaseView from ahriman.web.views.base import BaseView
@@ -32,23 +29,6 @@ class IndexView(BaseView):
""" """
root view root view
It uses jinja2 templates for report generation, the following variables are allowed:
* auth - authorization descriptor, required
* control - HTML to insert for login control, HTML string, required
* enabled - whether authorization is enabled by configuration or not, boolean, required
* username - authenticated username if any, string, null means not authenticated
* autorefresh_intervals - auto refresh intervals, optional
* interval - auto refresh interval in milliseconds, integer, required
* is_active - is current interval active or not, boolean, required
* text - text representation of the interval (e.g. "30 seconds"), string, required
* docs_enabled - indicates if api docs is enabled, boolean, required
* index_url - url to the repository index, string, optional
* repositories - list of repositories unique identifiers, required
* id - unique repository identifier, string, required
* repository - repository name, string, required
* architecture - repository architecture, string, required
Attributes: Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self GET_PERMISSION(UserAccess): (class attribute) get permissions of self
""" """
@@ -59,38 +39,9 @@ class IndexView(BaseView):
@aiohttp_jinja2.template("build-status.jinja2") @aiohttp_jinja2.template("build-status.jinja2")
async def get(self) -> dict[str, Any]: async def get(self) -> dict[str, Any]:
""" """
process get request. No parameters supported here process get request. Serves the React SPA via jinja2 template
Returns: Returns:
dict[str, Any]: parameters for jinja template dict[str, Any]: parameters for jinja template
""" """
auth_username = await authorized_userid(self.request) return {}
auth = {
"control": self.validator.auth_control,
"enabled": self.validator.enabled,
"username": auth_username,
}
autorefresh_intervals = [
{
"interval": interval * 1000, # milliseconds
"is_active": index == 0, # first element is always default
"text": pretty_interval(interval),
}
for index, interval in enumerate(self.configuration.getintlist("web", "autorefresh_intervals", fallback=[]))
if interval > 0 # special case if 0 exists and first, refresh will not be turned on by default
]
return {
"auth": auth,
"autorefresh_intervals": sorted(autorefresh_intervals, key=lambda interval: interval["interval"]),
"docs_enabled": aiohttp_apispec is not None,
"index_url": self.configuration.get("web", "index_url", fallback=None),
"repositories": [
{
"id": repository.id,
**repository.view(),
}
for repository in sorted(self.services)
]
}
+23 -1
View File
@@ -18,10 +18,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from aiohttp.web import Response, json_response from aiohttp.web import Response, json_response
from typing import ClassVar from collections.abc import Callable
from typing import Any, ClassVar
from ahriman import __version__ from ahriman import __version__
from ahriman.core.auth.helpers import authorized_userid
from ahriman.core.types import Comparable
from ahriman.core.utils import pretty_interval
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
from ahriman.web.apispec import aiohttp_apispec
from ahriman.web.apispec.decorators import apidocs from ahriman.web.apispec.decorators import apidocs
from ahriman.web.schemas import InfoSchema from ahriman.web.schemas import InfoSchema
from ahriman.web.views.base import BaseView from ahriman.web.views.base import BaseView
@@ -52,12 +57,29 @@ class InfoView(BaseView):
Returns: Returns:
Response: 200 with service information object Response: 200 with service information object
""" """
autorefresh_intervals = [
{
"interval": interval * 1000, # milliseconds
"is_active": index == 0, # first element is always default
"text": pretty_interval(interval),
}
for index, interval in enumerate(self.configuration.getintlist("web", "autorefresh_intervals", fallback=[]))
if interval > 0 # special case if 0 exists and first, refresh will not be turned on by default
]
comparator: Callable[[dict[str, Any]], Comparable] = lambda interval: interval["interval"]
username = await authorized_userid(self.request)
response = { response = {
"auth": self.validator.enabled, "auth": self.validator.enabled,
"autorefresh_intervals": sorted(autorefresh_intervals, key=comparator),
"docs_enabled": aiohttp_apispec is not None,
"index_url": self.configuration.get("web", "index_url", fallback=None),
"repositories": [ "repositories": [
repository_id.view() repository_id.view()
for repository_id in sorted(self.services) for repository_id in sorted(self.services)
], ],
"username": username,
"version": __version__, "version": __version__,
} }
-2
View File
@@ -46,8 +46,6 @@ SUBPACKAGES = {
prefix / "lib" / "systemd" / "system" / "ahriman-web@.service", prefix / "lib" / "systemd" / "system" / "ahriman-web@.service",
prefix / "share" / "ahriman" / "settings" / "ahriman.ini.d" / "00-web.ini", prefix / "share" / "ahriman" / "settings" / "ahriman.ini.d" / "00-web.ini",
prefix / "share" / "ahriman" / "templates" / "api.jinja2", prefix / "share" / "ahriman" / "templates" / "api.jinja2",
prefix / "share" / "ahriman" / "templates" / "build-status",
prefix / "share" / "ahriman" / "templates" / "build-status.jinja2",
prefix / "share" / "ahriman" / "templates" / "error.jinja2", prefix / "share" / "ahriman" / "templates" / "error.jinja2",
site_packages / "ahriman" / "application" / "handlers" / "web.py", site_packages / "ahriman" / "application" / "handlers" / "web.py",
site_packages / "ahriman" / "core" / "auth", site_packages / "ahriman" / "core" / "auth",
+2 -8
View File
@@ -569,15 +569,9 @@ def test_walk(resource_path_root: Path) -> None:
resource_path_root / "models" / "package_yay_pkgbuild", resource_path_root / "models" / "package_yay_pkgbuild",
resource_path_root / "models" / "pkgbuild", resource_path_root / "models" / "pkgbuild",
resource_path_root / "models" / "utf8", resource_path_root / "models" / "utf8",
resource_path_root / "web" / "templates" / "build-status" / "alerts.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "dashboard.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "key-import-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "login-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "package-add-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "package-info-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "package-rebuild-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "table.jinja2",
resource_path_root / "web" / "templates" / "static" / "favicon.ico", resource_path_root / "web" / "templates" / "static" / "favicon.ico",
resource_path_root / "web" / "templates" / "static" / "index.css",
resource_path_root / "web" / "templates" / "static" / "index.js",
resource_path_root / "web" / "templates" / "static" / "logo.svg", resource_path_root / "web" / "templates" / "static" / "logo.svg",
resource_path_root / "web" / "templates" / "utils" / "bootstrap-scripts.jinja2", resource_path_root / "web" / "templates" / "utils" / "bootstrap-scripts.jinja2",
resource_path_root / "web" / "templates" / "utils" / "style.jinja2", resource_path_root / "web" / "templates" / "utils" / "style.jinja2",
+1 -1
View File
@@ -42,7 +42,7 @@ async def test_get_index(client_with_auth: TestClient) -> None:
async def test_get_without_auth(client: TestClient) -> None: async def test_get_without_auth(client: TestClient) -> None:
""" """
must use dummy authorized_userid function in case if no security library installed must generate status page without authorization
""" """
response = await client.get("/") response = await client.get("/")
assert response.ok assert response.ok
+18
View File
@@ -193,6 +193,24 @@ commands = [
], ],
] ]
[env.frontend]
description = "Build frontend HTML and JS"
allowlist_externals = [
"npm",
]
change_dir = "frontend"
commands = [
[
"npm",
"install",
],
[
"npm",
"run",
"build",
],
]
[env.html] [env.html]
description = "Generate html documentation" description = "Generate html documentation"
dependency_groups = [ dependency_groups = [