mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-09-23 15:00:34 +00:00
API lib cleanup, 404 hosts WIP
This commit is contained in:
@@ -16,44 +16,45 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tabler/core": "^1.4.0",
|
||||
"@tabler/icons-react": "^3.34.1",
|
||||
"@tanstack/react-query": "^5.85.6",
|
||||
"@tabler/icons-react": "^3.35.0",
|
||||
"@tanstack/react-query": "^5.89.0",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"classnames": "^2.5.1",
|
||||
"country-flag-icons": "^1.5.19",
|
||||
"country-flag-icons": "^1.5.20",
|
||||
"date-fns": "^4.1.0",
|
||||
"formik": "^2.4.6",
|
||||
"generate-password-browser": "^1.1.0",
|
||||
"humps": "^2.0.1",
|
||||
"query-string": "^9.2.2",
|
||||
"query-string": "^9.3.1",
|
||||
"react": "^19.1.1",
|
||||
"react-bootstrap": "^2.10.10",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-intl": "^7.1.11",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"react-router-dom": "^7.9.1",
|
||||
"react-select": "^5.10.2",
|
||||
"react-toastify": "^11.0.5",
|
||||
"rooks": "^9.2.0"
|
||||
"rooks": "^9.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.2.4",
|
||||
"@formatjs/cli": "^6.7.2",
|
||||
"@tanstack/react-query-devtools": "^5.85.6",
|
||||
"@tanstack/react-query-devtools": "^5.89.0",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"@testing-library/jest-dom": "^6.8.0",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/country-flag-icons": "^1.2.2",
|
||||
"@types/humps": "^2.0.6",
|
||||
"@types/react": "^19.1.12",
|
||||
"@types/react": "^19.1.13",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@types/react-table": "^7.7.20",
|
||||
"@vitejs/plugin-react": "^5.0.2",
|
||||
"@vitejs/plugin-react": "^5.0.3",
|
||||
"happy-dom": "^18.0.1",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"sass": "^1.91.0",
|
||||
"sass": "^1.93.0",
|
||||
"tmp": "^0.2.5",
|
||||
"typescript": "5.9.2",
|
||||
"vite": "^7.1.4",
|
||||
"vite": "^7.1.6",
|
||||
"vite-plugin-checker": "^0.10.3",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.2.4"
|
||||
|
@@ -1,13 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { AccessList } from "./models";
|
||||
|
||||
export async function createAccessList(item: AccessList, abortController?: AbortController): Promise<AccessList> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createAccessList(item: AccessList): Promise<AccessList> {
|
||||
return await api.post({
|
||||
url: "/nginx/access-lists",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,13 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { Certificate } from "./models";
|
||||
|
||||
export async function createCertificate(item: Certificate, abortController?: AbortController): Promise<Certificate> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createCertificate(item: Certificate): Promise<Certificate> {
|
||||
return await api.post({
|
||||
url: "/nginx/certificates",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,13 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { DeadHost } from "./models";
|
||||
|
||||
export async function createDeadHost(item: DeadHost, abortController?: AbortController): Promise<DeadHost> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createDeadHost(item: DeadHost): Promise<DeadHost> {
|
||||
return await api.post({
|
||||
url: "/nginx/dead-hosts",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,13 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { ProxyHost } from "./models";
|
||||
|
||||
export async function createProxyHost(item: ProxyHost, abortController?: AbortController): Promise<ProxyHost> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createProxyHost(item: ProxyHost): Promise<ProxyHost> {
|
||||
return await api.post({
|
||||
url: "/nginx/proxy-hosts",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,16 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { RedirectionHost } from "./models";
|
||||
|
||||
export async function createRedirectionHost(
|
||||
item: RedirectionHost,
|
||||
abortController?: AbortController,
|
||||
): Promise<RedirectionHost> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createRedirectionHost(item: RedirectionHost): Promise<RedirectionHost> {
|
||||
return await api.post({
|
||||
url: "/nginx/redirection-hosts",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,13 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { Stream } from "./models";
|
||||
|
||||
export async function createStream(item: Stream, abortController?: AbortController): Promise<Stream> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createStream(item: Stream): Promise<Stream> {
|
||||
return await api.post({
|
||||
url: "/nginx/streams",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -15,14 +15,11 @@ export interface NewUser {
|
||||
roles?: string[];
|
||||
}
|
||||
|
||||
export async function createUser(item: NewUser, noAuth?: boolean, abortController?: AbortController): Promise<User> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function createUser(item: NewUser, noAuth?: boolean): Promise<User> {
|
||||
return await api.post({
|
||||
url: "/users",
|
||||
// todo: only use whitelist of fields for this data
|
||||
data: item,
|
||||
noAuth,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteAccessList(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteAccessList(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/nginx/access-lists/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteCertificate(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteCertificate(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/nginx/certificates/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteDeadHost(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteDeadHost(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/nginx/dead-hosts/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteProxyHost(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteProxyHost(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/nginx/proxy-hosts/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteRedirectionHost(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteRedirectionHost(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/nginx/redirection-hosts/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteStream(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteStream(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/nginx/streams/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function deleteUser(id: number, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.del(
|
||||
{
|
||||
export async function deleteUser(id: number): Promise<boolean> {
|
||||
return await api.del({
|
||||
url: `/users/${id}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,11 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { Binary } from "./responseTypes";
|
||||
|
||||
export async function downloadCertificate(id: number, abortController?: AbortController): Promise<Binary> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function downloadCertificate(id: number): Promise<Binary> {
|
||||
return await api.get({
|
||||
url: `/nginx/certificates/${id}/download`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
6
frontend/src/api/backend/expansions.ts
Normal file
6
frontend/src/api/backend/expansions.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export type AccessListExpansion = "owner" | "items" | "clients";
|
||||
export type AuditLogExpansion = "user";
|
||||
export type CertificateExpansion = "owner" | "proxy_hosts" | "redirection_hosts" | "dead_hosts";
|
||||
export type HostExpansion = "owner" | "certificate";
|
||||
export type ProxyHostExpansion = "owner" | "access_list" | "certificate";
|
||||
export type UserExpansion = "permissions";
|
@@ -1,11 +1,13 @@
|
||||
import * as api from "./base";
|
||||
import type { AccessListExpansion } from "./expansions";
|
||||
import type { AccessList } from "./models";
|
||||
|
||||
export async function getAccessList(id: number, abortController?: AbortController): Promise<AccessList> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getAccessList(id: number, expand?: AccessListExpansion[], params = {}): Promise<AccessList> {
|
||||
return await api.get({
|
||||
url: `/nginx/access-lists/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import * as api from "./base";
|
||||
import type { AccessListExpansion } from "./expansions";
|
||||
import type { AccessList } from "./models";
|
||||
|
||||
export type AccessListExpansion = "owner" | "items" | "clients";
|
||||
|
||||
export async function getAccessLists(expand?: AccessListExpansion[], params = {}): Promise<AccessList[]> {
|
||||
return await api.get({
|
||||
url: "/nginx/access-lists",
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import * as api from "./base";
|
||||
import type { AuditLogExpansion } from "./getAuditLogs";
|
||||
import type { AuditLogExpansion } from "./expansions";
|
||||
import type { AuditLog } from "./models";
|
||||
|
||||
export async function getAuditLog(id: number, expand?: AuditLogExpansion[], params = {}): Promise<AuditLog> {
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import * as api from "./base";
|
||||
import type { AuditLogExpansion } from "./expansions";
|
||||
import type { AuditLog } from "./models";
|
||||
|
||||
export type AuditLogExpansion = "user";
|
||||
|
||||
export async function getAuditLogs(expand?: AuditLogExpansion[], params = {}): Promise<AuditLog[]> {
|
||||
return await api.get({
|
||||
url: "/audit-log",
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import * as api from "./base";
|
||||
import type { CertificateExpansion } from "./expansions";
|
||||
import type { Certificate } from "./models";
|
||||
|
||||
export async function getCertificate(id: number, abortController?: AbortController): Promise<Certificate> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getCertificate(id: number, expand?: CertificateExpansion[], params = {}): Promise<Certificate> {
|
||||
return await api.get({
|
||||
url: `/nginx/certificates/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import * as api from "./base";
|
||||
import type { CertificateExpansion } from "./expansions";
|
||||
import type { Certificate } from "./models";
|
||||
|
||||
export type CertificateExpansion = "owner" | "proxy_hosts" | "redirection_hosts" | "dead_hosts";
|
||||
|
||||
export async function getCertificates(expand?: CertificateExpansion[], params = {}): Promise<Certificate[]> {
|
||||
return await api.get({
|
||||
url: "/nginx/certificates",
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import * as api from "./base";
|
||||
import type { HostExpansion } from "./expansions";
|
||||
import type { DeadHost } from "./models";
|
||||
|
||||
export async function getDeadHost(id: number, abortController?: AbortController): Promise<DeadHost> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getDeadHost(id: number, expand?: HostExpansion[], params = {}): Promise<DeadHost> {
|
||||
return await api.get({
|
||||
url: `/nginx/dead-hosts/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { HostExpansion } from "./expansions";
|
||||
import type { DeadHost } from "./models";
|
||||
|
||||
export type DeadHostExpansion = "owner" | "certificate";
|
||||
|
||||
export async function getDeadHosts(expand?: DeadHostExpansion[], params = {}): Promise<DeadHost[]> {
|
||||
export async function getDeadHosts(expand?: HostExpansion[], params = {}): Promise<DeadHost[]> {
|
||||
return await api.get({
|
||||
url: "/nginx/dead-hosts",
|
||||
params: {
|
||||
|
@@ -1,11 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { HealthResponse } from "./responseTypes";
|
||||
|
||||
export async function getHealth(abortController?: AbortController): Promise<HealthResponse> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getHealth(): Promise<HealthResponse> {
|
||||
return await api.get({
|
||||
url: "/",
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function getHostsReport(abortController?: AbortController): Promise<Record<string, number>> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getHostsReport(): Promise<Record<string, number>> {
|
||||
return await api.get({
|
||||
url: "/reports/hosts",
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import * as api from "./base";
|
||||
import type { ProxyHostExpansion } from "./expansions";
|
||||
import type { ProxyHost } from "./models";
|
||||
|
||||
export async function getProxyHost(id: number, abortController?: AbortController): Promise<ProxyHost> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getProxyHost(id: number, expand?: ProxyHostExpansion[], params = {}): Promise<ProxyHost> {
|
||||
return await api.get({
|
||||
url: `/nginx/proxy-hosts/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import * as api from "./base";
|
||||
import type { ProxyHostExpansion } from "./expansions";
|
||||
import type { ProxyHost } from "./models";
|
||||
|
||||
export type ProxyHostExpansion = "owner" | "access_list" | "certificate";
|
||||
|
||||
export async function getProxyHosts(expand?: ProxyHostExpansion[], params = {}): Promise<ProxyHost[]> {
|
||||
return await api.get({
|
||||
url: "/nginx/proxy-hosts",
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import * as api from "./base";
|
||||
import type { HostExpansion } from "./expansions";
|
||||
import type { ProxyHost } from "./models";
|
||||
|
||||
export async function getRedirectionHost(id: number, abortController?: AbortController): Promise<ProxyHost> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getRedirectionHost(id: number, expand?: HostExpansion[], params = {}): Promise<ProxyHost> {
|
||||
return await api.get({
|
||||
url: `/nginx/redirection-hosts/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,11 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { HostExpansion } from "./expansions";
|
||||
import type { RedirectionHost } from "./models";
|
||||
|
||||
export type RedirectionHostExpansion = "owner" | "certificate";
|
||||
export async function getRedirectionHosts(
|
||||
expand?: RedirectionHostExpansion[],
|
||||
params = {},
|
||||
): Promise<RedirectionHost[]> {
|
||||
export async function getRedirectionHosts(expand?: HostExpansion[], params = {}): Promise<RedirectionHost[]> {
|
||||
return await api.get({
|
||||
url: "/nginx/redirection-hosts",
|
||||
params: {
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { Setting } from "./models";
|
||||
|
||||
export async function getSetting(id: string, abortController?: AbortController): Promise<Setting> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getSetting(id: string, expand?: string[], params = {}): Promise<Setting> {
|
||||
return await api.get({
|
||||
url: `/settings/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import * as api from "./base";
|
||||
import type { HostExpansion } from "./expansions";
|
||||
import type { Stream } from "./models";
|
||||
|
||||
export async function getStream(id: number, abortController?: AbortController): Promise<Stream> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function getStream(id: number, expand?: HostExpansion[], params = {}): Promise<Stream> {
|
||||
return await api.get({
|
||||
url: `/nginx/streams/${id}`,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { HostExpansion } from "./expansions";
|
||||
import type { Stream } from "./models";
|
||||
|
||||
export type StreamExpansion = "owner" | "certificate";
|
||||
|
||||
export async function getStreams(expand?: StreamExpansion[], params = {}): Promise<Stream[]> {
|
||||
export async function getStreams(expand?: HostExpansion[], params = {}): Promise<Stream[]> {
|
||||
return await api.get({
|
||||
url: "/nginx/streams",
|
||||
params: {
|
||||
|
@@ -1,19 +1,9 @@
|
||||
import * as api from "./base";
|
||||
import type { TokenResponse } from "./responseTypes";
|
||||
|
||||
interface Options {
|
||||
payload: {
|
||||
identity: string;
|
||||
secret: string;
|
||||
};
|
||||
}
|
||||
|
||||
export async function getToken({ payload }: Options, abortController?: AbortController): Promise<TokenResponse> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function getToken(identity: string, secret: string): Promise<TokenResponse> {
|
||||
return await api.post({
|
||||
url: "/tokens",
|
||||
data: payload,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
data: { identity, secret },
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,14 @@
|
||||
import * as api from "./base";
|
||||
import type { UserExpansion } from "./expansions";
|
||||
import type { User } from "./models";
|
||||
|
||||
export async function getUser(id: number | string = "me", params = {}): Promise<User> {
|
||||
export async function getUser(id: number | string = "me", expand?: UserExpansion[], params = {}): Promise<User> {
|
||||
const userId = id ? id : "me";
|
||||
return await api.get({
|
||||
url: `/users/${userId}`,
|
||||
params,
|
||||
params: {
|
||||
expand: expand?.join(","),
|
||||
...params,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import * as api from "./base";
|
||||
import type { UserExpansion } from "./expansions";
|
||||
import type { User } from "./models";
|
||||
|
||||
export type UserExpansion = "permissions";
|
||||
|
||||
export async function getUsers(expand?: UserExpansion[], params = {}): Promise<User[]> {
|
||||
return await api.get({
|
||||
url: "/users",
|
||||
|
@@ -13,6 +13,7 @@ export * from "./deleteRedirectionHost";
|
||||
export * from "./deleteStream";
|
||||
export * from "./deleteUser";
|
||||
export * from "./downloadCertificate";
|
||||
export * from "./expansions";
|
||||
export * from "./getAccessList";
|
||||
export * from "./getAccessLists";
|
||||
export * from "./getAuditLog";
|
||||
|
@@ -1,11 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { TokenResponse } from "./responseTypes";
|
||||
|
||||
export async function refreshToken(abortController?: AbortController): Promise<TokenResponse> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function refreshToken(): Promise<TokenResponse> {
|
||||
return await api.get({
|
||||
url: "/tokens",
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,11 +1,8 @@
|
||||
import * as api from "./base";
|
||||
import type { Certificate } from "./models";
|
||||
|
||||
export async function renewCertificate(id: number, abortController?: AbortController): Promise<Certificate> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function renewCertificate(id: number): Promise<Certificate> {
|
||||
return await api.post({
|
||||
url: `/nginx/certificates/${id}/renew`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,17 +1,10 @@
|
||||
import * as api from "./base";
|
||||
import type { UserPermissions } from "./models";
|
||||
|
||||
export async function setPermissions(
|
||||
userId: number,
|
||||
data: UserPermissions,
|
||||
abortController?: AbortController,
|
||||
): Promise<boolean> {
|
||||
export async function setPermissions(userId: number, data: UserPermissions): Promise<boolean> {
|
||||
// Remove readonly fields
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/users/${userId}/permissions`,
|
||||
data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,16 +1,10 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function testHttpCertificate(
|
||||
domains: string[],
|
||||
abortController?: AbortController,
|
||||
): Promise<Record<string, string>> {
|
||||
return await api.get(
|
||||
{
|
||||
export async function testHttpCertificate(domains: string[]): Promise<Record<string, string>> {
|
||||
return await api.get({
|
||||
url: "/nginx/certificates/test-http",
|
||||
params: {
|
||||
domains: domains.join(","),
|
||||
},
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,14 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function toggleDeadHost(
|
||||
id: number,
|
||||
enabled: boolean,
|
||||
abortController?: AbortController,
|
||||
): Promise<boolean> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function toggleDeadHost(id: number, enabled: boolean): Promise<boolean> {
|
||||
return await api.post({
|
||||
url: `/nginx/dead-hosts/${id}/${enabled ? "enable" : "disable"}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,14 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function toggleProxyHost(
|
||||
id: number,
|
||||
enabled: boolean,
|
||||
abortController?: AbortController,
|
||||
): Promise<boolean> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function toggleProxyHost(id: number, enabled: boolean): Promise<boolean> {
|
||||
return await api.post({
|
||||
url: `/nginx/proxy-hosts/${id}/${enabled ? "enable" : "disable"}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,14 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function toggleRedirectionHost(
|
||||
id: number,
|
||||
enabled: boolean,
|
||||
abortController?: AbortController,
|
||||
): Promise<boolean> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function toggleRedirectionHost(id: number, enabled: boolean): Promise<boolean> {
|
||||
return await api.post({
|
||||
url: `/nginx/redirection-hosts/${id}/${enabled ? "enable" : "disable"}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import * as api from "./base";
|
||||
|
||||
export async function toggleStream(id: number, enabled: boolean, abortController?: AbortController): Promise<boolean> {
|
||||
return await api.post(
|
||||
{
|
||||
export async function toggleStream(id: number, enabled: boolean): Promise<boolean> {
|
||||
return await api.post({
|
||||
url: `/nginx/streams/${id}/${enabled ? "enable" : "disable"}`,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,15 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { AccessList } from "./models";
|
||||
|
||||
export async function updateAccessList(item: AccessList, abortController?: AbortController): Promise<AccessList> {
|
||||
export async function updateAccessList(item: AccessList): Promise<AccessList> {
|
||||
// Remove readonly fields
|
||||
const { id, createdOn: _, modifiedOn: __, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/nginx/access-lists/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,12 +1,7 @@
|
||||
import * as api from "./base";
|
||||
import type { User } from "./models";
|
||||
|
||||
export async function updateAuth(
|
||||
userId: number | "me",
|
||||
newPassword: string,
|
||||
current?: string,
|
||||
abortController?: AbortController,
|
||||
): Promise<User> {
|
||||
export async function updateAuth(userId: number | "me", newPassword: string, current?: string): Promise<User> {
|
||||
const data = {
|
||||
type: "password",
|
||||
current: current,
|
||||
@@ -16,11 +11,8 @@ export async function updateAuth(
|
||||
data.current = current;
|
||||
}
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/users/${userId}/auth`,
|
||||
data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,15 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { DeadHost } from "./models";
|
||||
|
||||
export async function updateDeadHost(item: DeadHost, abortController?: AbortController): Promise<DeadHost> {
|
||||
export async function updateDeadHost(item: DeadHost): Promise<DeadHost> {
|
||||
// Remove readonly fields
|
||||
const { id, createdOn: _, modifiedOn: __, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/nginx/dead-hosts/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,15 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { ProxyHost } from "./models";
|
||||
|
||||
export async function updateProxyHost(item: ProxyHost, abortController?: AbortController): Promise<ProxyHost> {
|
||||
export async function updateProxyHost(item: ProxyHost): Promise<ProxyHost> {
|
||||
// Remove readonly fields
|
||||
const { id, createdOn: _, modifiedOn: __, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/nginx/proxy-hosts/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,18 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { RedirectionHost } from "./models";
|
||||
|
||||
export async function updateRedirectionHost(
|
||||
item: RedirectionHost,
|
||||
abortController?: AbortController,
|
||||
): Promise<RedirectionHost> {
|
||||
export async function updateRedirectionHost(item: RedirectionHost): Promise<RedirectionHost> {
|
||||
// Remove readonly fields
|
||||
const { id, createdOn: _, modifiedOn: __, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/nginx/redirection-hosts/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,15 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { Setting } from "./models";
|
||||
|
||||
export async function updateSetting(item: Setting, abortController?: AbortController): Promise<Setting> {
|
||||
export async function updateSetting(item: Setting): Promise<Setting> {
|
||||
// Remove readonly fields
|
||||
const { id, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/settings/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,15 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { Stream } from "./models";
|
||||
|
||||
export async function updateStream(item: Stream, abortController?: AbortController): Promise<Stream> {
|
||||
export async function updateStream(item: Stream): Promise<Stream> {
|
||||
// Remove readonly fields
|
||||
const { id, createdOn: _, modifiedOn: __, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/nginx/streams/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,15 +1,12 @@
|
||||
import * as api from "./base";
|
||||
import type { User } from "./models";
|
||||
|
||||
export async function updateUser(item: User, abortController?: AbortController): Promise<User> {
|
||||
export async function updateUser(item: User): Promise<User> {
|
||||
// Remove readonly fields
|
||||
const { id, createdOn: _, modifiedOn: __, ...data } = item;
|
||||
|
||||
return await api.put(
|
||||
{
|
||||
return await api.put({
|
||||
url: `/users/${id}`,
|
||||
data: data,
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -6,13 +6,9 @@ export async function uploadCertificate(
|
||||
certificate: string,
|
||||
certificateKey: string,
|
||||
intermediateCertificate?: string,
|
||||
abortController?: AbortController,
|
||||
): Promise<Certificate> {
|
||||
return await api.post(
|
||||
{
|
||||
return await api.post({
|
||||
url: `/nginx/certificates/${id}/upload`,
|
||||
data: { certificate, certificateKey, intermediateCertificate },
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -5,13 +5,9 @@ export async function validateCertificate(
|
||||
certificate: string,
|
||||
certificateKey: string,
|
||||
intermediateCertificate?: string,
|
||||
abortController?: AbortController,
|
||||
): Promise<ValidatedCertificateResponse> {
|
||||
return await api.post(
|
||||
{
|
||||
return await api.post({
|
||||
url: "/nginx/certificates/validate",
|
||||
data: { certificate, certificateKey, intermediateCertificate },
|
||||
},
|
||||
abortController,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { intl } from "src/locale";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button } from "src/components";
|
||||
import { intl } from "src/locale";
|
||||
|
||||
export function ErrorNotFound() {
|
||||
const navigate = useNavigate();
|
||||
@@ -9,9 +9,7 @@ export function ErrorNotFound() {
|
||||
<div className="container-tight py-4">
|
||||
<div className="empty">
|
||||
<p className="empty-title">{intl.formatMessage({ id: "notfound.title" })}</p>
|
||||
<p className="empty-subtitle text-secondary">
|
||||
{intl.formatMessage({ id: "notfound.text" })}
|
||||
</p>
|
||||
<p className="empty-subtitle text-secondary">{intl.formatMessage({ id: "notfound.text" })}</p>
|
||||
<div className="empty-action">
|
||||
<Button type="button" size="md" onClick={() => navigate("/")}>
|
||||
{intl.formatMessage({ id: "notfound.action" })}
|
||||
|
119
frontend/src/components/Form/DomainNamesField.tsx
Normal file
119
frontend/src/components/Form/DomainNamesField.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Field, useFormikContext } from "formik";
|
||||
import type { ActionMeta, MultiValue } from "react-select";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
import { intl } from "src/locale";
|
||||
|
||||
export type SelectOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
color?: string;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
maxDomains?: number;
|
||||
isWildcardPermitted?: boolean;
|
||||
dnsProviderWildcardSupported?: boolean;
|
||||
name?: string;
|
||||
label?: string;
|
||||
}
|
||||
export function DomainNamesField({
|
||||
name = "domainNames",
|
||||
label = "domain-names",
|
||||
id = "domainNames",
|
||||
maxDomains,
|
||||
isWildcardPermitted,
|
||||
dnsProviderWildcardSupported,
|
||||
}: Props) {
|
||||
const { values, setFieldValue } = useFormikContext();
|
||||
|
||||
const getDomainCount = (v: string[] | undefined): number => {
|
||||
if (v?.length) {
|
||||
return v.length;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const handleChange = (v: MultiValue<SelectOption>, _actionMeta: ActionMeta<SelectOption>) => {
|
||||
const doms = v?.map((i: SelectOption) => {
|
||||
return i.value;
|
||||
});
|
||||
setFieldValue(name, doms);
|
||||
};
|
||||
|
||||
const isDomainValid = (d: string): boolean => {
|
||||
const dom = d.trim().toLowerCase();
|
||||
const v: any = values;
|
||||
|
||||
// Deny if the list of domains is hit
|
||||
if (maxDomains && getDomainCount(v?.[name]) >= maxDomains) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dom.length < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent wildcards
|
||||
if ((!isWildcardPermitted || !dnsProviderWildcardSupported) && dom.indexOf("*") !== -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent duplicate * in domain
|
||||
if ((dom.match(/\*/g) || []).length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent some invalid characters
|
||||
if ((dom.match(/(@|,|!|&|\$|#|%|\^|\(|\))/g) || []).length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This will match *.com type domains,
|
||||
return dom.match(/\*\.[^.]+$/m) === null;
|
||||
};
|
||||
|
||||
const helperTexts: string[] = [];
|
||||
if (maxDomains) {
|
||||
helperTexts.push(intl.formatMessage({ id: "domain_names.max" }, { count: maxDomains }));
|
||||
}
|
||||
if (!isWildcardPermitted) {
|
||||
helperTexts.push(intl.formatMessage({ id: "wildcards-not-permitted" }));
|
||||
} else if (!dnsProviderWildcardSupported) {
|
||||
helperTexts.push(intl.formatMessage({ id: "wildcards-not-supported" }));
|
||||
}
|
||||
|
||||
return (
|
||||
<Field name={name}>
|
||||
{({ field, form }: any) => (
|
||||
<div className="mb-3">
|
||||
<label className="form-label" htmlFor={id}>
|
||||
{intl.formatMessage({ id: label })}
|
||||
</label>
|
||||
<CreatableSelect
|
||||
name={field.name}
|
||||
id={id}
|
||||
closeMenuOnSelect={true}
|
||||
isClearable={false}
|
||||
isValidNewOption={isDomainValid}
|
||||
isMulti
|
||||
placeholder="Start typing to add domain..."
|
||||
onChange={handleChange}
|
||||
value={field.value?.map((d: string) => ({ label: d, value: d }))}
|
||||
/>
|
||||
{form.errors[field.name] ? (
|
||||
<div className="invalid-feedback">
|
||||
{form.errors[field.name] && form.touched[field.name] ? form.errors[field.name] : null}
|
||||
</div>
|
||||
) : helperTexts.length ? (
|
||||
helperTexts.map((i) => (
|
||||
<div key={i} className="invalid-feedback text-info">
|
||||
{i}
|
||||
</div>
|
||||
))
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
}
|
112
frontend/src/components/Form/SSLCertificateField.tsx
Normal file
112
frontend/src/components/Form/SSLCertificateField.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { IconShield } from "@tabler/icons-react";
|
||||
import { Field, useFormikContext } from "formik";
|
||||
import Select, { type ActionMeta, components, type OptionProps } from "react-select";
|
||||
import type { Certificate } from "src/api/backend";
|
||||
import { useCertificates } from "src/hooks";
|
||||
import { DateTimeFormat, intl } from "src/locale";
|
||||
|
||||
interface CertOption {
|
||||
readonly value: number | "new";
|
||||
readonly label: string;
|
||||
readonly subLabel: string;
|
||||
readonly icon: React.ReactNode;
|
||||
}
|
||||
|
||||
const Option = (props: OptionProps<CertOption>) => {
|
||||
return (
|
||||
<components.Option {...props}>
|
||||
<div className="flex-fill">
|
||||
<div className="font-weight-medium">
|
||||
{props.data.icon} <strong>{props.data.label}</strong>
|
||||
</div>
|
||||
<div className="text-secondary mt-1 ps-3">{props.data.subLabel}</div>
|
||||
</div>
|
||||
</components.Option>
|
||||
);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
name?: string;
|
||||
label?: string;
|
||||
required?: boolean;
|
||||
allowNew?: boolean;
|
||||
}
|
||||
export function SSLCertificateField({
|
||||
name = "certificateId",
|
||||
label = "ssl-certificate",
|
||||
id = "certificateId",
|
||||
required,
|
||||
allowNew,
|
||||
}: Props) {
|
||||
const { isLoading, isError, error, data } = useCertificates();
|
||||
|
||||
const { setFieldValue } = useFormikContext();
|
||||
|
||||
const handleChange = (v: any, _actionMeta: ActionMeta<CertOption>) => {
|
||||
setFieldValue(name, v?.value);
|
||||
};
|
||||
|
||||
const options: CertOption[] =
|
||||
data?.map((cert: Certificate) => ({
|
||||
value: cert.id,
|
||||
label: cert.niceName,
|
||||
subLabel: `${cert.provider === "letsencrypt" ? "Let's Encrypt" : cert.provider} — Expires: ${
|
||||
cert.expiresOn ? DateTimeFormat(cert.expiresOn) : "N/A"
|
||||
}`,
|
||||
icon: <IconShield size={14} className="text-pink" />,
|
||||
})) || [];
|
||||
|
||||
// Prepend the Add New option
|
||||
if (allowNew) {
|
||||
options?.unshift({
|
||||
value: "new",
|
||||
label: "Request a new HTTP certificate",
|
||||
subLabel: "with Let's Encrypt",
|
||||
icon: <IconShield size={14} className="text-lime" />,
|
||||
});
|
||||
}
|
||||
|
||||
// Prepend the None option
|
||||
if (!required) {
|
||||
options?.unshift({
|
||||
value: 0,
|
||||
label: "None",
|
||||
subLabel: "This host will not use HTTPS",
|
||||
icon: <IconShield size={14} className="text-red" />,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Field name={name}>
|
||||
{({ field, form }: any) => (
|
||||
<div className="mb-3">
|
||||
<label className="form-label" htmlFor={id}>
|
||||
{intl.formatMessage({ id: label })}
|
||||
</label>
|
||||
{isLoading ? <div className="placeholder placeholder-lg col-12 my-3 placeholder-glow" /> : null}
|
||||
{isError ? <div className="invalid-feedback">{`${error}`}</div> : null}
|
||||
{!isLoading && !isError ? (
|
||||
<Select
|
||||
defaultValue={options[0]}
|
||||
options={options}
|
||||
components={{ Option }}
|
||||
styles={{
|
||||
option: (base) => ({
|
||||
...base,
|
||||
height: "100%",
|
||||
}),
|
||||
}}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
) : null}
|
||||
{form.errors[field.name] ? (
|
||||
<div className="invalid-feedback">
|
||||
{form.errors[field.name] && form.touched[field.name] ? form.errors[field.name] : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
}
|
2
frontend/src/components/Form/index.ts
Normal file
2
frontend/src/components/Form/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./DomainNamesField";
|
||||
export * from "./SSLCertificateField";
|
@@ -7,11 +7,9 @@ function TableBody<T>(props: TableLayoutProps<T>) {
|
||||
const rows = tableInstance.getRowModel().rows;
|
||||
|
||||
if (rows.length === 0) {
|
||||
return emptyState ? (
|
||||
emptyState
|
||||
) : (
|
||||
return (
|
||||
<tbody className="table-tbody">
|
||||
<EmptyRow tableInstance={tableInstance} />
|
||||
{emptyState ? emptyState : <EmptyRow tableInstance={tableInstance} />}
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
export * from "./Button";
|
||||
export * from "./ErrorNotFound";
|
||||
export * from "./Flag";
|
||||
export * from "./Form";
|
||||
export * from "./HasPermission";
|
||||
export * from "./Loading";
|
||||
export * from "./LoadingPage";
|
||||
|
@@ -30,7 +30,7 @@ function AuthProvider({ children, tokenRefreshInterval = 5 * 60 * 1000 }: Props)
|
||||
};
|
||||
|
||||
const login = async (identity: string, secret: string) => {
|
||||
const response = await getToken({ payload: { identity, secret } });
|
||||
const response = await getToken(identity, secret);
|
||||
handleTokenUpdate(response);
|
||||
};
|
||||
|
||||
|
@@ -2,6 +2,7 @@ export * from "./useAccessLists";
|
||||
export * from "./useAuditLog";
|
||||
export * from "./useAuditLogs";
|
||||
export * from "./useCertificates";
|
||||
export * from "./useDeadHost";
|
||||
export * from "./useDeadHosts";
|
||||
export * from "./useHealth";
|
||||
export * from "./useHostReport";
|
||||
|
57
frontend/src/hooks/useDeadHost.ts
Normal file
57
frontend/src/hooks/useDeadHost.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { createDeadHost, type DeadHost, getDeadHost, updateDeadHost } from "src/api/backend";
|
||||
|
||||
const fetchDeadHost = (id: number | "new") => {
|
||||
if (id === "new") {
|
||||
return Promise.resolve({
|
||||
id: 0,
|
||||
createdOn: "",
|
||||
modifiedOn: "",
|
||||
ownerUserId: 0,
|
||||
domainNames: [],
|
||||
certificateId: 0,
|
||||
sslForced: false,
|
||||
advancedConfig: "",
|
||||
meta: {},
|
||||
http2Support: false,
|
||||
enabled: true,
|
||||
hstsEnabled: false,
|
||||
hstsSubdomains: false,
|
||||
} as DeadHost);
|
||||
}
|
||||
return getDeadHost(id, ["owner"]);
|
||||
};
|
||||
|
||||
const useDeadHost = (id: number | "new", options = {}) => {
|
||||
return useQuery<DeadHost, Error>({
|
||||
queryKey: ["dead-host", id],
|
||||
queryFn: () => fetchDeadHost(id),
|
||||
staleTime: 60 * 1000, // 1 minute
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
const useSetDeadHost = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (values: DeadHost) => (values.id ? updateDeadHost(values) : createDeadHost(values)),
|
||||
onMutate: (values: DeadHost) => {
|
||||
if (!values.id) {
|
||||
return;
|
||||
}
|
||||
const previousObject = queryClient.getQueryData(["dead-host", values.id]);
|
||||
queryClient.setQueryData(["dead-host", values.id], (old: DeadHost) => ({
|
||||
...old,
|
||||
...values,
|
||||
}));
|
||||
return () => queryClient.setQueryData(["dead-host", values.id], previousObject);
|
||||
},
|
||||
onError: (_, __, rollback: any) => rollback(),
|
||||
onSuccess: async ({ id }: DeadHost) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["dead-host", id] });
|
||||
queryClient.invalidateQueries({ queryKey: ["dead-hosts"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { useDeadHost, useSetDeadHost };
|
@@ -1,11 +1,11 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { type DeadHost, type DeadHostExpansion, getDeadHosts } from "src/api/backend";
|
||||
import { type DeadHost, getDeadHosts, type HostExpansion } from "src/api/backend";
|
||||
|
||||
const fetchDeadHosts = (expand?: DeadHostExpansion[]) => {
|
||||
const fetchDeadHosts = (expand?: HostExpansion[]) => {
|
||||
return getDeadHosts(expand);
|
||||
};
|
||||
|
||||
const useDeadHosts = (expand?: DeadHostExpansion[], options = {}) => {
|
||||
const useDeadHosts = (expand?: HostExpansion[], options = {}) => {
|
||||
return useQuery<DeadHost[], Error>({
|
||||
queryKey: ["dead-hosts", { expand }],
|
||||
queryFn: () => fetchDeadHosts(expand),
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getRedirectionHosts, type RedirectionHost, type RedirectionHostExpansion } from "src/api/backend";
|
||||
import { getRedirectionHosts, type HostExpansion, type RedirectionHost } from "src/api/backend";
|
||||
|
||||
const fetchRedirectionHosts = (expand?: RedirectionHostExpansion[]) => {
|
||||
const fetchRedirectionHosts = (expand?: HostExpansion[]) => {
|
||||
return getRedirectionHosts(expand);
|
||||
};
|
||||
|
||||
const useRedirectionHosts = (expand?: RedirectionHostExpansion[], options = {}) => {
|
||||
const useRedirectionHosts = (expand?: HostExpansion[], options = {}) => {
|
||||
return useQuery<RedirectionHost[], Error>({
|
||||
queryKey: ["redirection-hosts", { expand }],
|
||||
queryFn: () => fetchRedirectionHosts(expand),
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getStreams, type Stream, type StreamExpansion } from "src/api/backend";
|
||||
import { getStreams, type HostExpansion, type Stream } from "src/api/backend";
|
||||
|
||||
const fetchStreams = (expand?: StreamExpansion[]) => {
|
||||
const fetchStreams = (expand?: HostExpansion[]) => {
|
||||
return getStreams(expand);
|
||||
};
|
||||
|
||||
const useStreams = (expand?: StreamExpansion[], options = {}) => {
|
||||
const useStreams = (expand?: HostExpansion[], options = {}) => {
|
||||
return useQuery<Stream[], Error>({
|
||||
queryKey: ["streams", { expand }],
|
||||
queryFn: () => fetchStreams(expand),
|
||||
|
@@ -15,7 +15,7 @@ const fetchUser = (id: number | string) => {
|
||||
avatar: "",
|
||||
} as User);
|
||||
}
|
||||
return getUser(id, { expand: "permissions" });
|
||||
return getUser(id, ["permissions"]);
|
||||
};
|
||||
|
||||
const useUser = (id: string | number, options = {}) => {
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"column.access": "Access",
|
||||
"column.authorization": "Authorization",
|
||||
"column.destination": "Destination",
|
||||
"column.details": "Details",
|
||||
"column.email": "Email",
|
||||
"column.event": "Event",
|
||||
"column.expires": "Expires",
|
||||
@@ -40,12 +41,15 @@
|
||||
"column.status": "Status",
|
||||
"created-on": "Created: {date}",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dead-host.edit": "Edit 404 Host",
|
||||
"dead-host.new": "New 404 Host",
|
||||
"dead-hosts.actions-title": "404 Host #{id}",
|
||||
"dead-hosts.add": "Add 404 Host",
|
||||
"dead-hosts.count": "{count} 404 Hosts",
|
||||
"dead-hosts.empty": "There are no 404 Hosts",
|
||||
"dead-hosts.title": "404 Hosts",
|
||||
"disabled": "Disabled",
|
||||
"domain-names": "Domain Names",
|
||||
"email-address": "Email address",
|
||||
"empty-subtitle": "Why don't you create one?",
|
||||
"error.invalid-auth": "Invalid email or password",
|
||||
@@ -96,6 +100,7 @@
|
||||
"setup.preamble": "Get started by creating your admin account.",
|
||||
"setup.title": "Welcome!",
|
||||
"sign-in": "Sign in",
|
||||
"ssl-certificate": "SSL Certificate",
|
||||
"streams.actions-title": "Stream #{id}",
|
||||
"streams.add": "Add Stream",
|
||||
"streams.count": "{count} Streams",
|
||||
@@ -122,5 +127,7 @@
|
||||
"user.switch-light": "Switch to Light mode",
|
||||
"users.actions-title": "User #{id}",
|
||||
"users.add": "Add User",
|
||||
"users.title": "Users"
|
||||
"users.title": "Users",
|
||||
"wildcards-not-permitted": "Wildcards not permitted for this type",
|
||||
"wildcards-not-supported": "Wildcards not supported for this CA"
|
||||
}
|
@@ -77,6 +77,9 @@
|
||||
"column.destination": {
|
||||
"defaultMessage": "Destination"
|
||||
},
|
||||
"column.details": {
|
||||
"defaultMessage": "Details"
|
||||
},
|
||||
"column.email": {
|
||||
"defaultMessage": "Email"
|
||||
},
|
||||
@@ -131,15 +134,24 @@
|
||||
"dead-hosts.count": {
|
||||
"defaultMessage": "{count} 404 Hosts"
|
||||
},
|
||||
"dead-host.edit": {
|
||||
"defaultMessage": "Edit 404 Host"
|
||||
},
|
||||
"dead-hosts.empty": {
|
||||
"defaultMessage": "There are no 404 Hosts"
|
||||
},
|
||||
"dead-host.new": {
|
||||
"defaultMessage": "New 404 Host"
|
||||
},
|
||||
"dead-hosts.title": {
|
||||
"defaultMessage": "404 Hosts"
|
||||
},
|
||||
"disabled": {
|
||||
"defaultMessage": "Disabled"
|
||||
},
|
||||
"domain-names": {
|
||||
"defaultMessage": "Domain Names"
|
||||
},
|
||||
"email-address": {
|
||||
"defaultMessage": "Email address"
|
||||
},
|
||||
@@ -290,6 +302,9 @@
|
||||
"sign-in": {
|
||||
"defaultMessage": "Sign in"
|
||||
},
|
||||
"ssl-certificate": {
|
||||
"defaultMessage": "SSL Certificate"
|
||||
},
|
||||
"streams.actions-title": {
|
||||
"defaultMessage": "Stream #{id}"
|
||||
},
|
||||
@@ -370,5 +385,11 @@
|
||||
},
|
||||
"users.title": {
|
||||
"defaultMessage": "Users"
|
||||
},
|
||||
"wildcards-not-permitted": {
|
||||
"defaultMessage": "Wildcards not permitted for this type"
|
||||
},
|
||||
"wildcards-not-supported": {
|
||||
"defaultMessage": "Wildcards not supported for this CA"
|
||||
}
|
||||
}
|
||||
|
285
frontend/src/modals/DeadHostModal.tsx
Normal file
285
frontend/src/modals/DeadHostModal.tsx
Normal file
@@ -0,0 +1,285 @@
|
||||
import { IconSettings } from "@tabler/icons-react";
|
||||
import { Form, Formik } from "formik";
|
||||
import { useState } from "react";
|
||||
import { Alert } from "react-bootstrap";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import { Button, DomainNamesField, Loading, SSLCertificateField } from "src/components";
|
||||
import { useDeadHost } from "src/hooks";
|
||||
import { intl } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
id: number | "new";
|
||||
onClose: () => void;
|
||||
}
|
||||
export function DeadHostModal({ id, onClose }: Props) {
|
||||
const { data, isLoading, error } = useDeadHost(id);
|
||||
// const { mutate: setDeadHost } = useSetDeadHost();
|
||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||
|
||||
const onSubmit = async (values: any, { setSubmitting }: any) => {
|
||||
setSubmitting(true);
|
||||
setErrorMsg(null);
|
||||
console.log("SUBMIT:", values);
|
||||
setSubmitting(false);
|
||||
// const { ...payload } = {
|
||||
// id: id === "new" ? undefined : id,
|
||||
// roles: [],
|
||||
// ...values,
|
||||
// };
|
||||
|
||||
// setDeadHost(payload, {
|
||||
// onError: (err: any) => setErrorMsg(err.message),
|
||||
// onSuccess: () => {
|
||||
// showSuccess(intl.formatMessage({ id: "notification.dead-host-saved" }));
|
||||
// onClose();
|
||||
// },
|
||||
// onSettled: () => setSubmitting(false),
|
||||
// });
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal show onHide={onClose} animation={false}>
|
||||
{!isLoading && error && (
|
||||
<Alert variant="danger" className="m-3">
|
||||
{error?.message || "Unknown error"}
|
||||
</Alert>
|
||||
)}
|
||||
{isLoading && <Loading noLogo />}
|
||||
{!isLoading && data && (
|
||||
<Formik
|
||||
initialValues={
|
||||
{
|
||||
domainNames: data?.domainNames,
|
||||
certificateId: data?.certificateId,
|
||||
sslForced: data?.sslForced,
|
||||
advancedConfig: data?.advancedConfig,
|
||||
http2Support: data?.http2Support,
|
||||
hstsEnabled: data?.hstsEnabled,
|
||||
hstsSubdomains: data?.hstsSubdomains,
|
||||
} as any
|
||||
}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
{intl.formatMessage({ id: data?.id ? "dead-host.edit" : "dead-host.new" })}
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className="p-0">
|
||||
<Alert variant="danger" show={!!errorMsg} onClose={() => setErrorMsg(null)} dismissible>
|
||||
{errorMsg}
|
||||
</Alert>
|
||||
|
||||
<div className="card m-0 border-0">
|
||||
<div className="card-header">
|
||||
<ul className="nav nav-tabs card-header-tabs" data-bs-toggle="tabs">
|
||||
<li className="nav-item" role="presentation">
|
||||
<a
|
||||
href="#tab-details"
|
||||
className="nav-link active"
|
||||
data-bs-toggle="tab"
|
||||
aria-selected="true"
|
||||
role="tab"
|
||||
>
|
||||
{intl.formatMessage({ id: "column.details" })}
|
||||
</a>
|
||||
</li>
|
||||
<li className="nav-item" role="presentation">
|
||||
<a
|
||||
href="#tab-ssl"
|
||||
className="nav-link"
|
||||
data-bs-toggle="tab"
|
||||
aria-selected="false"
|
||||
tabIndex={-1}
|
||||
role="tab"
|
||||
>
|
||||
{intl.formatMessage({ id: "column.ssl" })}
|
||||
</a>
|
||||
</li>
|
||||
<li className="nav-item ms-auto" role="presentation">
|
||||
<a
|
||||
href="#tab-advanced"
|
||||
className="nav-link"
|
||||
title="Settings"
|
||||
data-bs-toggle="tab"
|
||||
aria-selected="false"
|
||||
tabIndex={-1}
|
||||
role="tab"
|
||||
>
|
||||
<IconSettings size={20} />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="tab-content">
|
||||
<div className="tab-pane active show" id="tab-details" role="tabpanel">
|
||||
<DomainNamesField isWildcardPermitted />
|
||||
</div>
|
||||
<div className="tab-pane" id="tab-ssl" role="tabpanel">
|
||||
<SSLCertificateField
|
||||
name="certificateId"
|
||||
label="ssl-certificate"
|
||||
allowNew
|
||||
/>
|
||||
</div>
|
||||
<div className="tab-pane" id="tab-advanced" role="tabpanel">
|
||||
<h4>Advanced</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <div className="row">
|
||||
<div className="col-lg-6">
|
||||
<div className="mb-3">
|
||||
<Field name="name" validate={validateString(1, 50)}>
|
||||
{({ field, form }: any) => (
|
||||
<div className="form-floating mb-3">
|
||||
<input
|
||||
id="name"
|
||||
className={`form-control ${form.errors.name && form.touched.name ? "is-invalid" : ""}`}
|
||||
placeholder={intl.formatMessage({ id: "user.full-name" })}
|
||||
{...field}
|
||||
/>
|
||||
<label htmlFor="name">
|
||||
{intl.formatMessage({ id: "user.full-name" })}
|
||||
</label>
|
||||
{form.errors.name ? (
|
||||
<div className="invalid-feedback">
|
||||
{form.errors.name && form.touched.name
|
||||
? form.errors.name
|
||||
: null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="mb-3">
|
||||
<Field name="nickname" validate={validateString(1, 30)}>
|
||||
{({ field, form }: any) => (
|
||||
<div className="form-floating mb-3">
|
||||
<input
|
||||
id="nickname"
|
||||
className={`form-control ${form.errors.nickname && form.touched.nickname ? "is-invalid" : ""}`}
|
||||
placeholder={intl.formatMessage({ id: "user.nickname" })}
|
||||
{...field}
|
||||
/>
|
||||
<label htmlFor="nickname">
|
||||
{intl.formatMessage({ id: "user.nickname" })}
|
||||
</label>
|
||||
{form.errors.nickname ? (
|
||||
<div className="invalid-feedback">
|
||||
{form.errors.nickname && form.touched.nickname
|
||||
? form.errors.nickname
|
||||
: null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<Field name="email" validate={validateEmail()}>
|
||||
{({ field, form }: any) => (
|
||||
<div className="form-floating mb-3">
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
className={`form-control ${form.errors.email && form.touched.email ? "is-invalid" : ""}`}
|
||||
placeholder={intl.formatMessage({ id: "email-address" })}
|
||||
{...field}
|
||||
/>
|
||||
<label htmlFor="email">
|
||||
{intl.formatMessage({ id: "email-address" })}
|
||||
</label>
|
||||
{form.errors.email ? (
|
||||
<div className="invalid-feedback">
|
||||
{form.errors.email && form.touched.email
|
||||
? form.errors.email
|
||||
: null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
{currentUser && data && currentUser?.id !== data?.id ? (
|
||||
<div className="my-3">
|
||||
<h3 className="py-2">{intl.formatMessage({ id: "user.flags.title" })}</h3>
|
||||
<div className="divide-y">
|
||||
<div>
|
||||
<label className="row" htmlFor="isAdmin">
|
||||
<span className="col">
|
||||
{intl.formatMessage({ id: "role.admin" })}
|
||||
</span>
|
||||
<span className="col-auto">
|
||||
<Field name="isAdmin" type="checkbox">
|
||||
{({ field }: any) => (
|
||||
<label className="form-check form-check-single form-switch">
|
||||
<input
|
||||
{...field}
|
||||
id="isAdmin"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
</Field>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label className="row" htmlFor="isDisabled">
|
||||
<span className="col">
|
||||
{intl.formatMessage({ id: "disabled" })}
|
||||
</span>
|
||||
<span className="col-auto">
|
||||
<Field name="isDisabled" type="checkbox">
|
||||
{({ field }: any) => (
|
||||
<label className="form-check form-check-single form-switch">
|
||||
<input
|
||||
{...field}
|
||||
id="isDisabled"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
</Field>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null} */}
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
||||
{intl.formatMessage({ id: "cancel" })}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
actionType="primary"
|
||||
className="ms-auto"
|
||||
data-bs-dismiss="modal"
|
||||
isLoading={isSubmitting}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{intl.formatMessage({ id: "save" })}
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
export * from "./ChangePasswordModal";
|
||||
export * from "./DeadHostModal";
|
||||
export * from "./DeleteConfirmModal";
|
||||
export * from "./EventDetailsModal";
|
||||
export * from "./PermissionsModal";
|
||||
|
@@ -1,132 +0,0 @@
|
||||
import { IconDotsVertical, IconEdit, IconPower, IconSearch, IconTrash } from "@tabler/icons-react";
|
||||
import { Button } from "src/components";
|
||||
import { intl } from "src/locale";
|
||||
|
||||
export default function CertificateTable() {
|
||||
return (
|
||||
<div className="card mt-4">
|
||||
<div className="card-status-top bg-pink" />
|
||||
<div className="card-table">
|
||||
<div className="card-header">
|
||||
<div className="row w-full">
|
||||
<div className="col">
|
||||
<h2 className="mt-1 mb-0">{intl.formatMessage({ id: "certificates.title" })}</h2>
|
||||
</div>
|
||||
<div className="col-md-auto col-sm-12">
|
||||
<div className="ms-auto d-flex flex-wrap btn-list">
|
||||
<div className="input-group input-group-flat w-auto">
|
||||
<span className="input-group-text input-group-text-sm">
|
||||
<IconSearch size={16} />
|
||||
</span>
|
||||
<input
|
||||
id="advanced-table-search"
|
||||
type="text"
|
||||
className="form-control form-control-sm"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
<Button size="sm" className="btn-pink">
|
||||
Add Certificate (dropdown)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="advanced-table">
|
||||
<div className="table-responsive">
|
||||
<table className="table table-vcenter table-selectable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="w-1" />
|
||||
<th>
|
||||
<button type="button" className="table-sort d-flex justify-content-between">
|
||||
Source
|
||||
</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" className="table-sort d-flex justify-content-between">
|
||||
Destination
|
||||
</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" className="table-sort d-flex justify-content-between">
|
||||
SSL
|
||||
</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" className="table-sort d-flex justify-content-between">
|
||||
Access
|
||||
</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" className="table-sort d-flex justify-content-between">
|
||||
Status
|
||||
</button>
|
||||
</th>
|
||||
<th className="w-1" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="table-tbody">
|
||||
<tr>
|
||||
<td data-label="Owner">
|
||||
<div className="d-flex py-1 align-items-center">
|
||||
<span
|
||||
className="avatar avatar-2 me-2"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td data-label="Destination">
|
||||
<div className="flex-fill">
|
||||
<div className="font-weight-medium">
|
||||
<span className="badge badge-lg domain-name">blog.jc21.com</span>
|
||||
</div>
|
||||
<div className="text-secondary mt-1">Created: 20th September 2024</div>
|
||||
</div>
|
||||
</td>
|
||||
<td data-label="Source">http://172.17.0.1:3001</td>
|
||||
<td data-label="SSL">Let's Encrypt</td>
|
||||
<td data-label="Access">Public</td>
|
||||
<td data-label="Status">
|
||||
<span className="badge bg-lime-lt">Online</span>
|
||||
</td>
|
||||
<td data-label="Status" className="text-end">
|
||||
<span className="dropdown">
|
||||
<button
|
||||
type="button"
|
||||
className="btn dropdown-toggle btn-action btn-sm px-1"
|
||||
data-bs-boundary="viewport"
|
||||
data-bs-toggle="dropdown"
|
||||
>
|
||||
<IconDotsVertical />
|
||||
</button>
|
||||
<div className="dropdown-menu dropdown-menu-end">
|
||||
<span className="dropdown-header">Proxy Host #2</span>
|
||||
<a className="dropdown-item" href="#">
|
||||
<IconEdit size={16} />
|
||||
Edit
|
||||
</a>
|
||||
<a className="dropdown-item" href="#">
|
||||
<IconPower size={16} />
|
||||
Disable
|
||||
</a>
|
||||
<div className="dropdown-divider" />
|
||||
<a className="dropdown-item" href="#">
|
||||
<IconTrash size={16} />
|
||||
Delete
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -4,15 +4,18 @@ import { intl } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
tableInstance: ReactTable<any>;
|
||||
onNew?: () => void;
|
||||
}
|
||||
export default function Empty({ tableInstance }: Props) {
|
||||
export default function Empty({ tableInstance, onNew }: Props) {
|
||||
return (
|
||||
<tr>
|
||||
<td colSpan={tableInstance.getVisibleFlatColumns().length}>
|
||||
<div className="text-center my-4">
|
||||
<h2>{intl.formatMessage({ id: "dead-hosts.empty" })}</h2>
|
||||
<p className="text-muted">{intl.formatMessage({ id: "empty-subtitle" })}</p>
|
||||
<Button className="btn-red my-3">{intl.formatMessage({ id: "dead-hosts.add" })}</Button>
|
||||
<Button className="btn-red my-3" onClick={onNew}>
|
||||
{intl.formatMessage({ id: "dead-hosts.add" })}
|
||||
</Button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -10,8 +10,10 @@ import Empty from "./Empty";
|
||||
interface Props {
|
||||
data: DeadHost[];
|
||||
isFetching?: boolean;
|
||||
onDelete?: (id: number) => void;
|
||||
onNew?: () => void;
|
||||
}
|
||||
export default function Table({ data, isFetching }: Props) {
|
||||
export default function Table({ data, isFetching, onDelete, onNew }: Props) {
|
||||
const columnHelper = createColumnHelper<DeadHost>();
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
@@ -78,7 +80,14 @@ export default function Table({ data, isFetching }: Props) {
|
||||
{intl.formatMessage({ id: "action.disable" })}
|
||||
</a>
|
||||
<div className="dropdown-divider" />
|
||||
<a className="dropdown-item" href="#">
|
||||
<a
|
||||
className="dropdown-item"
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onDelete?.(info.row.original.id);
|
||||
}}
|
||||
>
|
||||
<IconTrash size={16} />
|
||||
{intl.formatMessage({ id: "action.delete" })}
|
||||
</a>
|
||||
@@ -91,7 +100,7 @@ export default function Table({ data, isFetching }: Props) {
|
||||
},
|
||||
}),
|
||||
],
|
||||
[columnHelper],
|
||||
[columnHelper, onDelete],
|
||||
);
|
||||
|
||||
const tableInstance = useReactTable<DeadHost>({
|
||||
@@ -105,5 +114,7 @@ export default function Table({ data, isFetching }: Props) {
|
||||
enableSortingRemoval: false,
|
||||
});
|
||||
|
||||
return <TableLayout tableInstance={tableInstance} emptyState={<Empty tableInstance={tableInstance} />} />;
|
||||
return (
|
||||
<TableLayout tableInstance={tableInstance} emptyState={<Empty tableInstance={tableInstance} onNew={onNew} />} />
|
||||
);
|
||||
}
|
||||
|
@@ -1,11 +1,16 @@
|
||||
import { IconSearch } from "@tabler/icons-react";
|
||||
import { useState } from "react";
|
||||
import Alert from "react-bootstrap/Alert";
|
||||
import { Button, LoadingPage } from "src/components";
|
||||
import { useDeadHosts } from "src/hooks";
|
||||
import { intl } from "src/locale";
|
||||
import { DeadHostModal, DeleteConfirmModal } from "src/modals";
|
||||
import { showSuccess } from "src/notifications";
|
||||
import Table from "./Table";
|
||||
|
||||
export default function TableWrapper() {
|
||||
const [deleteId, setDeleteId] = useState(0);
|
||||
const [editId, setEditId] = useState(0 as number | "new");
|
||||
const { isFetching, isLoading, isError, error, data } = useDeadHosts(["owner", "certificate"]);
|
||||
|
||||
if (isLoading) {
|
||||
@@ -16,6 +21,11 @@ export default function TableWrapper() {
|
||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||
}
|
||||
|
||||
const handleDelete = async () => {
|
||||
// await deleteUser(deleteId);
|
||||
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card mt-4">
|
||||
<div className="card-status-top bg-red" />
|
||||
@@ -38,14 +48,30 @@ export default function TableWrapper() {
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
<Button size="sm" className="btn-red">
|
||||
<Button size="sm" className="btn-red" onClick={() => setEditId("new")}>
|
||||
{intl.formatMessage({ id: "dead-hosts.add" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Table data={data ?? []} isFetching={isFetching} />
|
||||
<Table
|
||||
data={data ?? []}
|
||||
isFetching={isFetching}
|
||||
onDelete={(id: number) => setDeleteId(id)}
|
||||
onNew={() => setEditId("new")}
|
||||
/>
|
||||
{editId ? <DeadHostModal id={editId} onClose={() => setEditId(0)} /> : null}
|
||||
{deleteId ? (
|
||||
<DeleteConfirmModal
|
||||
title={intl.formatMessage({ id: "user.delete.title" })}
|
||||
onConfirm={handleDelete}
|
||||
onClose={() => setDeleteId(0)}
|
||||
invalidations={[["dead-hosts"], ["dead-host", deleteId]]}
|
||||
>
|
||||
{intl.formatMessage({ id: "user.delete.content" })}
|
||||
</DeleteConfirmModal>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@@ -7,15 +7,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.4.tgz#2856c55443d3d461693f32d2b96fb6ea92e1ffa9"
|
||||
integrity sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==
|
||||
|
||||
"@ampproject/remapping@^2.2.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
|
||||
integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.27.1":
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
|
||||
integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
|
||||
@@ -29,21 +21,21 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790"
|
||||
integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==
|
||||
|
||||
"@babel/core@^7.28.3":
|
||||
version "7.28.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.3.tgz#aceddde69c5d1def69b839d09efa3e3ff59c97cb"
|
||||
integrity sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==
|
||||
"@babel/core@^7.28.4":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.4.tgz#12a550b8794452df4c8b084f95003bce1742d496"
|
||||
integrity sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.2.0"
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/generator" "^7.28.3"
|
||||
"@babel/helper-compilation-targets" "^7.27.2"
|
||||
"@babel/helper-module-transforms" "^7.28.3"
|
||||
"@babel/helpers" "^7.28.3"
|
||||
"@babel/parser" "^7.28.3"
|
||||
"@babel/helpers" "^7.28.4"
|
||||
"@babel/parser" "^7.28.4"
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/traverse" "^7.28.3"
|
||||
"@babel/types" "^7.28.2"
|
||||
"@babel/traverse" "^7.28.4"
|
||||
"@babel/types" "^7.28.4"
|
||||
"@jridgewell/remapping" "^2.3.5"
|
||||
convert-source-map "^2.0.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
@@ -77,7 +69,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
||||
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
||||
|
||||
"@babel/helper-module-imports@^7.27.1":
|
||||
"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204"
|
||||
integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==
|
||||
@@ -114,13 +106,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f"
|
||||
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
|
||||
|
||||
"@babel/helpers@^7.28.3":
|
||||
version "7.28.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.3.tgz#b83156c0a2232c133d1b535dd5d3452119c7e441"
|
||||
integrity sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==
|
||||
"@babel/helpers@^7.28.4":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827"
|
||||
integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==
|
||||
dependencies:
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.28.2"
|
||||
"@babel/types" "^7.28.4"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.27.2", "@babel/parser@^7.28.3":
|
||||
version "7.28.3"
|
||||
@@ -129,6 +121,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.2"
|
||||
|
||||
"@babel/parser@^7.28.4":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.4.tgz#da25d4643532890932cc03f7705fe19637e03fa8"
|
||||
integrity sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.4"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92"
|
||||
@@ -143,6 +142,11 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.27.1"
|
||||
|
||||
"@babel/runtime@^7.12.0", "@babel/runtime@^7.18.3":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326"
|
||||
integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==
|
||||
|
||||
"@babel/runtime@^7.12.5", "@babel/runtime@^7.24.7", "@babel/runtime@^7.26.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7":
|
||||
version "7.28.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.3.tgz#75c5034b55ba868121668be5d5bb31cc64e6e61a"
|
||||
@@ -170,6 +174,19 @@
|
||||
"@babel/types" "^7.28.2"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/traverse@^7.28.4":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.4.tgz#8d456101b96ab175d487249f60680221692b958b"
|
||||
integrity sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/generator" "^7.28.3"
|
||||
"@babel/helper-globals" "^7.28.0"
|
||||
"@babel/parser" "^7.28.4"
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.28.4"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.28.2":
|
||||
version "7.28.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b"
|
||||
@@ -178,6 +195,14 @@
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
|
||||
"@babel/types@^7.28.4":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.4.tgz#0a4e618f4c60a7cd6c11cb2d48060e4dbe38ac3a"
|
||||
integrity sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
|
||||
"@biomejs/biome@^2.2.4":
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.2.4.tgz#184e4b83f89bd0d4151682a5aa3840df37748e17"
|
||||
@@ -232,6 +257,94 @@
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.4.tgz#c8e21413120fe073fa49b78fdd987022941ff66f"
|
||||
integrity sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==
|
||||
|
||||
"@emotion/babel-plugin@^11.13.5":
|
||||
version "11.13.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz#eab8d65dbded74e0ecfd28dc218e75607c4e7bc0"
|
||||
integrity sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.16.7"
|
||||
"@babel/runtime" "^7.18.3"
|
||||
"@emotion/hash" "^0.9.2"
|
||||
"@emotion/memoize" "^0.9.0"
|
||||
"@emotion/serialize" "^1.3.3"
|
||||
babel-plugin-macros "^3.1.0"
|
||||
convert-source-map "^1.5.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.5.7"
|
||||
stylis "4.2.0"
|
||||
|
||||
"@emotion/cache@^11.14.0", "@emotion/cache@^11.4.0":
|
||||
version "11.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.14.0.tgz#ee44b26986eeb93c8be82bb92f1f7a9b21b2ed76"
|
||||
integrity sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.9.0"
|
||||
"@emotion/sheet" "^1.4.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
"@emotion/weak-memoize" "^0.4.0"
|
||||
stylis "4.2.0"
|
||||
|
||||
"@emotion/hash@^0.9.2":
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b"
|
||||
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
|
||||
|
||||
"@emotion/memoize@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102"
|
||||
integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==
|
||||
|
||||
"@emotion/react@^11.8.1":
|
||||
version "11.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.14.0.tgz#cfaae35ebc67dd9ef4ea2e9acc6cd29e157dd05d"
|
||||
integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.18.3"
|
||||
"@emotion/babel-plugin" "^11.13.5"
|
||||
"@emotion/cache" "^11.14.0"
|
||||
"@emotion/serialize" "^1.3.3"
|
||||
"@emotion/use-insertion-effect-with-fallbacks" "^1.2.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
"@emotion/weak-memoize" "^0.4.0"
|
||||
hoist-non-react-statics "^3.3.1"
|
||||
|
||||
"@emotion/serialize@^1.3.3":
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.3.tgz#d291531005f17d704d0463a032fe679f376509e8"
|
||||
integrity sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.9.2"
|
||||
"@emotion/memoize" "^0.9.0"
|
||||
"@emotion/unitless" "^0.10.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@emotion/sheet@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c"
|
||||
integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==
|
||||
|
||||
"@emotion/unitless@^0.10.0":
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745"
|
||||
integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
|
||||
|
||||
"@emotion/use-insertion-effect-with-fallbacks@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf"
|
||||
integrity sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==
|
||||
|
||||
"@emotion/utils@^1.4.2":
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.2.tgz#6df6c45881fcb1c412d6688a311a98b7f59c1b52"
|
||||
integrity sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==
|
||||
|
||||
"@emotion/weak-memoize@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
|
||||
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
||||
|
||||
"@esbuild/aix-ppc64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9"
|
||||
@@ -362,6 +475,26 @@
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz#585624dc829cfb6e7c0aa6c3ca7d7e6daa87e34f"
|
||||
integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==
|
||||
|
||||
"@floating-ui/core@^1.7.3":
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7"
|
||||
integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==
|
||||
dependencies:
|
||||
"@floating-ui/utils" "^0.2.10"
|
||||
|
||||
"@floating-ui/dom@^1.0.1":
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.4.tgz#ee667549998745c9c3e3e84683b909c31d6c9a77"
|
||||
integrity sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==
|
||||
dependencies:
|
||||
"@floating-ui/core" "^1.7.3"
|
||||
"@floating-ui/utils" "^0.2.10"
|
||||
|
||||
"@floating-ui/utils@^0.2.10":
|
||||
version "0.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c"
|
||||
integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==
|
||||
|
||||
"@formatjs/cli@^6.7.2":
|
||||
version "6.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-6.7.2.tgz#8d1a3225dee98cadbc5331b1971f1b79dead4253"
|
||||
@@ -427,6 +560,14 @@
|
||||
"@jridgewell/sourcemap-codec" "^1.5.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@jridgewell/remapping@^2.3.5":
|
||||
version "2.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1"
|
||||
integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.1.0":
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
|
||||
@@ -575,10 +716,10 @@
|
||||
uncontrollable "^8.0.4"
|
||||
warning "^4.0.3"
|
||||
|
||||
"@rolldown/pluginutils@1.0.0-beta.34":
|
||||
version "1.0.0-beta.34"
|
||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz#4421645c676926faa4574940d72fa7ce0ec7d419"
|
||||
integrity sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==
|
||||
"@rolldown/pluginutils@1.0.0-beta.35":
|
||||
version "1.0.0-beta.35"
|
||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz#1a477e7742b154b67519d40e4fc17485de338e7a"
|
||||
integrity sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.50.0":
|
||||
version "4.50.0"
|
||||
@@ -700,41 +841,41 @@
|
||||
"@popperjs/core" "^2.11.8"
|
||||
bootstrap "5.3.7"
|
||||
|
||||
"@tabler/icons-react@^3.34.1":
|
||||
version "3.34.1"
|
||||
resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.34.1.tgz#852b8efcab5382e44cc0f09b3de7d25ef3cba6f9"
|
||||
integrity sha512-Ld6g0NqOO05kyyHsfU8h787PdHBm7cFmOycQSIrGp45XcXYDuOK2Bs0VC4T2FWSKZ6bx5g04imfzazf/nqtk1A==
|
||||
"@tabler/icons-react@^3.35.0":
|
||||
version "3.35.0"
|
||||
resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.35.0.tgz#27f295f36b42f8dc2e7841dd651c8905d0097818"
|
||||
integrity sha512-XG7t2DYf3DyHT5jxFNp5xyLVbL4hMJYJhiSdHADzAjLRYfL7AnjlRfiHDHeXxkb2N103rEIvTsBRazxXtAUz2g==
|
||||
dependencies:
|
||||
"@tabler/icons" "3.34.1"
|
||||
"@tabler/icons" "3.35.0"
|
||||
|
||||
"@tabler/icons@3.34.1":
|
||||
version "3.34.1"
|
||||
resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.34.1.tgz#a04a8cf79a5ebdcc44796dfa3de51d04811d2f9f"
|
||||
integrity sha512-9gTnUvd7Fd/DmQgr3MKY+oJLa1RfNsQo8c/ir3TJAWghOuZXodbtbVp0QBY2DxWuuvrSZFys0HEbv1CoiI5y6A==
|
||||
"@tabler/icons@3.35.0":
|
||||
version "3.35.0"
|
||||
resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.35.0.tgz#6f35247e41baba2a1b0f4dff048bb1335d6c1075"
|
||||
integrity sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ==
|
||||
|
||||
"@tanstack/query-core@5.85.9":
|
||||
version "5.85.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.85.9.tgz#69e800f4d1c42ca4a110469229d8ecca409d477a"
|
||||
integrity sha512-5fxb9vwyftYE6KFLhhhDyLr8NO75+Wpu7pmTo+TkwKmMX2oxZDoLwcqGP8ItKSpUMwk3urWgQDZfyWr5Jm9LsQ==
|
||||
"@tanstack/query-core@5.89.0":
|
||||
version "5.89.0"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.89.0.tgz#67862fa9aa036942b1906bc51385115a2bbec45a"
|
||||
integrity sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==
|
||||
|
||||
"@tanstack/query-devtools@5.84.0":
|
||||
version "5.84.0"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.84.0.tgz#dabed4f4abf405f0e320758ed7bc895a7687d9bb"
|
||||
integrity sha512-fbF3n+z1rqhvd9EoGp5knHkv3p5B2Zml1yNRjh7sNXklngYI5RVIWUrUjZ1RIcEoscarUb0+bOvIs5x9dwzOXQ==
|
||||
"@tanstack/query-devtools@5.87.3":
|
||||
version "5.87.3"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.87.3.tgz#0cfff30823f837d6b9ead08f8d1b16459203fdb2"
|
||||
integrity sha512-LkzxzSr2HS1ALHTgDmJH5eGAVsSQiuwz//VhFW5OqNk0OQ+Fsqba0Tsf+NzWRtXYvpgUqwQr4b2zdFZwxHcGvg==
|
||||
|
||||
"@tanstack/react-query-devtools@^5.85.6":
|
||||
version "5.85.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.85.9.tgz#7d1a09a97cb25ee6acbfed455a49739b4fc96e56"
|
||||
integrity sha512-BAdhgwpzxkC1vdyCfiPbbC7FU/t/x6q2d9ZyhON/WykVUdznD69nlppuWpSIlIGipdRG7sF6tRZ6x3GtSq0EUQ==
|
||||
"@tanstack/react-query-devtools@^5.89.0":
|
||||
version "5.89.0"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.89.0.tgz#ca9cc274cbec7c1479ab67335282a06b4566d164"
|
||||
integrity sha512-Syc4UjZeIJCkXCRGyQcWwlnv89JNb98MMg/DAkFCV3rwOcknj98+nG3Nm6xLXM6ne9sK6RZeDJMPLKZUh6NUGA==
|
||||
dependencies:
|
||||
"@tanstack/query-devtools" "5.84.0"
|
||||
"@tanstack/query-devtools" "5.87.3"
|
||||
|
||||
"@tanstack/react-query@^5.85.6":
|
||||
version "5.85.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.85.9.tgz#d27315b3f327af31237d513e505f3e6a2cad5739"
|
||||
integrity sha512-2T5zgSpcOZXGkH/UObIbIkGmUPQqZqn7esVQFXLOze622h4spgWf5jmvrqAo9dnI13/hyMcNsF1jsoDcb59nJQ==
|
||||
"@tanstack/react-query@^5.89.0":
|
||||
version "5.89.0"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.89.0.tgz#ae295ced60d1aee555337a572ad4045e2af3d00a"
|
||||
integrity sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==
|
||||
dependencies:
|
||||
"@tanstack/query-core" "5.85.9"
|
||||
"@tanstack/query-core" "5.89.0"
|
||||
|
||||
"@tanstack/react-table@^8.21.3":
|
||||
version "8.21.3"
|
||||
@@ -860,6 +1001,11 @@
|
||||
dependencies:
|
||||
undici-types "~6.21.0"
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
|
||||
integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
|
||||
|
||||
"@types/prop-types@^15.7.12":
|
||||
version "15.7.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7"
|
||||
@@ -877,18 +1023,25 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^4.4.6":
|
||||
"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.6":
|
||||
version "4.4.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044"
|
||||
integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==
|
||||
|
||||
"@types/react@*", "@types/react@16 || 17 || 18 || 19", "@types/react@>=16.9.11", "@types/react@^19.1.12":
|
||||
"@types/react@*", "@types/react@16 || 17 || 18 || 19", "@types/react@>=16.9.11":
|
||||
version "19.1.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.12.tgz#7bfaa76aabbb0b4fe0493c21a3a7a93d33e8937b"
|
||||
integrity sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@^19.1.13":
|
||||
version "19.1.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.13.tgz#fc650ffa680d739a25a530f5d7ebe00cdd771883"
|
||||
integrity sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/warning@^3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.3.tgz#d1884c8cc4a426d1ac117ca2611bf333834c6798"
|
||||
@@ -899,15 +1052,15 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz#e5e06dcd3e92d4e622ef0129637707d66c28d6a4"
|
||||
integrity sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==
|
||||
|
||||
"@vitejs/plugin-react@^5.0.2":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.0.2.tgz#3b5d73fc0e4370a0fafe27154d2c208e2bca8f71"
|
||||
integrity sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==
|
||||
"@vitejs/plugin-react@^5.0.3":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.0.3.tgz#182ea45406d89e55b4e35c92a4a8c2c8388726c8"
|
||||
integrity sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==
|
||||
dependencies:
|
||||
"@babel/core" "^7.28.3"
|
||||
"@babel/core" "^7.28.4"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.27.1"
|
||||
"@rolldown/pluginutils" "1.0.0-beta.34"
|
||||
"@rolldown/pluginutils" "1.0.0-beta.35"
|
||||
"@types/babel__core" "^7.20.5"
|
||||
react-refresh "^0.17.0"
|
||||
|
||||
@@ -1004,6 +1157,15 @@ assertion-error@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7"
|
||||
integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==
|
||||
|
||||
babel-plugin-macros@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
|
||||
integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
cosmiconfig "^7.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
@@ -1044,6 +1206,11 @@ cac@^6.7.14:
|
||||
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
|
||||
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
caniuse-lite@^1.0.30001737:
|
||||
version "1.0.30001739"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz#b34ce2d56bfc22f4352b2af0144102d623a124f4"
|
||||
@@ -1082,6 +1249,11 @@ clsx@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
|
||||
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
|
||||
|
||||
convert-source-map@^1.5.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
|
||||
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
|
||||
|
||||
convert-source-map@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
@@ -1092,10 +1264,21 @@ cookie@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610"
|
||||
integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==
|
||||
|
||||
country-flag-icons@^1.5.19:
|
||||
version "1.5.19"
|
||||
resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.5.19.tgz#ecfc0ad0f92a5b484310ac59578cb61b6b35fa66"
|
||||
integrity sha512-D/ZkRyj+ywJC6b2IrAN3/tpbReMUqmuRLlcKFoY/o0+EPQN9Ev/e8tV+D3+9scvu/tarxwLErNwS73C3yzxs/g==
|
||||
cosmiconfig@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
|
||||
integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
|
||||
dependencies:
|
||||
"@types/parse-json" "^4.0.0"
|
||||
import-fresh "^3.2.1"
|
||||
parse-json "^5.0.0"
|
||||
path-type "^4.0.0"
|
||||
yaml "^1.10.0"
|
||||
|
||||
country-flag-icons@^1.5.20:
|
||||
version "1.5.20"
|
||||
resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.5.20.tgz#a373b13f2b2899a2ef85a4b6fb6a80b8f38f9a01"
|
||||
integrity sha512-ldchBFYlw2dXXGXO6q/xCYaFiiK/eg5qSctBRDzUTDvHqAdIMOVTj1sp0OWVo7g6h+RURTjlu+5BhtGwIbe9tg==
|
||||
|
||||
css.escape@^1.5.1:
|
||||
version "1.5.1"
|
||||
@@ -1172,6 +1355,13 @@ electron-to-chromium@^1.5.211:
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz#f434187f227fb7e67bfcf8243b959cf3ce14013e"
|
||||
integrity sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414"
|
||||
integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es-module-lexer@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a"
|
||||
@@ -1214,6 +1404,11 @@ escalade@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
|
||||
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
|
||||
|
||||
escape-string-regexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
estree-walker@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d"
|
||||
@@ -1248,6 +1443,11 @@ filter-obj@^5.1.0:
|
||||
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-5.1.0.tgz#5bd89676000a713d7db2e197f660274428e524ed"
|
||||
integrity sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
|
||||
|
||||
formik@^2.4.6:
|
||||
version "2.4.6"
|
||||
resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.6.tgz#4da75ca80f1a827ab35b08fd98d5a76e928c9686"
|
||||
@@ -1267,6 +1467,11 @@ fsevents@~2.3.2, fsevents@~2.3.3:
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
generate-password-browser@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/generate-password-browser/-/generate-password-browser-1.1.0.tgz#ec1661d0f3ce0b36e2ffdf6099578725a43d12e9"
|
||||
@@ -1294,7 +1499,14 @@ happy-dom@^18.0.1:
|
||||
"@types/whatwg-mimetype" "^3.0.2"
|
||||
whatwg-mimetype "^3.0.0"
|
||||
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
hasown@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@@ -1316,6 +1528,14 @@ immutable@^5.0.2:
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.3.tgz#e6486694c8b76c37c063cca92399fa64098634d4"
|
||||
integrity sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==
|
||||
|
||||
import-fresh@^3.2.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf"
|
||||
integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==
|
||||
dependencies:
|
||||
parent-module "^1.0.0"
|
||||
resolve-from "^4.0.0"
|
||||
|
||||
indent-string@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||
@@ -1338,6 +1558,18 @@ invariant@^2.2.4:
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
is-arrayish@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
|
||||
|
||||
is-core-module@^2.16.0:
|
||||
version "2.16.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
|
||||
integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
|
||||
dependencies:
|
||||
hasown "^2.0.2"
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
@@ -1370,11 +1602,21 @@ jsesc@^3.0.2:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
|
||||
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
|
||||
|
||||
json-parse-even-better-errors@^2.3.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
||||
|
||||
json5@^2.2.3:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
|
||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||
|
||||
lines-and-columns@^1.1.6:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||
|
||||
lodash-es@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||
@@ -1421,6 +1663,11 @@ magic-string@^0.30.17:
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.5.5"
|
||||
|
||||
memoize-one@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
|
||||
|
||||
micromatch@^4.0.5:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||
@@ -1467,11 +1714,38 @@ object-assign@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
|
||||
parent-module@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
|
||||
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
|
||||
dependencies:
|
||||
callsites "^3.0.0"
|
||||
|
||||
parse-json@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
|
||||
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
error-ex "^1.3.1"
|
||||
json-parse-even-better-errors "^2.3.0"
|
||||
lines-and-columns "^1.1.6"
|
||||
|
||||
path-key@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
|
||||
integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
|
||||
|
||||
path-parse@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
pathe@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716"
|
||||
@@ -1533,7 +1807,7 @@ prop-types-extra@^1.1.0:
|
||||
react-is "^16.3.2"
|
||||
warning "^4.0.0"
|
||||
|
||||
prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -1542,10 +1816,10 @@ prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
query-string@^9.2.2:
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.2.2.tgz#a0104824edfdd2c1db2f18af71cef7abf6a3b20f"
|
||||
integrity sha512-pDSIZJ9sFuOp6VnD+5IkakSVf+rICAuuU88Hcsr6AKL0QtxSIfVuKiVP2oahFI7tk3CRSexwV+Ya6MOoTxzg9g==
|
||||
query-string@^9.3.1:
|
||||
version "9.3.1"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.3.1.tgz#d0c93e6c7fb7c17bdf04aa09e382114580ede270"
|
||||
integrity sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw==
|
||||
dependencies:
|
||||
decode-uri-component "^0.4.1"
|
||||
filter-obj "^5.1.0"
|
||||
@@ -1630,21 +1904,36 @@ react-refresh@^0.17.0:
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
|
||||
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
|
||||
|
||||
react-router-dom@^7.8.2:
|
||||
version "7.8.2"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.8.2.tgz#25a8fc36588189baf3bbb5e360c8ffffbd2beabc"
|
||||
integrity sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==
|
||||
react-router-dom@^7.9.1:
|
||||
version "7.9.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.9.1.tgz#48044923701773da6362f9003ec46f308f293f15"
|
||||
integrity sha512-U9WBQssBE9B1vmRjo9qTM7YRzfZ3lUxESIZnsf4VjR/lXYz9MHjvOxHzr/aUm4efpktbVOrF09rL/y4VHa8RMw==
|
||||
dependencies:
|
||||
react-router "7.8.2"
|
||||
react-router "7.9.1"
|
||||
|
||||
react-router@7.8.2:
|
||||
version "7.8.2"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.8.2.tgz#9d2d4147ca72832c550acc60ed688062d18f70b8"
|
||||
integrity sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==
|
||||
react-router@7.9.1:
|
||||
version "7.9.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.9.1.tgz#b227410c31f24dd416c939ca5d0f8d5c8a1404d4"
|
||||
integrity sha512-pfAByjcTpX55mqSDGwGnY9vDCpxqBLASg0BMNAuMmpSGESo/TaOUG6BllhAtAkCGx8Rnohik/XtaqiYUJtgW2g==
|
||||
dependencies:
|
||||
cookie "^1.0.1"
|
||||
set-cookie-parser "^2.6.0"
|
||||
|
||||
react-select@^5.10.2:
|
||||
version "5.10.2"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.10.2.tgz#8dffc69dfd7d74684d9613e6eb27204e3b99e127"
|
||||
integrity sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.0"
|
||||
"@emotion/cache" "^11.4.0"
|
||||
"@emotion/react" "^11.8.1"
|
||||
"@floating-ui/dom" "^1.0.1"
|
||||
"@types/react-transition-group" "^4.4.0"
|
||||
memoize-one "^6.0.0"
|
||||
prop-types "^15.6.0"
|
||||
react-transition-group "^4.3.0"
|
||||
use-isomorphic-layout-effect "^1.2.0"
|
||||
|
||||
react-toastify@^11.0.5:
|
||||
version "11.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-11.0.5.tgz#ce4c42d10eeb433988ab2264d3e445c4e9d13313"
|
||||
@@ -1652,7 +1941,7 @@ react-toastify@^11.0.5:
|
||||
dependencies:
|
||||
clsx "^2.1.1"
|
||||
|
||||
react-transition-group@^4.4.5:
|
||||
react-transition-group@^4.3.0, react-transition-group@^4.4.5:
|
||||
version "4.4.5"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
|
||||
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
|
||||
@@ -1680,6 +1969,20 @@ redent@^3.0.0:
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
resolve@^1.19.0:
|
||||
version "1.22.10"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39"
|
||||
integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==
|
||||
dependencies:
|
||||
is-core-module "^2.16.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
rollup@^4.43.0:
|
||||
version "4.50.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.50.0.tgz#6f237f598b7163ede33ce827af8534c929aaa186"
|
||||
@@ -1710,10 +2013,10 @@ rollup@^4.43.0:
|
||||
"@rollup/rollup-win32-x64-msvc" "4.50.0"
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rooks@^9.2.0:
|
||||
version "9.2.0"
|
||||
resolved "https://registry.yarnpkg.com/rooks/-/rooks-9.2.0.tgz#41916802611026329061954f6c8c16d8a9e7dffa"
|
||||
integrity sha512-kCt4nz8YOSzayr0tIdRCBug+gfxKV1QNAbKb/LYtrDC1/9x7r1hHUMAep4Wh+oxagGA9OezB77CTBhkiHDkzGA==
|
||||
rooks@^9.3.0:
|
||||
version "9.3.0"
|
||||
resolved "https://registry.yarnpkg.com/rooks/-/rooks-9.3.0.tgz#7a3eb44192b7d5b1321acdf15fafdee37987c348"
|
||||
integrity sha512-ez9ReItW+a/GXsA92Lfh5KWTjhbzlp354KOlC5oh9RHVD5fs/GaWwBq72F2xkDXVblgCgFs0Nel1hxojtszhgw==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
lodash.debounce "^4.0.8"
|
||||
@@ -1725,10 +2028,10 @@ safe-buffer@^5.1.0:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
sass@^1.91.0:
|
||||
version "1.92.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.92.0.tgz#02d9ae21ce1763def2cd461449aac2eb56364796"
|
||||
integrity sha512-KDNI0BxgIRDAfJgzNm5wuy+4yOCIZyrUbjSpiU/JItfih+KGXAVefKL53MTml054MmBA3DDKIBMSI/7XLxZJ3A==
|
||||
sass@^1.93.0:
|
||||
version "1.93.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.93.0.tgz#8252f61405be295f4755d1ed5df48bf118587aa5"
|
||||
integrity sha512-CQi5/AzCwiubU3dSqRDJ93RfOfg/hhpW1l6wCIvolmehfwgCI35R/0QDs1+R+Ygrl8jFawwwIojE2w47/mf94A==
|
||||
dependencies:
|
||||
chokidar "^4.0.0"
|
||||
immutable "^5.0.2"
|
||||
@@ -1761,6 +2064,11 @@ siginfo@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
|
||||
source-map@^0.5.7:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
|
||||
|
||||
split-on-first@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-3.0.0.tgz#f04959c9ea8101b9b0bbf35a61b9ebea784a23e7"
|
||||
@@ -1797,6 +2105,16 @@ strip-literal@^3.0.0:
|
||||
dependencies:
|
||||
js-tokens "^9.0.1"
|
||||
|
||||
stylis@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
|
||||
integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
|
||||
|
||||
supports-preserve-symlinks-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
tiny-invariant@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
|
||||
@@ -1825,6 +2143,14 @@ tinyglobby@^0.2.14:
|
||||
fdir "^6.4.4"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
tinyglobby@^0.2.15:
|
||||
version "0.2.15"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2"
|
||||
integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==
|
||||
dependencies:
|
||||
fdir "^6.5.0"
|
||||
picomatch "^4.0.3"
|
||||
|
||||
tinypool@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591"
|
||||
@@ -1900,6 +2226,11 @@ update-browserslist-db@^1.1.3:
|
||||
escalade "^3.2.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
use-isomorphic-layout-effect@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz#2f11a525628f56424521c748feabc2ffcc962fce"
|
||||
integrity sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==
|
||||
|
||||
use-sync-external-store@^1.4.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0"
|
||||
@@ -1940,7 +2271,7 @@ vite-tsconfig-paths@^5.1.4:
|
||||
globrex "^0.1.2"
|
||||
tsconfck "^3.0.3"
|
||||
|
||||
"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.4:
|
||||
"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0":
|
||||
version "7.1.4"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.4.tgz#354944affb55e1aff0157406b74e0d0a3232df9a"
|
||||
integrity sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==
|
||||
@@ -1954,6 +2285,20 @@ vite-tsconfig-paths@^5.1.4:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.3"
|
||||
|
||||
vite@^7.1.6:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.6.tgz#336806d29983135677f498a05efb0fd46c5eef2d"
|
||||
integrity sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==
|
||||
dependencies:
|
||||
esbuild "^0.25.0"
|
||||
fdir "^6.5.0"
|
||||
picomatch "^4.0.3"
|
||||
postcss "^8.5.6"
|
||||
rollup "^4.43.0"
|
||||
tinyglobby "^0.2.15"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.3"
|
||||
|
||||
vitest@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.4.tgz#0637b903ad79d1539a25bc34c0ed54b5c67702ea"
|
||||
@@ -2012,3 +2357,8 @@ yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yaml@^1.10.0:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
Reference in New Issue
Block a user