mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-10-17 02:12:16 +00:00
upload ai slop
This commit is contained in:
1 parent
49ebbc34fa
commit
3dfc78cc4c
93 files changed
+7745
-1732
No files matched your search
@@ -12,3 +12,6 @@ __pycache__/
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.pyd
|
*.pyd
|
||||||
*.pyo
|
*.pyo
|
||||||
|
|
||||||
|
node_modules/
|
||||||
|
frontend/
|
||||||
@@ -99,3 +99,6 @@ status_cache.json
|
|||||||
*.db
|
*.db
|
||||||
|
|
||||||
docs/html/
|
docs/html/
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
node_modules/
|
||||||
@@ -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: "^_" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
@@ -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>
|
||||||
Generated
+4280
File diff suppressed because it is too large.
Load diff
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
};
|
||||||
@@ -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();
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export type BuildStatus = "unknown" | "pending" | "building" | "failed" | "success";
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface Changes {
|
||||||
|
changes?: string;
|
||||||
|
last_commit_sha?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export interface Counters {
|
||||||
|
building: number;
|
||||||
|
failed: number;
|
||||||
|
pending: number;
|
||||||
|
success: number;
|
||||||
|
total: number;
|
||||||
|
unknown: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export interface Dependencies {
|
||||||
|
paths: Record<string, string[]>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export interface Event {
|
||||||
|
created: number;
|
||||||
|
data?: Record<string, unknown>;
|
||||||
|
event: string;
|
||||||
|
message?: string;
|
||||||
|
object_id: string;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export interface LogRecord {
|
||||||
|
created: number;
|
||||||
|
message: string;
|
||||||
|
process_id: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface LoginRequest {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export interface PGPKey {
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface PGPKeyRequest {
|
||||||
|
key: string;
|
||||||
|
server: string;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface Patch {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export interface Remote {
|
||||||
|
branch?: string;
|
||||||
|
git_url?: string;
|
||||||
|
path?: string;
|
||||||
|
source: string;
|
||||||
|
web_url?: string;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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];
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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>,
|
||||||
|
);
|
||||||
@@ -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;
|
||||||
@@ -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" },
|
||||||
|
};
|
||||||
@@ -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"]
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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__,
|
||||||
|
|||||||
@@ -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)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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__,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 = [
|
||||||
|
|||||||
Reference in new issue
Block a user