Agent+MultiServer
This commit is contained in:
1 parent
9b25cb807a
commit
fc3ed57a40
26 files changed
+3233
-338
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
FROM node:22-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
EXPOSE 7070
|
||||||
|
|
||||||
|
CMD ["node", "src/index.js"]
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Stackpulse Agent
|
||||||
|
|
||||||
|
Der Stackpulse Agent stellt Docker- und Host-Metadaten über eine REST-API bereit. Er verbindet sich lokal über `/var/run/docker.sock`, validiert alle Anfragen per `X-Agent-Token` und läuft standardmäßig auf Port `7070`.
|
||||||
|
|
||||||
|
## Start lokal
|
||||||
|
1. Abhängigkeiten installieren: `npm install`
|
||||||
|
2. Starten: `AGENT_TOKEN=<token> npm start`
|
||||||
|
3. Optional: Port via `AGENT_PORT` anpassen.
|
||||||
|
|
||||||
|
## Als Docker-Container
|
||||||
|
```
|
||||||
|
docker build -t stackpulse-agent ./agent
|
||||||
|
docker run -d \
|
||||||
|
-p 7070:7070 \
|
||||||
|
-e AGENT_TOKEN=<token> \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
stackpulse-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Agent liest nur Docker-Daten und verändert keine Container oder Images.
|
||||||
|
|
||||||
|
## Stack-Image-Checks (CE-/BE-Parität)
|
||||||
|
Endpoint: `GET /stack-images?checkUpdates=true|false`
|
||||||
|
- Liefert pro Stack (Compose: `com.docker.compose.project`, Swarm: `com.docker.stack.namespace`) die verwendeten Images.
|
||||||
|
- Optional `checkUpdates=true` für lokalen/remote Digest-Vergleich (`updateAvailable`).
|
||||||
|
|
||||||
|
### Portainer-Version
|
||||||
|
- `GET /portainer/version` – liest den laufenden Portainer-Container (Image/Tag/Labels) aus, ermittelt lokale Digest und vergleicht mit Registry-Digest (Update-Indikator). Funktioniert ohne Portainer-API.
|
||||||
|
|
||||||
|
Optionale Registry-Creds (für private Registries):
|
||||||
|
- `REGISTRY_TOKEN` (Bearer)
|
||||||
|
- oder `REGISTRY_USERNAME` + `REGISTRY_PASSWORD` (Basic)
|
||||||
|
|
||||||
|
Hinweis: Für Swarm-Stacks muss der Agent Swarm-Services lesen können (`docker.listServices`). Ohne Swarm-Manager-Rolle bleibt die Swarm-Liste leer.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "stackpulse-agent",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Stackpulse Agent for Docker metadata and update checks",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node src/index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dockerode": "^4.0.2",
|
||||||
|
"express": "^4.19.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const Docker = require('dockerode');
|
||||||
|
|
||||||
|
const infoRoutes = require('./routes/info');
|
||||||
|
const containerRoutes = require('./routes/containers');
|
||||||
|
const imageRoutes = require('./routes/images');
|
||||||
|
const stackRoutes = require('./routes/stacks');
|
||||||
|
const portainerRoutes = require('./routes/portainer');
|
||||||
|
|
||||||
|
const AGENT_PORT = parseInt(process.env.AGENT_PORT || '7070', 10);
|
||||||
|
const AGENT_TOKEN = process.env.AGENT_TOKEN;
|
||||||
|
const DOCKER_SOCKET = process.env.DOCKER_SOCKET || '/var/run/docker.sock';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const docker = new Docker({ socketPath: DOCKER_SOCKET });
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
if (!AGENT_TOKEN) {
|
||||||
|
// Keep the server running to allow late injection, but warn loudly.
|
||||||
|
console.warn('AGENT_TOKEN is not set. All requests will be rejected until it is configured.');
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const token = req.header('X-Agent-Token');
|
||||||
|
|
||||||
|
if (!token || token !== AGENT_TOKEN) {
|
||||||
|
return res.status(403).json({ error: 'Forbidden' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(infoRoutes(docker));
|
||||||
|
app.use(containerRoutes(docker));
|
||||||
|
app.use(imageRoutes(docker));
|
||||||
|
app.use(stackRoutes(docker));
|
||||||
|
app.use(portainerRoutes(docker));
|
||||||
|
|
||||||
|
app.use((req, res) => res.status(404).json({ error: 'Not found' }));
|
||||||
|
|
||||||
|
app.use((err, req, res, next) => {
|
||||||
|
console.error('Unhandled error:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(AGENT_PORT, () => {
|
||||||
|
console.log(`Stackpulse Agent listening on port ${AGENT_PORT}`);
|
||||||
|
});
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
const express = require('express');
|
||||||
|
|
||||||
|
module.exports = function containerRoutes(docker) {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/containers', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
const payload = containers.map((container) => ({
|
||||||
|
id: container.Id,
|
||||||
|
name: Array.isArray(container.Names) && container.Names.length > 0
|
||||||
|
? container.Names[0].replace(/^\//, '')
|
||||||
|
: null,
|
||||||
|
status: container.Status,
|
||||||
|
image: container.Image,
|
||||||
|
ports: container.Ports,
|
||||||
|
labels: container.Labels,
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json(payload);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/stacks', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
|
||||||
|
const stacks = containers.reduce((acc, container) => {
|
||||||
|
const composeProject = container.Labels?.['com.docker.compose.project'];
|
||||||
|
const swarmStack = container.Labels?.['com.docker.stack.namespace'];
|
||||||
|
const stackName = composeProject || swarmStack || 'unassigned';
|
||||||
|
|
||||||
|
if (!acc[stackName]) {
|
||||||
|
acc[stackName] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
acc[stackName].push({
|
||||||
|
id: container.Id,
|
||||||
|
name: Array.isArray(container.Names) && container.Names.length > 0
|
||||||
|
? container.Names[0].replace(/^\//, '')
|
||||||
|
: null,
|
||||||
|
status: container.Status,
|
||||||
|
image: container.Image,
|
||||||
|
ports: container.Ports,
|
||||||
|
labels: container.Labels,
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const payload = Object.entries(stacks).map(([name, stackContainers]) => ({
|
||||||
|
name,
|
||||||
|
containers: stackContainers,
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json(payload);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/container/:id', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const container = docker.getContainer(req.params.id);
|
||||||
|
const inspect = await container.inspect();
|
||||||
|
|
||||||
|
res.json(inspect);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const { checkImageUpdate, getLocalImageInfo } = require('../services/registryService');
|
||||||
|
|
||||||
|
module.exports = function imageRoutes(docker) {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/images', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const images = await docker.listImages();
|
||||||
|
const payload = images.map((image) => ({
|
||||||
|
repoTags: image.RepoTags || [],
|
||||||
|
size: image.Size,
|
||||||
|
id: image.Id,
|
||||||
|
created: image.Created,
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json(payload);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Accept full image name with slashes/colons: /image/check/<image> (URL-encoded)
|
||||||
|
router.get('/image/check/*', async (req, res) => {
|
||||||
|
const raw = req.params[0] || req.params.name || '';
|
||||||
|
if (!raw) {
|
||||||
|
return res.status(400).json({ error: 'invalid_image' });
|
||||||
|
}
|
||||||
|
const imageName = decodeURIComponent(raw);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await checkImageUpdate(docker, imageName);
|
||||||
|
res.json(result);
|
||||||
|
} catch (err) {
|
||||||
|
const status = err.status || 500;
|
||||||
|
res.status(status).json({ error: err.code || err.message || 'Internal error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
module.exports = function infoRoutes(docker) {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/info', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const [dockerVersion, containers, images] = await Promise.all([
|
||||||
|
docker.version(),
|
||||||
|
docker.listContainers({ all: true }),
|
||||||
|
docker.listImages(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
dockerVersion: dockerVersion.Version,
|
||||||
|
hostname: os.hostname(),
|
||||||
|
uptime: os.uptime(),
|
||||||
|
platform: os.platform(),
|
||||||
|
containerCount: containers.length,
|
||||||
|
imageCount: images.length,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/events', (req, res) => {
|
||||||
|
res.json({ message: 'Events endpoint not implemented yet' });
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const { checkImageUpdate } = require('../services/registryService');
|
||||||
|
|
||||||
|
function extractTag(imageName) {
|
||||||
|
const parts = imageName.split(':');
|
||||||
|
return parts.length > 1 ? parts[parts.length - 1] : 'latest';
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickPortainerContainer(containers) {
|
||||||
|
return containers.find((container) => {
|
||||||
|
const labels = container.Labels || {};
|
||||||
|
if (labels['io.portainer.container']) return true;
|
||||||
|
const image = container.Image || '';
|
||||||
|
return /portainer/i.test(image);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPortainerVersionInfo(docker) {
|
||||||
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
const portainer = pickPortainerContainer(containers);
|
||||||
|
if (!portainer) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageName = portainer.Image;
|
||||||
|
const tag = extractTag(imageName);
|
||||||
|
let version = null;
|
||||||
|
let localDigest = null;
|
||||||
|
let remoteDigest = null;
|
||||||
|
let updateAvailable = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const inspect = await docker.getImage(imageName).inspect();
|
||||||
|
const labels = inspect?.Config?.Labels || {};
|
||||||
|
version = labels['org.opencontainers.image.version'] || labels.version || tag;
|
||||||
|
const repoDigests = inspect?.RepoDigests || [];
|
||||||
|
localDigest = repoDigests.length ? repoDigests[0].split('@')[1] || repoDigests[0] : null;
|
||||||
|
} catch {
|
||||||
|
version = tag;
|
||||||
|
localDigest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const info = await checkImageUpdate(docker, imageName);
|
||||||
|
remoteDigest = info.remoteDigest;
|
||||||
|
localDigest = info.localDigest || localDigest;
|
||||||
|
updateAvailable = info.updateAvailable;
|
||||||
|
} catch {
|
||||||
|
remoteDigest = null;
|
||||||
|
updateAvailable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
containerId: portainer.Id,
|
||||||
|
image: imageName,
|
||||||
|
tag,
|
||||||
|
version,
|
||||||
|
localDigest,
|
||||||
|
remoteDigest,
|
||||||
|
updateAvailable
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function portainerVersionRoutes(docker) {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/portainer/version', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const info = await getPortainerVersionInfo(docker);
|
||||||
|
if (!info) {
|
||||||
|
return res.status(404).json({ error: 'Portainer container not found' });
|
||||||
|
}
|
||||||
|
res.json(info);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const { checkImageUpdate, getLocalImageInfo } = require('../services/registryService');
|
||||||
|
|
||||||
|
async function getComposeStacks(docker) {
|
||||||
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
const stacks = containers.reduce((acc, container) => {
|
||||||
|
const composeProject = container.Labels?.['com.docker.compose.project'];
|
||||||
|
if (!composeProject) return acc;
|
||||||
|
|
||||||
|
if (!acc[composeProject]) {
|
||||||
|
acc[composeProject] = {
|
||||||
|
name: composeProject,
|
||||||
|
type: 'compose',
|
||||||
|
images: new Map(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
acc[composeProject].images.set(container.Image, {
|
||||||
|
source: 'container',
|
||||||
|
name: container.Image
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return Object.values(stacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSwarmStacks(docker) {
|
||||||
|
try {
|
||||||
|
const services = await docker.listServices();
|
||||||
|
const stacks = services.reduce((acc, service) => {
|
||||||
|
const stackNs = service.Spec?.Labels?.['com.docker.stack.namespace'];
|
||||||
|
if (!stackNs) return acc;
|
||||||
|
|
||||||
|
if (!acc[stackNs]) {
|
||||||
|
acc[stackNs] = {
|
||||||
|
name: stackNs,
|
||||||
|
type: 'swarm',
|
||||||
|
images: new Map(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const image = service.Spec?.TaskTemplate?.ContainerSpec?.Image;
|
||||||
|
if (image) {
|
||||||
|
acc[stackNs].images.set(image, {
|
||||||
|
source: service.Spec?.Name || 'service',
|
||||||
|
name: image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return Object.values(stacks);
|
||||||
|
} catch (err) {
|
||||||
|
// Not a swarm or no permissions; just return empty
|
||||||
|
if (err.statusCode === 503 || /This node is not a swarm manager/i.test(err.message || '')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enrichImagesWithDigests(docker, imageEntries) {
|
||||||
|
return Promise.all(imageEntries.map(async (entry) => {
|
||||||
|
try {
|
||||||
|
return await checkImageUpdate(docker, entry.name);
|
||||||
|
} catch (err) {
|
||||||
|
const status = err.status || 500;
|
||||||
|
return {
|
||||||
|
...entry,
|
||||||
|
localDigest: null,
|
||||||
|
remoteDigest: null,
|
||||||
|
updateAvailable: false,
|
||||||
|
error: err.code || err.message || `update_check_failed_${status}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function stackRoutes(docker) {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/stack-images', async (req, res, next) => {
|
||||||
|
const withChecks = req.query.checkUpdates === 'true';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [composeStacks, swarmStacks] = await Promise.all([
|
||||||
|
getComposeStacks(docker),
|
||||||
|
getSwarmStacks(docker)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const combined = [...composeStacks, ...swarmStacks];
|
||||||
|
|
||||||
|
const result = await Promise.all(combined.map(async (stack) => {
|
||||||
|
const images = Array.from(stack.images.values());
|
||||||
|
if (!withChecks) {
|
||||||
|
return { name: stack.name, type: stack.type, images };
|
||||||
|
}
|
||||||
|
|
||||||
|
const enriched = await enrichImagesWithDigests(docker, images);
|
||||||
|
return { name: stack.name, type: stack.type, images: enriched };
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json(result);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Always return local/remote digests with error details when resolution fails
|
||||||
|
router.get('/stack-images/status', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const [composeStacks, swarmStacks] = await Promise.all([
|
||||||
|
getComposeStacks(docker),
|
||||||
|
getSwarmStacks(docker)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const combined = [...composeStacks, ...swarmStacks];
|
||||||
|
|
||||||
|
const result = await Promise.all(combined.map(async (stack) => {
|
||||||
|
const images = Array.from(stack.images.values());
|
||||||
|
const enriched = await enrichImagesWithDigests(docker, images);
|
||||||
|
return { name: stack.name, type: stack.type, images: enriched };
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json(result);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
const DEFAULT_REGISTRY = 'dockerhub';
|
||||||
|
const GHCR_HOST = 'ghcr.io';
|
||||||
|
const DOCKERHUB_HOST = 'registry-1.docker.io';
|
||||||
|
const ACCEPT_HEADERS = [
|
||||||
|
'application/vnd.oci.image.manifest.v1+json',
|
||||||
|
'application/vnd.docker.distribution.manifest.v2+json'
|
||||||
|
];
|
||||||
|
|
||||||
|
function createError(status, code, message) {
|
||||||
|
const err = new Error(message || code);
|
||||||
|
err.status = status;
|
||||||
|
err.code = code;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectRegistry(imageName = '') {
|
||||||
|
if (imageName.startsWith(`${GHCR_HOST}/`)) return 'ghcr';
|
||||||
|
if (!imageName.includes('/')) return 'dockerhub';
|
||||||
|
return 'generic';
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitImageIntoComponents(imageName) {
|
||||||
|
if (!imageName) throw createError(400, 'invalid_image', 'Image name required');
|
||||||
|
|
||||||
|
const registryType = detectRegistry(imageName);
|
||||||
|
let registryHost;
|
||||||
|
let remainder = imageName;
|
||||||
|
|
||||||
|
if (registryType === 'ghcr') {
|
||||||
|
registryHost = GHCR_HOST;
|
||||||
|
remainder = imageName.replace(`${GHCR_HOST}/`, '');
|
||||||
|
} else if (registryType === 'dockerhub') {
|
||||||
|
registryHost = DOCKERHUB_HOST;
|
||||||
|
if (!imageName.includes('/')) {
|
||||||
|
remainder = `library/${imageName}`;
|
||||||
|
} else if (imageName.startsWith('docker.io/')) {
|
||||||
|
remainder = imageName.replace('docker.io/', '');
|
||||||
|
} else if (imageName.startsWith(`${DOCKERHUB_HOST}/`)) {
|
||||||
|
remainder = imageName.replace(`${DOCKERHUB_HOST}/`, '');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const firstSlash = imageName.indexOf('/');
|
||||||
|
registryHost = imageName.slice(0, firstSlash);
|
||||||
|
remainder = imageName.slice(firstSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const digestIndex = remainder.indexOf('@');
|
||||||
|
let repoPart = remainder;
|
||||||
|
let digest = null;
|
||||||
|
if (digestIndex !== -1) {
|
||||||
|
repoPart = remainder.slice(0, digestIndex);
|
||||||
|
digest = remainder.slice(digestIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastColon = repoPart.lastIndexOf(':');
|
||||||
|
let tag = 'latest';
|
||||||
|
let repository = repoPart;
|
||||||
|
if (lastColon > -1 && repoPart.indexOf('/') < lastColon) {
|
||||||
|
tag = repoPart.slice(lastColon + 1);
|
||||||
|
repository = repoPart.slice(0, lastColon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
registryType,
|
||||||
|
registryHost,
|
||||||
|
repository,
|
||||||
|
tag,
|
||||||
|
digest,
|
||||||
|
fullImage: imageName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLocalImageInfo(docker, imageName, preferredTag = null) {
|
||||||
|
try {
|
||||||
|
const image = docker.getImage(imageName);
|
||||||
|
const inspect = await image.inspect();
|
||||||
|
const repoTags = inspect?.RepoTags || [];
|
||||||
|
const repoDigests = inspect?.RepoDigests || [];
|
||||||
|
|
||||||
|
let localTagFull = repoTags.length ? repoTags[0] : null;
|
||||||
|
let localDigestFull = repoDigests.length ? repoDigests[0] : null;
|
||||||
|
|
||||||
|
// Fallback: search listImages for matching repoTag when digest is missing
|
||||||
|
if (!localDigestFull) {
|
||||||
|
const images = await docker.listImages();
|
||||||
|
const matchByTag = images.find((img) => (img.RepoTags || []).includes(imageName));
|
||||||
|
const normalizedRepo = imageName.includes(':') ? imageName.split(':')[0] : imageName;
|
||||||
|
const matchByRepo = images.find((img) => (img.RepoTags || []).some((t) => t.startsWith(`${normalizedRepo}:`)));
|
||||||
|
const candidate = matchByTag || matchByRepo;
|
||||||
|
if (candidate) {
|
||||||
|
localDigestFull = (candidate.RepoDigests || [])[0] || null;
|
||||||
|
localTagFull = (candidate.RepoTags || [])[0] || localTagFull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let localTag = preferredTag || null;
|
||||||
|
if (!localTag) {
|
||||||
|
localTag = localTagFull && localTagFull.includes(':')
|
||||||
|
? localTagFull.split(':').pop()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
const localDigestHash = localDigestFull && localDigestFull.includes('@')
|
||||||
|
? localDigestFull.split('@')[1]
|
||||||
|
: localDigestFull;
|
||||||
|
|
||||||
|
return { localTag, localDigestFull, localDigestHash };
|
||||||
|
} catch (err) {
|
||||||
|
throw createError(404, 'image_not_found', `Local image not found: ${imageName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBasicAuthHeader() {
|
||||||
|
const username = process.env.REGISTRY_USERNAME || process.env.GITHUB_USERNAME;
|
||||||
|
const password = process.env.REGISTRY_PASSWORD || process.env.GITHUB_TOKEN || process.env.GITHUB_PAT;
|
||||||
|
if (!username || !password) return {};
|
||||||
|
const base = Buffer.from(`${username}:${password}`, 'utf8').toString('base64');
|
||||||
|
return { Authorization: `Basic ${base}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBearerHeader() {
|
||||||
|
const token = process.env.REGISTRY_TOKEN;
|
||||||
|
if (!token) return {};
|
||||||
|
return { Authorization: `Bearer ${token}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchRemoteManifest(registryHost, repository, reference, headers) {
|
||||||
|
const url = `https://${registryHost}/v2/${repository}/manifests/${reference}`;
|
||||||
|
const res = await fetch(url, { headers });
|
||||||
|
const body = await res.text();
|
||||||
|
return { res, body };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchRegistryTokenDockerHub(repository) {
|
||||||
|
const headers = {
|
||||||
|
Accept: ACCEPT_HEADERS.join(', '),
|
||||||
|
...buildBearerHeader(),
|
||||||
|
...buildBasicAuthHeader(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const url = `https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repository}:pull`;
|
||||||
|
const res = await fetch(url, { headers });
|
||||||
|
if (!res.ok) {
|
||||||
|
const body = await res.text();
|
||||||
|
throw createError(res.status === 401 ? 403 : res.status, 'token_error', `Failed to fetch Docker Hub token: ${res.status} ${body || ''}`.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.token) {
|
||||||
|
throw createError(403, 'token_error', 'Token missing in Docker Hub response');
|
||||||
|
}
|
||||||
|
return data.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAnonymousTokenDockerHub(repository) {
|
||||||
|
const headers = {
|
||||||
|
Accept: ACCEPT_HEADERS.join(', ')
|
||||||
|
};
|
||||||
|
const url = `https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repository}:pull`;
|
||||||
|
const res = await fetch(url, { headers });
|
||||||
|
if (!res.ok) {
|
||||||
|
const body = await res.text();
|
||||||
|
throw createError(res.status === 401 ? 403 : res.status, 'token_error', `Failed to fetch Docker Hub token anonymously: ${res.status} ${body || ''}`.trim());
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.token) {
|
||||||
|
throw createError(403, 'token_error', 'Token missing in Docker Hub anonymous response');
|
||||||
|
}
|
||||||
|
return data.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveRemoteDigestDockerHub(repository, tag, localDigestHash) {
|
||||||
|
const accept = { Accept: ACCEPT_HEADERS.join(', ') };
|
||||||
|
let token;
|
||||||
|
try {
|
||||||
|
token = await fetchRegistryTokenDockerHub(repository);
|
||||||
|
} catch {
|
||||||
|
token = null;
|
||||||
|
}
|
||||||
|
let headers = token ? { ...accept, Authorization: `Bearer ${token}` } : { ...accept };
|
||||||
|
|
||||||
|
let { res, body } = await fetchRemoteManifest(DOCKERHUB_HOST, repository, tag, headers);
|
||||||
|
if (res.status === 404 && localDigestHash) {
|
||||||
|
({ res, body } = await fetchRemoteManifest(DOCKERHUB_HOST, repository, localDigestHash, headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res.status === 401 || res.status === 403) && !token) {
|
||||||
|
try {
|
||||||
|
const anonToken = await fetchAnonymousTokenDockerHub(repository);
|
||||||
|
headers = { ...accept, Authorization: `Bearer ${anonToken}` };
|
||||||
|
({ res, body } = await fetchRemoteManifest(DOCKERHUB_HOST, repository, tag, headers));
|
||||||
|
if (res.status === 404 && localDigestHash) {
|
||||||
|
({ res, body } = await fetchRemoteManifest(DOCKERHUB_HOST, repository, localDigestHash, headers));
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
if (res.status === 404) throw createError(404, 'tag_not_found', 'Tag not found on registry');
|
||||||
|
if (res.status === 401 || res.status === 403) throw createError(403, 'auth_required', body || 'Unauthorized');
|
||||||
|
throw createError(502, 'registry_error', `Registry responded with ${res.status} ${body || ''}`.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
const digest = extractDigestFromManifest(body);
|
||||||
|
if (!digest) throw createError(500, 'digest_missing', 'Could not extract digest from manifest');
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveRemoteDigestGeneric(registryHost, repository, tag, localDigestHash) {
|
||||||
|
const accept = { Accept: ACCEPT_HEADERS.join(', ') };
|
||||||
|
const headers = {
|
||||||
|
...accept,
|
||||||
|
...buildBearerHeader(),
|
||||||
|
...buildBasicAuthHeader(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let { res, body } = await fetchRemoteManifest(registryHost, repository, tag, headers);
|
||||||
|
if (res.status === 404 && localDigestHash) {
|
||||||
|
({ res, body } = await fetchRemoteManifest(registryHost, repository, localDigestHash, headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
if (res.status === 404) throw createError(404, 'tag_not_found', 'Tag not found on registry');
|
||||||
|
if (res.status === 401 || res.status === 403) throw createError(403, 'auth_required', body || 'Unauthorized');
|
||||||
|
throw createError(502, 'registry_error', `Registry responded with ${res.status} ${body || ''}`.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
const digest = extractDigestFromManifest(body);
|
||||||
|
if (!digest) throw createError(500, 'digest_missing', 'Could not extract digest from manifest');
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveRemoteDigest(registryType, registryHost, repository, tag, localDigestHash) {
|
||||||
|
const fetchDigestViaBuildx = async (ref) => {
|
||||||
|
const { execFile } = require('child_process');
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
execFile('docker', ['buildx', 'imagetools', 'inspect', ref], { maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
|
||||||
|
if (err) {
|
||||||
|
const msg = stderr || err.message || 'docker buildx imagetools inspect failed';
|
||||||
|
return reject(createError(502, 'registry_error', msg.trim()));
|
||||||
|
}
|
||||||
|
const match = stdout.match(/Digest:\s*(sha256:[a-fA-F0-9]+)/);
|
||||||
|
if (match && match[1]) {
|
||||||
|
return resolve(match[1]);
|
||||||
|
}
|
||||||
|
return reject(createError(500, 'digest_missing', 'Could not extract digest from imagetools inspect'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchRemoteDigestViaDocker = async (ref) => {
|
||||||
|
const { execFile } = require('child_process');
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
execFile('docker', ['manifest', 'inspect', ref], { maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
|
||||||
|
if (err) {
|
||||||
|
const msg = stderr || err.message || 'docker manifest inspect failed';
|
||||||
|
return reject(createError(502, 'registry_error', msg.trim()));
|
||||||
|
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(stdout);
|
||||||
|
if (Array.isArray(json.manifests) && json.manifests.length > 0) {
|
||||||
|
const candidate = json.manifests[0];
|
||||||
|
if (candidate?.digest) {
|
||||||
|
return resolve(candidate.digest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (json?.config?.digest) {
|
||||||
|
return resolve(json.config.digest);
|
||||||
|
}
|
||||||
|
if (Array.isArray(json?.layers) && json.layers.length > 0 && json.layers[0].digest) {
|
||||||
|
return resolve(json.layers[0].digest);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// fall through to error
|
||||||
|
}
|
||||||
|
return reject(createError(500, 'digest_missing', 'Could not extract digest from docker manifest inspect'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (registryType === 'ghcr') {
|
||||||
|
// Use docker buildx imagetools inspect for GHCR: tag first, then digest fallback
|
||||||
|
const host = registryHost || GHCR_HOST;
|
||||||
|
try {
|
||||||
|
const digest = await fetchDigestViaBuildx(`${host}/${repository}:${tag}`);
|
||||||
|
return digest;
|
||||||
|
} catch (err) {
|
||||||
|
if (localDigestHash) {
|
||||||
|
return fetchDigestViaBuildx(`${host}/${repository}@${localDigestHash}`);
|
||||||
|
}
|
||||||
|
throw err.code ? err : createError(502, 'registry_error', err.message || 'GHCR lookup failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (registryType === 'dockerhub') {
|
||||||
|
const host = 'docker.io';
|
||||||
|
try {
|
||||||
|
return await fetchDigestViaBuildx(`${host}/${repository}:${tag}`);
|
||||||
|
} catch (err) {
|
||||||
|
if (localDigestHash) {
|
||||||
|
try {
|
||||||
|
return await fetchDigestViaBuildx(`${host}/${repository}@${localDigestHash}`);
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback to manifest inspect/HTTP if buildx fails
|
||||||
|
try {
|
||||||
|
return await fetchRemoteDigestViaDocker(`${host}/${repository}:${tag}`);
|
||||||
|
} catch (err) {
|
||||||
|
if (localDigestHash) {
|
||||||
|
try {
|
||||||
|
return await fetchRemoteDigestViaDocker(`${host}/${repository}@${localDigestHash}`);
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resolveRemoteDigestDockerHub(repository, tag, localDigestHash);
|
||||||
|
}
|
||||||
|
// generic
|
||||||
|
try {
|
||||||
|
return await fetchDigestViaBuildx(`${registryHost}/${repository}:${tag}`);
|
||||||
|
} catch (err) {
|
||||||
|
if (localDigestHash) {
|
||||||
|
try {
|
||||||
|
return await fetchDigestViaBuildx(`${registryHost}/${repository}@${localDigestHash}`);
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fallback manifest path
|
||||||
|
try {
|
||||||
|
return await fetchRemoteDigestViaDocker(`${registryHost}/${repository}:${tag}`);
|
||||||
|
} catch (err) {
|
||||||
|
if (localDigestHash) {
|
||||||
|
try {
|
||||||
|
return await fetchRemoteDigestViaDocker(`${registryHost}/${repository}@${localDigestHash}`);
|
||||||
|
} catch {
|
||||||
|
// fall through to HTTP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resolveRemoteDigestGeneric(registryHost, repository, tag, localDigestHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkImageUpdate(docker, imageName) {
|
||||||
|
const { registryType, registryHost, repository, tag } = splitImageIntoComponents(imageName);
|
||||||
|
const { localTag, localDigestHash } = await getLocalImageInfo(docker, imageName, tag);
|
||||||
|
|
||||||
|
const remoteDigest = await resolveRemoteDigest(registryType, registryHost, repository, tag, localDigestHash);
|
||||||
|
|
||||||
|
return {
|
||||||
|
image: imageName,
|
||||||
|
localTag,
|
||||||
|
localDigest: localDigestHash,
|
||||||
|
remoteDigest,
|
||||||
|
updateAvailable: Boolean(localDigestHash && remoteDigest && localDigestHash !== remoteDigest)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
detectRegistry,
|
||||||
|
splitImageIntoComponents,
|
||||||
|
getLocalImageInfo,
|
||||||
|
checkImageUpdate,
|
||||||
|
resolveRemoteDigestDockerHub,
|
||||||
|
resolveRemoteDigestGeneric
|
||||||
|
};
|
||||||
@@ -209,6 +209,16 @@ CREATE TABLE server_update_scripts (
|
|||||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE
|
FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE server_agents (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
server_id INTEGER NOT NULL UNIQUE,
|
||||||
|
agent_url TEXT,
|
||||||
|
agent_token TEXT NOT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
CREATE INDEX idx_server_update_scripts_server ON server_update_scripts (server_id);
|
CREATE INDEX idx_server_update_scripts_server ON server_update_scripts (server_id);
|
||||||
|
|
||||||
CREATE TABLE user_settings (
|
CREATE TABLE user_settings (
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { db } from './index.js';
|
import { db } from './index.js';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
const BLUEPRINT_FILENAME = 'dbs';
|
const BLUEPRINT_FILENAME = 'dbs';
|
||||||
const PERMISSION_BLUEPRINT = [
|
const PERMISSION_BLUEPRINT = [
|
||||||
@@ -191,8 +192,8 @@ const PERMISSION_BLUEPRINT = [
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'maintenance-server-delete',
|
key: 'maintenance-server-edit',
|
||||||
label: 'Server löschen',
|
label: 'Server bearbeiten',
|
||||||
sortOrder: 1,
|
sortOrder: 1,
|
||||||
defaultLevel: 'none',
|
defaultLevel: 'none',
|
||||||
levels: ['full', 'none'],
|
levels: ['full', 'none'],
|
||||||
@@ -200,6 +201,18 @@ const PERMISSION_BLUEPRINT = [
|
|||||||
{ dependsOnKey: 'maintenance-access', requiredLevel: '!=none' },
|
{ dependsOnKey: 'maintenance-access', requiredLevel: '!=none' },
|
||||||
{ dependsOnKey: 'maintenance-server-manage', requiredLevel: '!=none' }
|
{ dependsOnKey: 'maintenance-server-manage', requiredLevel: '!=none' }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'maintenance-server-delete',
|
||||||
|
label: 'Server löschen',
|
||||||
|
sortOrder: 2,
|
||||||
|
defaultLevel: 'none',
|
||||||
|
levels: ['full', 'none'],
|
||||||
|
dependencies: [
|
||||||
|
{ dependsOnKey: 'maintenance-access', requiredLevel: '!=none' },
|
||||||
|
{ dependsOnKey: 'maintenance-server-manage', requiredLevel: 'full' },
|
||||||
|
{ dependsOnKey: 'maintenance-server-edit', requiredLevel: '=full' }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -722,6 +735,25 @@ const ensurePermissionSeeds = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ensureServerAgentEntries = () => {
|
||||||
|
if (!tableExists('server_agents')) return;
|
||||||
|
const servers = db.prepare('SELECT id FROM servers').all();
|
||||||
|
const insertAgent = db.prepare(`
|
||||||
|
INSERT OR IGNORE INTO server_agents (server_id, agent_url, agent_token, created_at, updated_at)
|
||||||
|
VALUES (?, NULL, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||||
|
`);
|
||||||
|
const updateMissingToken = db.prepare(`
|
||||||
|
UPDATE server_agents
|
||||||
|
SET agent_token = ?
|
||||||
|
WHERE server_id = ? AND (agent_token IS NULL OR agent_token = '')
|
||||||
|
`);
|
||||||
|
servers.forEach((server) => {
|
||||||
|
const token = `sp_${crypto.randomBytes(16).toString('hex')}`;
|
||||||
|
insertAgent.run(server.id, token);
|
||||||
|
updateMissingToken.run(token, server.id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const ensureDatabaseSchema = () => {
|
export const ensureDatabaseSchema = () => {
|
||||||
try {
|
try {
|
||||||
const statements = loadBlueprintStatements();
|
const statements = loadBlueprintStatements();
|
||||||
@@ -730,6 +762,7 @@ export const ensureDatabaseSchema = () => {
|
|||||||
|
|
||||||
dropDeprecatedArtifacts();
|
dropDeprecatedArtifacts();
|
||||||
ensureTablesAndColumns(tableDefinitions);
|
ensureTablesAndColumns(tableDefinitions);
|
||||||
|
ensureServerAgentEntries();
|
||||||
ensureIndexes(indexDefinitions);
|
ensureIndexes(indexDefinitions);
|
||||||
ensurePermissionSeeds();
|
ensurePermissionSeeds();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
+680
-49
@@ -41,7 +41,15 @@ import {
|
|||||||
getSetupStatus,
|
getSetupStatus,
|
||||||
completeSetup,
|
completeSetup,
|
||||||
removeServer,
|
removeServer,
|
||||||
setServerApiKey
|
setServerApiKey,
|
||||||
|
getServerById,
|
||||||
|
ensureServer,
|
||||||
|
getServerConnection,
|
||||||
|
updateServerDetails,
|
||||||
|
getServerStatus,
|
||||||
|
getAgentConfig,
|
||||||
|
setAgentConfig,
|
||||||
|
generateAgentToken
|
||||||
} from './setup/index.js';
|
} from './setup/index.js';
|
||||||
import {
|
import {
|
||||||
listUsers,
|
listUsers,
|
||||||
@@ -633,6 +641,36 @@ const applySelfStackStatus = (status) => {
|
|||||||
|
|
||||||
const buildSetupStatusResponse = () => applySelfStackStatus(getSetupStatus());
|
const buildSetupStatusResponse = () => applySelfStackStatus(getSetupStatus());
|
||||||
|
|
||||||
|
const isCommunityEdition = async () => {
|
||||||
|
try {
|
||||||
|
const summary = await fetchPortainerStatusSummary();
|
||||||
|
const edition = (summary?.edition || '').toLowerCase();
|
||||||
|
return edition.includes('community');
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pingAgent = async (agentUrl, agentToken) => {
|
||||||
|
if (!agentUrl) return { online: false, error: 'agent_url_missing' };
|
||||||
|
const url = agentUrl.replace(/\/+$/, '');
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||||
|
const resp = await fetch(`${url}/info`, {
|
||||||
|
headers: { 'X-Agent-Token': agentToken || '' },
|
||||||
|
signal: controller.signal
|
||||||
|
});
|
||||||
|
clearTimeout(timeout);
|
||||||
|
if (!resp.ok) {
|
||||||
|
return { online: false, error: `status_${resp.status}` };
|
||||||
|
}
|
||||||
|
return { online: true, error: null };
|
||||||
|
} catch (err) {
|
||||||
|
return { online: false, error: err?.message || 'agent_unreachable' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const LEGACY_PORTAINER_SCRIPT_SETTING_KEY = 'portainer_update_script';
|
const LEGACY_PORTAINER_SCRIPT_SETTING_KEY = 'portainer_update_script';
|
||||||
const LEGACY_PORTAINER_SSH_CONFIG_KEY = 'portainer_ssh_config';
|
const LEGACY_PORTAINER_SSH_CONFIG_KEY = 'portainer_ssh_config';
|
||||||
|
|
||||||
@@ -667,13 +705,22 @@ const upsertServerUpdateScriptStmt = db.prepare(`
|
|||||||
const deleteServerUpdateScriptStmt = db.prepare('DELETE FROM server_update_scripts WHERE server_id = ?');
|
const deleteServerUpdateScriptStmt = db.prepare('DELETE FROM server_update_scripts WHERE server_id = ?');
|
||||||
const deleteAllServerUpdateScriptsStmt = db.prepare('DELETE FROM server_update_scripts');
|
const deleteAllServerUpdateScriptsStmt = db.prepare('DELETE FROM server_update_scripts');
|
||||||
|
|
||||||
const DEFAULT_PORTAINER_UPDATE_SCRIPT = [
|
const DEFAULT_PORTAINER_UPDATE_SCRIPT_BE = [
|
||||||
'docker stop portainer',
|
'docker stop portainer',
|
||||||
'docker rm portainer',
|
'docker rm portainer',
|
||||||
'docker pull portainer/portainer-ee:lts',
|
'docker pull portainer/portainer-ee:lts',
|
||||||
'docker run -d -p 8000:8000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ee:lts'
|
'docker run -d -p 8000:8000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ee:lts'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
const DEFAULT_PORTAINER_UPDATE_SCRIPT_CE = [
|
||||||
|
'docker stop portainer',
|
||||||
|
'docker rm portainer',
|
||||||
|
'docker pull portainer/portainer-ce:lts',
|
||||||
|
'docker run -d -p 8000:8000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:lts'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const DEFAULT_PORTAINER_UPDATE_SCRIPT = DEFAULT_PORTAINER_UPDATE_SCRIPT_BE;
|
||||||
|
|
||||||
let portainerUpdateState = {
|
let portainerUpdateState = {
|
||||||
running: false,
|
running: false,
|
||||||
status: 'idle',
|
status: 'idle',
|
||||||
@@ -744,27 +791,45 @@ const migrateLegacyUpdateScript = (serverIdHint = null) => {
|
|||||||
legacyUpdateScriptMigrated = true;
|
legacyUpdateScriptMigrated = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveStoredUpdateScriptRow = () => {
|
const resolveStoredUpdateScriptRow = (preferredServerId = null, fallbackToAny = true) => {
|
||||||
const primaryServerId = resolvePrimaryServerId();
|
const primaryServerId = preferredServerId ?? resolvePrimaryServerId();
|
||||||
migrateLegacyUpdateScript(primaryServerId);
|
migrateLegacyUpdateScript(primaryServerId);
|
||||||
|
|
||||||
if (primaryServerId) {
|
if (primaryServerId) {
|
||||||
const row = selectServerUpdateScriptStmt.get(primaryServerId);
|
const row = selectServerUpdateScriptStmt.get(primaryServerId);
|
||||||
if (row) return row;
|
if (row) return { row, serverId: primaryServerId };
|
||||||
|
if (!fallbackToAny) {
|
||||||
|
return { row: null, serverId: primaryServerId };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectAnyServerUpdateScriptStmt.get() ?? null;
|
if (!fallbackToAny) {
|
||||||
|
return { row: null, serverId: primaryServerId ?? null };
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallback = selectAnyServerUpdateScriptStmt.get();
|
||||||
|
if (fallback) {
|
||||||
|
return { row: fallback, serverId: fallback.server_id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { row: null, serverId: primaryServerId ?? null };
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveTargetServerIdForUpdateScript = () => {
|
const resolveTargetServerIdForUpdateScript = (preferredServerId = null, fallbackToAny = true) => {
|
||||||
|
if (preferredServerId) {
|
||||||
|
return preferredServerId;
|
||||||
|
}
|
||||||
|
if (!fallbackToAny) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const primaryId = resolvePrimaryServerId();
|
const primaryId = resolvePrimaryServerId();
|
||||||
if (primaryId) return primaryId;
|
if (primaryId) return primaryId;
|
||||||
const fallback = selectAnyServerUpdateScriptStmt.get();
|
const fallback = selectAnyServerUpdateScriptStmt.get();
|
||||||
return fallback?.server_id ?? null;
|
return fallback?.server_id ?? null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCustomPortainerScript = () => {
|
const getCustomPortainerScript = (serverId = null) => {
|
||||||
const row = resolveStoredUpdateScriptRow();
|
const { row } = resolveStoredUpdateScriptRow(serverId, !serverId);
|
||||||
if (!row) return null;
|
if (!row) return null;
|
||||||
const normalized = normalizeScriptText(row.custom_script ?? '');
|
const normalized = normalizeScriptText(row.custom_script ?? '');
|
||||||
if (!normalized.trim()) return null;
|
if (!normalized.trim()) return null;
|
||||||
@@ -774,14 +839,14 @@ const getCustomPortainerScript = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveCustomPortainerScript = (script) => {
|
const saveCustomPortainerScript = (script, serverId = null) => {
|
||||||
const normalized = normalizeScriptText(script);
|
const normalized = normalizeScriptText(script);
|
||||||
const trimmed = normalized.trim();
|
const trimmed = normalized.trim();
|
||||||
const serverId = resolveTargetServerIdForUpdateScript();
|
const targetServerId = resolveTargetServerIdForUpdateScript(serverId, !serverId);
|
||||||
|
|
||||||
if (!trimmed) {
|
if (!trimmed) {
|
||||||
if (serverId) {
|
if (targetServerId) {
|
||||||
deleteServerUpdateScriptStmt.run(serverId);
|
deleteServerUpdateScriptStmt.run(targetServerId);
|
||||||
} else {
|
} else {
|
||||||
deleteAllServerUpdateScriptsStmt.run();
|
deleteAllServerUpdateScriptsStmt.run();
|
||||||
}
|
}
|
||||||
@@ -789,17 +854,17 @@ const saveCustomPortainerScript = (script) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serverId) {
|
if (!targetServerId) {
|
||||||
throw new Error('SERVER_NOT_CONFIGURED');
|
throw new Error('SERVER_NOT_CONFIGURED');
|
||||||
}
|
}
|
||||||
|
|
||||||
upsertServerUpdateScriptStmt.run(serverId, normalized);
|
upsertServerUpdateScriptStmt.run(targetServerId, normalized);
|
||||||
deleteSetting(LEGACY_PORTAINER_SCRIPT_SETTING_KEY);
|
deleteSetting(LEGACY_PORTAINER_SCRIPT_SETTING_KEY);
|
||||||
return normalized;
|
return normalized;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEffectivePortainerScript = () => {
|
const getEffectivePortainerScript = (serverId = null, defaultScript = DEFAULT_PORTAINER_UPDATE_SCRIPT) => {
|
||||||
const custom = getCustomPortainerScript();
|
const custom = getCustomPortainerScript(serverId);
|
||||||
if (custom) {
|
if (custom) {
|
||||||
return {
|
return {
|
||||||
script: custom.script,
|
script: custom.script,
|
||||||
@@ -808,12 +873,30 @@ const getEffectivePortainerScript = () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
script: DEFAULT_PORTAINER_UPDATE_SCRIPT,
|
script: defaultScript,
|
||||||
source: 'default',
|
source: 'default',
|
||||||
updatedAt: null
|
updatedAt: null
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resolveServerEdition = async (serverId) => {
|
||||||
|
try {
|
||||||
|
const { server, apiKey } = getServerConnection(serverId);
|
||||||
|
if (!server?.url || !apiKey) return 'Business Edition';
|
||||||
|
const client = createPortainerSetupClient({ baseURL: server.url, apiKey });
|
||||||
|
try {
|
||||||
|
const licenseInfoRes = await client.get('/api/licenses/info');
|
||||||
|
const licenseInfo = licenseInfoRes.data ?? {};
|
||||||
|
const edition = extractPortainerEdition(licenseInfo) ?? 'Business Edition';
|
||||||
|
return edition;
|
||||||
|
} catch {
|
||||||
|
return 'Community Edition';
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return 'Business Edition';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const SSH_ENCRYPTION_KEY = crypto.createHash('sha256')
|
const SSH_ENCRYPTION_KEY = crypto.createHash('sha256')
|
||||||
.update(process.env.PORTAINER_SSH_SECRET || process.env.PORTAINER_API_KEY || 'stackpulse-portainer-ssh-secret')
|
.update(process.env.PORTAINER_SSH_SECRET || process.env.PORTAINER_API_KEY || 'stackpulse-portainer-ssh-secret')
|
||||||
@@ -980,16 +1063,30 @@ const migrateLegacySshConfig = (serverIdHint = null) => {
|
|||||||
legacySshConfigMigrated = true;
|
legacySshConfigMigrated = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveStoredSshConfigRow = () => {
|
const resolveStoredSshConfigRow = (preferredServerId = null, fallbackToAny = true) => {
|
||||||
const primaryServerId = resolvePrimaryServerId();
|
const primaryServerId = preferredServerId ?? resolvePrimaryServerId();
|
||||||
migrateLegacySshConfig(primaryServerId);
|
migrateLegacySshConfig(primaryServerId);
|
||||||
|
|
||||||
if (primaryServerId) {
|
if (primaryServerId) {
|
||||||
const row = selectServerSshConfigByServerStmt.get(primaryServerId);
|
const row = selectServerSshConfigByServerStmt.get(primaryServerId);
|
||||||
if (row) return row;
|
if (row) {
|
||||||
|
return { row, serverId: primaryServerId };
|
||||||
|
}
|
||||||
|
if (!fallbackToAny) {
|
||||||
|
return { row: null, serverId: primaryServerId };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectAnyServerSshConfigStmt.get() ?? null;
|
if (!fallbackToAny) {
|
||||||
|
return { row: null, serverId: primaryServerId ?? null };
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallback = selectAnyServerSshConfigStmt.get();
|
||||||
|
if (fallback) {
|
||||||
|
return { row: fallback, serverId: fallback.server_id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { row: null, serverId: primaryServerId ?? null };
|
||||||
};
|
};
|
||||||
|
|
||||||
const persistPortainerSshConfig = (serverId, config) => {
|
const persistPortainerSshConfig = (serverId, config) => {
|
||||||
@@ -1010,8 +1107,8 @@ const persistPortainerSshConfig = (serverId, config) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPortainerSshConfig = () => {
|
const getPortainerSshConfig = (serverId = null) => {
|
||||||
const row = resolveStoredSshConfigRow();
|
const { row } = resolveStoredSshConfigRow(serverId, !serverId);
|
||||||
if (!row) {
|
if (!row) {
|
||||||
return { ...DEFAULT_PORTAINER_SSH_CONFIG };
|
return { ...DEFAULT_PORTAINER_SSH_CONFIG };
|
||||||
}
|
}
|
||||||
@@ -1043,28 +1140,34 @@ const mergeSshConfig = (base, overrides = {}) => ({
|
|||||||
extraSshArgs: normalizeExtraArgs(overrides.extraSshArgs, base.extraSshArgs)
|
extraSshArgs: normalizeExtraArgs(overrides.extraSshArgs, base.extraSshArgs)
|
||||||
});
|
});
|
||||||
|
|
||||||
const resolveTargetServerIdForSshConfig = () => {
|
const resolveTargetServerIdForSshConfig = (preferredServerId = null, fallbackToAny = true) => {
|
||||||
|
if (preferredServerId) {
|
||||||
|
return preferredServerId;
|
||||||
|
}
|
||||||
|
if (!fallbackToAny) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const primaryId = resolvePrimaryServerId();
|
const primaryId = resolvePrimaryServerId();
|
||||||
if (primaryId) return primaryId;
|
if (primaryId) return primaryId;
|
||||||
const fallback = selectAnyServerSshConfigStmt.get();
|
const fallback = selectAnyServerSshConfigStmt.get();
|
||||||
return fallback?.server_id ?? null;
|
return fallback?.server_id ?? null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const savePortainerSshConfig = (payload = {}) => {
|
const savePortainerSshConfig = (payload = {}, serverId = null) => {
|
||||||
const current = getPortainerSshConfig();
|
const current = getPortainerSshConfig(serverId);
|
||||||
const next = mergeSshConfig(current, payload);
|
const next = mergeSshConfig(current, payload);
|
||||||
const serverId = resolveTargetServerIdForSshConfig();
|
const targetServerId = resolveTargetServerIdForSshConfig(serverId, !serverId);
|
||||||
if (!serverId) {
|
if (!targetServerId) {
|
||||||
throw new Error('SERVER_NOT_CONFIGURED');
|
throw new Error('SERVER_NOT_CONFIGURED');
|
||||||
}
|
}
|
||||||
persistPortainerSshConfig(serverId, next);
|
persistPortainerSshConfig(targetServerId, next);
|
||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deletePortainerSshConfig = () => {
|
const deletePortainerSshConfig = (serverId = null) => {
|
||||||
const serverId = resolveTargetServerIdForSshConfig();
|
const targetServerId = resolveTargetServerIdForSshConfig(serverId, !serverId);
|
||||||
if (serverId) {
|
if (targetServerId) {
|
||||||
deleteServerSshConfigStmt.run(serverId);
|
deleteServerSshConfigStmt.run(targetServerId);
|
||||||
} else {
|
} else {
|
||||||
deleteAllServerSshConfigsStmt.run();
|
deleteAllServerSshConfigsStmt.run();
|
||||||
}
|
}
|
||||||
@@ -1150,17 +1253,19 @@ const buildSshCommandArgs = (config) => {
|
|||||||
return { args, sshConfig, cleanup, env: envOverrides };
|
return { args, sshConfig, cleanup, env: envOverrides };
|
||||||
};
|
};
|
||||||
|
|
||||||
const ensureSshConfigReady = () => getPortainerSshConfig();
|
const ensureSshConfigReady = (serverId = null) => {
|
||||||
|
const config = getPortainerSshConfig(serverId);
|
||||||
const testSshConnection = async (configOverride = null) => {
|
const hasHost = Boolean(config.host && config.username);
|
||||||
const baseConfig = configOverride
|
|
||||||
? mergeSshConfig(getPortainerSshConfig(), configOverride)
|
|
||||||
: ensureSshConfigReady();
|
|
||||||
const hasHost = Boolean(baseConfig.host && baseConfig.username);
|
|
||||||
if (!hasHost) {
|
if (!hasHost) {
|
||||||
throw new Error('SSH-Konfiguration ist unvollständig (Host/Benutzer erforderlich).');
|
throw new Error('SSH-Konfiguration ist unvollständig (Host/Benutzer erforderlich).');
|
||||||
}
|
}
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
|
||||||
|
const testSshConnection = async (configOverride = null, serverId = null) => {
|
||||||
|
const baseConfig = configOverride
|
||||||
|
? mergeSshConfig(getPortainerSshConfig(serverId), configOverride)
|
||||||
|
: ensureSshConfigReady(serverId);
|
||||||
const { args, env: envOverrides, cleanup } = buildSshCommandArgs(baseConfig);
|
const { args, env: envOverrides, cleanup } = buildSshCommandArgs(baseConfig);
|
||||||
const sshArgs = [...args, 'echo', '__PORTAINER_SSH_TEST__'];
|
const sshArgs = [...args, 'echo', '__PORTAINER_SSH_TEST__'];
|
||||||
|
|
||||||
@@ -1299,9 +1404,25 @@ const compareSemver = (a, b) => {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const extractPortainerEdition = (payload) => {
|
||||||
|
if (!payload || typeof payload !== 'object') return null;
|
||||||
|
const enumType = payload.type ?? payload.Type;
|
||||||
|
if (enumType === 2 || enumType === 3) return 'Business Edition';
|
||||||
|
if (enumType === 1) return 'Community Edition';
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const extractPortainerBuild = (payload) => {
|
||||||
|
if (!payload || typeof payload !== 'object') return null;
|
||||||
|
return payload.BuildNumber
|
||||||
|
?? payload.Server?.Build
|
||||||
|
?? payload.VersionInfo?.BuildNumber
|
||||||
|
?? null;
|
||||||
|
};
|
||||||
|
|
||||||
const fetchPortainerStatusSummary = async () => {
|
const fetchPortainerStatusSummary = async () => {
|
||||||
const statusRes = await axiosInstance.get('/api/status');
|
const statusRes = await axiosInstance.get('/api/status');
|
||||||
const statusData = statusRes.data ?? {};
|
let statusData = statusRes.data ?? {};
|
||||||
|
|
||||||
const currentVersion = statusData.Version
|
const currentVersion = statusData.Version
|
||||||
?? statusData.ServerVersion
|
?? statusData.ServerVersion
|
||||||
@@ -1309,8 +1430,31 @@ const fetchPortainerStatusSummary = async () => {
|
|||||||
?? statusData.ServerInfo?.Version
|
?? statusData.ServerInfo?.Version
|
||||||
?? statusData.ServerVersionNumber
|
?? statusData.ServerVersionNumber
|
||||||
?? null;
|
?? null;
|
||||||
const edition = statusData.Edition ?? statusData.Server?.Edition ?? null;
|
let edition = null;
|
||||||
const build = statusData.BuildNumber ?? statusData.Server?.Build ?? null;
|
const build = extractPortainerBuild(statusData);
|
||||||
|
|
||||||
|
// Edition ausschließlich über Lizenz-Endpoint ableiten
|
||||||
|
let effectiveEdition = null;
|
||||||
|
let effectiveBuild = build;
|
||||||
|
try {
|
||||||
|
const licenseInfoRes = await axiosInstance.get('/api/licenses/info');
|
||||||
|
const licenseInfo = licenseInfoRes.data ?? {};
|
||||||
|
effectiveEdition = extractPortainerEdition(licenseInfo) ?? 'Business Edition';
|
||||||
|
} catch (err) {
|
||||||
|
// Endpoint fehlt -> Community Edition
|
||||||
|
effectiveEdition = 'Community Edition';
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional: Build über /api/system/status ergänzen, falls leer
|
||||||
|
if (!effectiveBuild) {
|
||||||
|
try {
|
||||||
|
const systemStatusRes = await axiosInstance.get('/api/system/status');
|
||||||
|
const systemStatus = systemStatusRes.data ?? {};
|
||||||
|
effectiveBuild = extractPortainerBuild(systemStatus) ?? effectiveBuild;
|
||||||
|
} catch (err) {
|
||||||
|
// Build bleibt ggf. null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const errors = {};
|
const errors = {};
|
||||||
let latestVersion = null;
|
let latestVersion = null;
|
||||||
@@ -2055,6 +2199,43 @@ app.post('/api/setup/portainer-stacks', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/servers/:id/agent', requirePermission('maintenance-server-edit', 'read'), async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
try {
|
||||||
|
const config = getAgentConfig(id, { autoCreate: true });
|
||||||
|
const editionFlag = await isCommunityEdition();
|
||||||
|
const { online, error } = await pingAgent(config?.agentUrl, config?.agentToken);
|
||||||
|
res.json({
|
||||||
|
serverId: Number(id),
|
||||||
|
agentUrl: config?.agentUrl || null,
|
||||||
|
agentToken: config?.agentToken || null,
|
||||||
|
online,
|
||||||
|
agentError: error || null,
|
||||||
|
community: editionFlag
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).json({ error: err.code || err.message || 'AGENT_CONFIG_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put('/api/servers/:id/agent', requirePermission('maintenance-server-edit', 'full'), async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
agentUrl: req.body?.agentUrl,
|
||||||
|
agentToken: req.body?.agentToken
|
||||||
|
};
|
||||||
|
// Token ist systemgeneriert; wenn keiner übergeben, wird Auto-Token gesetzt
|
||||||
|
const config = setAgentConfig(id, {
|
||||||
|
agentUrl: payload.agentUrl,
|
||||||
|
agentToken: payload.agentToken || undefined
|
||||||
|
});
|
||||||
|
res.json(config);
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).json({ error: err.code || err.message || 'AGENT_CONFIG_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.post('/api/setup/complete', (req, res) => {
|
app.post('/api/setup/complete', (req, res) => {
|
||||||
const { superuser: superuserInput, server: serverInput, apiKey: apiKeyInput, selfStackId: selfStackInput } = req.body ?? {};
|
const { superuser: superuserInput, server: serverInput, apiKey: apiKeyInput, selfStackId: selfStackInput } = req.body ?? {};
|
||||||
const hasSelfStackInput = req.body ? Object.prototype.hasOwnProperty.call(req.body, 'selfStackId') : false;
|
const hasSelfStackInput = req.body ? Object.prototype.hasOwnProperty.call(req.body, 'selfStackId') : false;
|
||||||
@@ -2139,6 +2320,12 @@ app.post('/api/setup/complete', (req, res) => {
|
|||||||
return res.status(400).json({ error: 'API_KEY_REQUIRED' });
|
return res.status(400).json({ error: 'API_KEY_REQUIRED' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetServerId) {
|
||||||
|
// Ensure agent token exists for CE servers
|
||||||
|
const agent = setAgentConfig(targetServerId, { agentUrl: null, agentToken: undefined });
|
||||||
|
created.agent = agent;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasSelfStackInput) {
|
if (hasSelfStackInput) {
|
||||||
const normalizedSelfStackId = typeof selfStackInput === 'string'
|
const normalizedSelfStackId = typeof selfStackInput === 'string'
|
||||||
? selfStackInput.trim()
|
? selfStackInput.trim()
|
||||||
@@ -2182,6 +2369,450 @@ app.post('/api/setup/complete', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/setup/servers/:id', requirePermission('maintenance-server-manage', 'read'), (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
try {
|
||||||
|
const detail = getServerStatus(id);
|
||||||
|
res.json({ success: true, ...detail });
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
switch (code) {
|
||||||
|
case 'SERVER_ID_INVALID':
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
case 'SERVER_NOT_FOUND':
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
default:
|
||||||
|
console.error('⚠️ [Setup] Serverdetails konnten nicht geladen werden:', error);
|
||||||
|
return res.status(500).json({ error: 'SERVER_FETCH_FAILED' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/setup/servers/:id/check', requirePermission('maintenance-server-manage', 'read'), async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
try {
|
||||||
|
const { server, apiKey } = getServerConnection(id);
|
||||||
|
const agentConfig = getAgentConfig(id, { autoCreate: true });
|
||||||
|
if (!apiKey) {
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
online: false,
|
||||||
|
portainer: {
|
||||||
|
currentVersion: null,
|
||||||
|
latestVersion: null,
|
||||||
|
updateAvailable: null,
|
||||||
|
edition: null,
|
||||||
|
build: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const client = createPortainerSetupClient({ baseURL: server.url, apiKey });
|
||||||
|
const statusRes = await client.get('/api/status');
|
||||||
|
let statusData = statusRes.data ?? {};
|
||||||
|
const currentVersion = statusData.Version
|
||||||
|
?? statusData.ServerVersion
|
||||||
|
?? statusData.Server?.Version
|
||||||
|
?? statusData.ServerInfo?.Version
|
||||||
|
?? statusData.ServerVersionNumber
|
||||||
|
?? null;
|
||||||
|
let edition = null;
|
||||||
|
let build = extractPortainerBuild(statusData);
|
||||||
|
|
||||||
|
// Edition ausschließlich über Lizenz-Endpoint ableiten
|
||||||
|
try {
|
||||||
|
const licenseInfoRes = await client.get('/api/licenses/info');
|
||||||
|
const licenseInfo = licenseInfoRes.data ?? {};
|
||||||
|
edition = extractPortainerEdition(licenseInfo) ?? 'Business Edition';
|
||||||
|
} catch (err) {
|
||||||
|
edition = 'Community Edition';
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional: Build über /api/system/status ergänzen, falls leer
|
||||||
|
if (!build) {
|
||||||
|
try {
|
||||||
|
const systemStatusRes = await client.get('/api/system/status');
|
||||||
|
const systemStatus = systemStatusRes.data ?? {};
|
||||||
|
build = extractPortainerBuild(systemStatus) ?? build;
|
||||||
|
} catch (err) {
|
||||||
|
// Build bleibt ggf. null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hole Version/Edition analog BE über /system/version (falls verfügbar)
|
||||||
|
try {
|
||||||
|
const sysVerRes = await client.get('/api/system/version');
|
||||||
|
const sysVer = sysVerRes.data ?? {};
|
||||||
|
const apiVersion = sysVer.Version || sysVer.version || null;
|
||||||
|
const apiEdition = sysVer.Edition || sysVer.edition || null;
|
||||||
|
if (apiVersion) {
|
||||||
|
statusData = { ...statusData, Version: apiVersion };
|
||||||
|
}
|
||||||
|
if (apiEdition) {
|
||||||
|
edition = apiEdition;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// ignore, CE ohne endpoint oder Fehler
|
||||||
|
}
|
||||||
|
|
||||||
|
let agentOnline = null;
|
||||||
|
let agentError = null;
|
||||||
|
let agentVersion = null;
|
||||||
|
|
||||||
|
if ((edition || '').toLowerCase().includes('community') && agentConfig?.agentUrl) {
|
||||||
|
const { online, error } = await pingAgent(agentConfig.agentUrl, agentConfig.agentToken);
|
||||||
|
agentOnline = online;
|
||||||
|
agentError = error;
|
||||||
|
if (online) {
|
||||||
|
try {
|
||||||
|
const agentRes = await fetch(`${agentConfig.agentUrl.replace(/\/+$/, '')}/portainer/version`, {
|
||||||
|
headers: { 'X-Agent-Token': agentConfig.agentToken || '' }
|
||||||
|
});
|
||||||
|
if (agentRes.ok) {
|
||||||
|
agentVersion = await agentRes.json();
|
||||||
|
} else {
|
||||||
|
agentError = `agent_status_${agentRes.status}`;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
agentError = err?.message || 'agent_fetch_failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const effectiveCurrentVersion = statusData.Version
|
||||||
|
?? statusData.ServerVersion
|
||||||
|
?? statusData.Server?.Version
|
||||||
|
?? statusData.ServerInfo?.Version
|
||||||
|
?? statusData.ServerVersionNumber
|
||||||
|
?? currentVersion;
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
online: true,
|
||||||
|
portainer: {
|
||||||
|
currentVersion: effectiveCurrentVersion,
|
||||||
|
latestVersion: null,
|
||||||
|
updateAvailable: false,
|
||||||
|
edition,
|
||||||
|
build
|
||||||
|
},
|
||||||
|
agent: {
|
||||||
|
url: agentConfig?.agentUrl || null,
|
||||||
|
token: agentConfig?.agentToken || null,
|
||||||
|
online: agentOnline,
|
||||||
|
error: agentError
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_ID_INVALID') {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
if (code === 'API_KEY_REQUIRED' || code === 'SERVER_URL_REQUIRED') {
|
||||||
|
return res.status(400).json({ error: code });
|
||||||
|
}
|
||||||
|
console.error('⚠️ [Setup] Server-Check fehlgeschlagen:', error);
|
||||||
|
return res.status(500).json({ error: 'SERVER_CHECK_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/setup/servers', requirePermission('maintenance-server-edit', 'full'), async (req, res) => {
|
||||||
|
const name = typeof req.body?.name === 'string' ? req.body.name.trim() : '';
|
||||||
|
const urlRaw = typeof req.body?.url === 'string' ? req.body.url.trim() : '';
|
||||||
|
const apiKeyRaw = typeof req.body?.apiKey === 'string'
|
||||||
|
? req.body.apiKey
|
||||||
|
: typeof req.body?.key === 'string'
|
||||||
|
? req.body.key
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const normalizedExternalUrl = normalizeExternalPortainerUrl(urlRaw);
|
||||||
|
if (!normalizedExternalUrl) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_URL_INVALID' });
|
||||||
|
}
|
||||||
|
if (!apiKeyRaw.trim()) {
|
||||||
|
return res.status(400).json({ error: 'API_KEY_REQUIRED' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// verify connectivity
|
||||||
|
const client = createPortainerSetupClient({ baseURL: normalizedExternalUrl, apiKey: apiKeyRaw.trim() });
|
||||||
|
await client.get('/api/status');
|
||||||
|
|
||||||
|
const server = ensureServer({ name, url: normalizedExternalUrl });
|
||||||
|
setServerApiKey({ serverId: server.id, apiKey: apiKeyRaw.trim() });
|
||||||
|
const status = buildSetupStatusResponse();
|
||||||
|
res.status(201).json({ success: true, server, status });
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_URL_REQUIRED' || code === 'SERVER_NAME_REQUIRED') {
|
||||||
|
return res.status(400).json({ error: code });
|
||||||
|
}
|
||||||
|
if (code === 'SERVER_URL_TAKEN') {
|
||||||
|
return res.status(409).json({ error: 'SERVER_URL_TAKEN' });
|
||||||
|
}
|
||||||
|
if (code === 'SERVER_ID_INVALID') {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
if (error.response?.status === 401) {
|
||||||
|
return res.status(401).json({ error: 'API_KEY_INVALID', message: error.response?.data?.message || 'Portainer API-Key ungültig' });
|
||||||
|
}
|
||||||
|
if (error.response?.status === 404) {
|
||||||
|
return res.status(404).json({ error: 'SERVER_UNREACHABLE', message: error.response?.data?.message || 'Server nicht erreichbar' });
|
||||||
|
}
|
||||||
|
console.error('⚠️ [Setup] Server konnte nicht erstellt werden:', error);
|
||||||
|
return res.status(500).json({ error: 'SERVER_CREATE_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/setup/servers/:id/ssh-config', requirePermission('maintenance-ssh-update', 'read'), (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
const config = getPortainerSshConfig(serverId);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
ssh: {
|
||||||
|
host: config.host,
|
||||||
|
port: config.port,
|
||||||
|
username: config.username,
|
||||||
|
extraSshArgs: config.extraSshArgs,
|
||||||
|
passwordStored: Boolean(config.password)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
return res.status(500).json({ error: 'SSH_CONFIG_LOAD_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put('/api/setup/servers/:id/ssh-config', requirePermission('maintenance-ssh-update', 'full'), (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
const config = savePortainerSshConfig(req.body || {}, serverId);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
ssh: {
|
||||||
|
host: config.host,
|
||||||
|
port: config.port,
|
||||||
|
username: config.username,
|
||||||
|
extraSshArgs: config.extraSshArgs,
|
||||||
|
passwordStored: Boolean(config.password)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
console.error('❌ [Setup] Server-spezifische SSH-Konfiguration konnte nicht gespeichert werden:', error);
|
||||||
|
return res.status(400).json({ error: code || 'SSH_CONFIG_SAVE_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.delete('/api/setup/servers/:id/ssh-config', requirePermission('maintenance-ssh-update', 'full'), (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
const config = deletePortainerSshConfig(serverId);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
ssh: {
|
||||||
|
host: config.host,
|
||||||
|
port: config.port,
|
||||||
|
username: config.username,
|
||||||
|
extraSshArgs: config.extraSshArgs,
|
||||||
|
passwordStored: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
console.error('❌ [Setup] Server-spezifische SSH-Konfiguration konnte nicht gelöscht werden:', error);
|
||||||
|
return res.status(500).json({ error: 'SSH_CONFIG_DELETE_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/setup/servers/:id/test-ssh', requirePermission('maintenance-ssh-update', 'full'), async (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
const override = req.body && Object.keys(req.body).length ? req.body : null;
|
||||||
|
const result = await testSshConnection(override, serverId);
|
||||||
|
res.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
console.error('❌ [Setup] SSH Test für Server fehlgeschlagen:', error);
|
||||||
|
res.status(500).json({ error: code || 'SSH_TEST_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/setup/servers/:id/update-script', requirePermission('maintenance-ssh-update', 'read'), async (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
const edition = (await resolveServerEdition(serverId) || '').toLowerCase();
|
||||||
|
const defaultScript = edition.includes('community')
|
||||||
|
? DEFAULT_PORTAINER_UPDATE_SCRIPT_CE
|
||||||
|
: DEFAULT_PORTAINER_UPDATE_SCRIPT_BE;
|
||||||
|
const script = getEffectivePortainerScript(serverId, defaultScript);
|
||||||
|
const custom = getCustomPortainerScript(serverId);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
script: {
|
||||||
|
default: defaultScript,
|
||||||
|
custom: custom?.script ?? null,
|
||||||
|
customUpdatedAt: custom?.updatedAt ?? null,
|
||||||
|
effective: script.script,
|
||||||
|
source: script.source,
|
||||||
|
updatedAt: script.updatedAt
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
console.error('❌ [Setup] Update-Skript konnte nicht geladen werden:', error);
|
||||||
|
res.status(500).json({ error: 'UPDATE_SCRIPT_LOAD_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put('/api/setup/servers/:id/update-script', requirePermission('maintenance-ssh-update', 'full'), async (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
if (portainerUpdateState.running) {
|
||||||
|
return res.status(409).json({ error: 'Aktualisierung läuft. Skript kann derzeit nicht geändert werden.' });
|
||||||
|
}
|
||||||
|
const incoming = req.body?.script;
|
||||||
|
if (typeof incoming !== 'string') {
|
||||||
|
return res.status(400).json({ error: 'Feld "script" (string) wird benötigt.' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
saveCustomPortainerScript(incoming, serverId);
|
||||||
|
const custom = getCustomPortainerScript(serverId);
|
||||||
|
const edition = (await resolveServerEdition(serverId) || '').toLowerCase();
|
||||||
|
const defaultScript = edition.includes('community')
|
||||||
|
? DEFAULT_PORTAINER_UPDATE_SCRIPT_CE
|
||||||
|
: DEFAULT_PORTAINER_UPDATE_SCRIPT_BE;
|
||||||
|
const effective = getEffectivePortainerScript(serverId, defaultScript);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
script: {
|
||||||
|
default: defaultScript,
|
||||||
|
custom: custom?.script ?? null,
|
||||||
|
customUpdatedAt: custom?.updatedAt ?? null,
|
||||||
|
effective: effective.script,
|
||||||
|
source: effective.source,
|
||||||
|
updatedAt: effective.updatedAt
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
console.error('❌ [Setup] Update-Skript konnte nicht gespeichert werden:', error);
|
||||||
|
res.status(400).json({ error: code || 'UPDATE_SCRIPT_SAVE_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.delete('/api/setup/servers/:id/update-script', requirePermission('maintenance-ssh-update', 'full'), async (req, res) => {
|
||||||
|
const serverId = Number(req.params.id);
|
||||||
|
if (!Number.isFinite(serverId)) {
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
}
|
||||||
|
if (portainerUpdateState.running) {
|
||||||
|
return res.status(409).json({ error: 'Aktualisierung läuft. Skript kann derzeit nicht geändert werden.' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getServerById(serverId);
|
||||||
|
saveCustomPortainerScript('', serverId);
|
||||||
|
const edition = (await resolveServerEdition(serverId) || '').toLowerCase();
|
||||||
|
const defaultScript = edition.includes('community')
|
||||||
|
? DEFAULT_PORTAINER_UPDATE_SCRIPT_CE
|
||||||
|
: DEFAULT_PORTAINER_UPDATE_SCRIPT_BE;
|
||||||
|
const effective = getEffectivePortainerScript(serverId, defaultScript);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
script: {
|
||||||
|
default: defaultScript,
|
||||||
|
custom: null,
|
||||||
|
customUpdatedAt: null,
|
||||||
|
effective: effective.script,
|
||||||
|
source: effective.source,
|
||||||
|
updatedAt: effective.updatedAt
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
if (code === 'SERVER_NOT_FOUND') {
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
}
|
||||||
|
console.error('❌ [Setup] Update-Skript konnte nicht gelöscht werden:', error);
|
||||||
|
res.status(400).json({ error: code || 'UPDATE_SCRIPT_DELETE_FAILED' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put('/api/setup/servers/:id', requirePermission('maintenance-server-edit', 'full'), (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
const name = typeof req.body?.name === 'string' ? req.body.name.trim() : '';
|
||||||
|
const url = typeof req.body?.url === 'string' ? req.body.url.trim() : '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const server = updateServerDetails(id, { name, url });
|
||||||
|
const status = buildSetupStatusResponse();
|
||||||
|
res.json({ success: true, server, status });
|
||||||
|
} catch (error) {
|
||||||
|
const code = error.code || error.message;
|
||||||
|
switch (code) {
|
||||||
|
case 'SERVER_ID_INVALID':
|
||||||
|
return res.status(400).json({ error: 'SERVER_ID_INVALID' });
|
||||||
|
case 'SERVER_NOT_FOUND':
|
||||||
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
|
case 'SERVER_URL_REQUIRED':
|
||||||
|
case 'SERVER_NAME_REQUIRED':
|
||||||
|
return res.status(400).json({ error: code });
|
||||||
|
case 'SERVER_URL_TAKEN':
|
||||||
|
return res.status(409).json({ error: 'SERVER_URL_TAKEN' });
|
||||||
|
default:
|
||||||
|
console.error('⚠️ [Setup] Server konnte nicht aktualisiert werden:', error);
|
||||||
|
return res.status(500).json({ error: 'SERVER_UPDATE_FAILED' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.delete('/api/setup/servers/:id', requirePermission('maintenance-server-delete', 'full'), (req, res) => {
|
app.delete('/api/setup/servers/:id', requirePermission('maintenance-server-delete', 'full'), (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const numericId = Number(id);
|
const numericId = Number(id);
|
||||||
@@ -2201,13 +2832,13 @@ app.delete('/api/setup/servers/:id', requirePermission('maintenance-server-delet
|
|||||||
case 'SERVER_NOT_FOUND':
|
case 'SERVER_NOT_FOUND':
|
||||||
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
return res.status(404).json({ error: 'SERVER_NOT_FOUND' });
|
||||||
default:
|
default:
|
||||||
console.error('⚠️ [Setup] Server konnte nicht gelöscht werden:', error);
|
console.error('⚠️ [Setup] Server konnte nicht gelöscht werden:', error);
|
||||||
return res.status(500).json({ error: 'SERVER_DELETE_FAILED' });
|
return res.status(500).json({ error: 'SERVER_DELETE_FAILED' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.put('/api/setup/servers/:id/api-key', requirePermission('maintenance-server-manage', 'full'), (req, res) => {
|
app.put('/api/setup/servers/:id/api-key', requirePermission('maintenance-server-edit', 'full'), (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const numericId = Number(id);
|
const numericId = Number(id);
|
||||||
if (!Number.isFinite(numericId)) {
|
if (!Number.isFinite(numericId)) {
|
||||||
@@ -2234,12 +2865,12 @@ app.put('/api/setup/servers/:id/api-key', requirePermission('maintenance-server-
|
|||||||
return res.status(500).json({ error: 'API_KEY_ENCRYPT_FAILED' });
|
return res.status(500).json({ error: 'API_KEY_ENCRYPT_FAILED' });
|
||||||
default:
|
default:
|
||||||
console.error('⚠️ [Setup] API-Key konnte nicht aktualisiert werden:', error);
|
console.error('⚠️ [Setup] API-Key konnte nicht aktualisiert werden:', error);
|
||||||
return res.status(500).json({ error: 'API_KEY_UPDATE_FAILED' });
|
return res.status(500).json({ error: 'API_KEY_UPDATE_FAILED' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.put('/api/setup/self-stack', requirePermission('maintenance-server-manage', 'full'), (req, res) => {
|
app.put('/api/setup/self-stack', requirePermission('maintenance-server-edit', 'full'), (req, res) => {
|
||||||
const hasPayload = req.body ? Object.prototype.hasOwnProperty.call(req.body, 'selfStackId') : false;
|
const hasPayload = req.body ? Object.prototype.hasOwnProperty.call(req.body, 'selfStackId') : false;
|
||||||
if (!hasPayload) {
|
if (!hasPayload) {
|
||||||
return res.status(400).json({ error: 'SELF_STACK_ID_MISSING' });
|
return res.status(400).json({ error: 'SELF_STACK_ID_MISSING' });
|
||||||
|
|||||||
@@ -267,10 +267,12 @@ export function saveGroupPermissionValues(groupId, values = {}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const serverManageLevel = getSubmittedLevel('maintenance-server-manage');
|
const serverManageLevel = getSubmittedLevel('maintenance-server-manage');
|
||||||
|
const serverEditLevel = getSubmittedLevel('maintenance-server-edit');
|
||||||
const serverDeleteLevel = getSubmittedLevel('maintenance-server-delete');
|
const serverDeleteLevel = getSubmittedLevel('maintenance-server-delete');
|
||||||
|
|
||||||
if (getLevelPriority(serverDeleteLevel) >= getLevelPriority('full') &&
|
if (getLevelPriority(serverDeleteLevel) >= getLevelPriority('full') &&
|
||||||
getLevelPriority(serverManageLevel) < getLevelPriority('full')) {
|
(getLevelPriority(serverManageLevel) < getLevelPriority('full') ||
|
||||||
|
getLevelPriority(serverEditLevel) < getLevelPriority('full'))) {
|
||||||
const error = new Error('PERMISSION_DEPENDENCY_LEVEL');
|
const error = new Error('PERMISSION_DEPENDENCY_LEVEL');
|
||||||
error.code = 'PERMISSION_DEPENDENCY_LEVEL';
|
error.code = 'PERMISSION_DEPENDENCY_LEVEL';
|
||||||
error.permissionKey = 'maintenance-server-delete';
|
error.permissionKey = 'maintenance-server-delete';
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
function $j(e,t){for(var r=0;r<t.length;r++){const n=t[r];if(typeof n!="string"&&!Array.isArray(n)){for(const o in n)if(o!=="default"&&!(o in e)){const a=Object.getOwnPropertyDescriptor(n,o);a&&Object.defineProperty(e,o,a.get?a:{enumerable:!0,get:()=>n[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))n(o);new MutationObserver(o=>{for(const a of o)if(a.type==="childList")for(const i of a.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&n(i)}).observe(document,{childList:!0,subtree:!0});function r(o){const a={};return o.integrity&&(a.integrity=o.integrity),o.referrerPolicy&&(a.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?a.credentials="include":o.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function n(o){if(o.ep)return;o.ep=!0;const a=r(o);fetch(o.href,a)}})();function r_(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function cu(e){if(e.__esModule)return e;var t=e.default;if(typeof t=="function"){var r=function n(){return this instanceof n?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};r.prototype=t.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(e).forEach(function(n){var o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,o.get?o:{enumerable:!0,get:function(){return e[n]}})}),r}var n_={exports:{}},Zd={},o_={exports:{}},kt={};/**
|
||||||
|
* @license React
|
||||||
|
* react.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/var du=Symbol.for("react.element"),Hj=Symbol.for("react.portal"),qj=Symbol.for("react.fragment"),Gj=Symbol.for("react.strict_mode"),Kj=Symbol.for("react.profiler"),Yj=Symbol.for("react.provider"),Qj=Symbol.for("react.context"),Xj=Symbol.for("react.forward_ref"),Zj=Symbol.for("react.suspense"),Jj=Symbol.for("react.memo"),e2=Symbol.for("react.lazy"),fy=Symbol.iterator;function t2(e){return e===null||typeof e!="object"?null:(e=fy&&e[fy]||e["@@iterator"],typeof e=="function"?e:null)}var a_={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},i_=Object.assign,s_={};function Ss(e,t,r){this.props=e,this.context=t,this.refs=s_,this.updater=r||a_}Ss.prototype.isReactComponent={};Ss.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Ss.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function l_(){}l_.prototype=Ss.prototype;function y0(e,t,r){this.props=e,this.context=t,this.refs=s_,this.updater=r||a_}var x0=y0.prototype=new l_;x0.constructor=y0;i_(x0,Ss.prototype);x0.isPureReactComponent=!0;var py=Array.isArray,u_=Object.prototype.hasOwnProperty,w0={current:null},c_={key:!0,ref:!0,__self:!0,__source:!0};function d_(e,t,r){var n,o={},a=null,i=null;if(t!=null)for(n in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(a=""+t.key),t)u_.call(t,n)&&!c_.hasOwnProperty(n)&&(o[n]=t[n]);var u=arguments.length-2;if(u===1)o.children=r;else if(1<u){for(var f=Array(u),g=0;g<u;g++)f[g]=arguments[g+2];o.children=f}if(e&&e.defaultProps)for(n in u=e.defaultProps,u)o[n]===void 0&&(o[n]=u[n]);return{$$typeof:du,type:e,key:a,ref:i,props:o,_owner:w0.current}}function r2(e,t){return{$$typeof:du,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}function _0(e){return typeof e=="object"&&e!==null&&e.$$typeof===du}function n2(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(r){return t[r]})}var hy=/\/+/g;function Dp(e,t){return typeof e=="object"&&e!==null&&e.key!=null?n2(""+e.key):t.toString(36)}function Tc(e,t,r,n,o){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case du:case Hj:i=!0}}if(i)return i=e,o=o(i),e=n===""?"."+Dp(i,0):n,py(o)?(r="",e!=null&&(r=e.replace(hy,"$&/")+"/"),Tc(o,t,r,"",function(g){return g})):o!=null&&(_0(o)&&(o=r2(o,r+(!o.key||i&&i.key===o.key?"":(""+o.key).replace(hy,"$&/")+"/")+e)),t.push(o)),1;if(i=0,n=n===""?".":n+":",py(e))for(var u=0;u<e.length;u++){a=e[u];var f=n+Dp(a,u);i+=Tc(a,t,r,f,o)}else if(f=t2(e),typeof f=="function")for(e=f.call(e),u=0;!(a=e.next()).done;)a=a.value,f=n+Dp(a,u++),i+=Tc(a,t,r,f,o);else if(a==="object")throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return i}function Ku(e,t,r){if(e==null)return e;var n=[],o=0;return Tc(e,n,"","",function(a){return t.call(r,a,o++)}),n}function o2(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r)},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var Yr={current:null},Pc={transition:null},a2={ReactCurrentDispatcher:Yr,ReactCurrentBatchConfig:Pc,ReactCurrentOwner:w0};kt.Children={map:Ku,forEach:function(e,t,r){Ku(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return Ku(e,function(){t++}),t},toArray:function(e){return Ku(e,function(t){return t})||[]},only:function(e){if(!_0(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};kt.Component=Ss;kt.Fragment=qj;kt.Profiler=Kj;kt.PureComponent=y0;kt.StrictMode=Gj;kt.Suspense=Zj;kt.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=a2;kt.cloneElement=function(e,t,r){if(e==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var n=i_({},e.props),o=e.key,a=e.ref,i=e._owner;if(t!=null){if(t.ref!==void 0&&(a=t.ref,i=w0.current),t.key!==void 0&&(o=""+t.key),e.type&&e.type.defaultProps)var u=e.type.defaultProps;for(f in t)u_.call(t,f)&&!c_.hasOwnProperty(f)&&(n[f]=t[f]===void 0&&u!==void 0?u[f]:t[f])}var f=arguments.length-2;if(f===1)n.children=r;else if(1<f){u=Array(f);for(var g=0;g<f;g++)u[g]=arguments[g+2];n.children=u}return{$$typeof:du,type:e.type,key:o,ref:a,props:n,_owner:i}};kt.createContext=function(e){return e={$$typeof:Qj,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null},e.Provider={$$typeof:Yj,_conLine truncated
|
||||||
|
* @license React
|
||||||
|
* react-jsx-runtime.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/var i2=P,s2=Symbol.for("react.element"),l2=Symbol.for("react.fragment"),u2=Object.prototype.hasOwnProperty,c2=i2.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,d2={key:!0,ref:!0,__self:!0,__source:!0};function f_(e,t,r){var n,o={},a=null,i=null;r!==void 0&&(a=""+r),t.key!==void 0&&(a=""+t.key),t.ref!==void 0&&(i=t.ref);for(n in t)u2.call(t,n)&&!d2.hasOwnProperty(n)&&(o[n]=t[n]);if(e&&e.defaultProps)for(n in t=e.defaultProps,t)o[n]===void 0&&(o[n]=t[n]);return{$$typeof:s2,type:e,key:a,ref:i,props:o,_owner:c2.current}}Zd.Fragment=l2;Zd.jsx=f_;Zd.jsxs=f_;n_.exports=Zd;var v=n_.exports;function p_(e,t){return function(){return e.apply(t,arguments)}}const{toString:f2}=Object.prototype,{getPrototypeOf:C0}=Object,Jd=(e=>t=>{const r=f2.call(t);return e[r]||(e[r]=r.slice(8,-1).toLowerCase())})(Object.create(null)),mo=e=>(e=e.toLowerCase(),t=>Jd(t)===e),ef=e=>t=>typeof t===e,{isArray:Cs}=Array,Dl=ef("undefined");function p2(e){return e!==null&&!Dl(e)&&e.constructor!==null&&!Dl(e.constructor)&&yn(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const h_=mo("ArrayBuffer");function h2(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&h_(e.buffer),t}const g2=ef("string"),yn=ef("function"),g_=ef("number"),tf=e=>e!==null&&typeof e=="object",m2=e=>e===!0||e===!1,Oc=e=>{if(Jd(e)!=="object")return!1;const t=C0(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)},b2=mo("Date"),v2=mo("File"),y2=mo("Blob"),x2=mo("FileList"),w2=e=>tf(e)&&yn(e.pipe),_2=e=>{let t;return e&&(typeof FormData=="function"&&e instanceof FormData||yn(e.append)&&((t=Jd(e))==="formdata"||t==="object"&&yn(e.toString)&&e.toString()==="[object FormData]"))},S2=mo("URLSearchParams"),[C2,T2,P2,O2]=["ReadableStream","Request","Response","Headers"].map(mo),k2=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function fu(e,t,{allOwnKeys:r=!1}={}){if(e===null||typeof e>"u")return;let n,o;if(typeof e!="object"&&(e=[e]),Cs(e))for(n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else{const a=r?Object.getOwnPropertyNames(e):Object.keys(e),i=a.length;let u;for(n=0;n<i;n++)u=a[n],t.call(null,e[u],u,e)}}function m_(e,t){t=t.toLowerCase();const r=Object.keys(e);let n=r.length,o;for(;n-- >0;)if(o=r[n],t===o.toLowerCase())return o;return null}const Xa=(()=>typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global)(),b_=e=>!Dl(e)&&e!==Xa;function zh(){const{caseless:e}=b_(this)&&this||{},t={},r=(n,o)=>{const a=e&&m_(t,o)||o;Oc(t[a])&&Oc(n)?t[a]=zh(t[a],n):Oc(n)?t[a]=zh({},n):Cs(n)?t[a]=n.slice():t[a]=n};for(let n=0,o=arguments.length;n<o;n++)arguments[n]&&fu(arguments[n],r);return t}const N2=(e,t,r,{allOwnKeys:n}={})=>(fu(t,(o,a)=>{r&&yn(o)?e[a]=p_(o,r):e[a]=o},{allOwnKeys:n}),e),E2=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),j2=(e,t,r,n)=>{e.prototype=Object.create(t.prototype,n),e.prototype.constructor=e,Object.defineProperty(e,"super",{value:t.prototype}),r&&Object.assign(e.prototype,r)},A2=(e,t,r,n)=>{let o,a,i;const u={};if(t=t||{},e==null)return t;do{for(o=Object.getOwnPropertyNames(e),a=o.length;a-- >0;)i=o[a],(!n||n(i,e,t))&&!u[i]&&(t[i]=e[i],u[i]=!0);e=r!==!1&&C0(e)}while(e&&(!r||r(e,t))&&e!==Object.prototype);return t},R2=(e,t,r)=>{e=String(e),(r===void 0||r>e.length)&&(r=e.length),r-=t.length;const n=e.indexOf(t,r);return n!==-1&&n===r},M2=e=>{if(!e)return null;if(Cs(e))return e;let t=e.length;if(!g_(t))return null;const r=new Array(t);for(;t-- >0;)r[t]=e[t];return r},I2=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&C0(Uint8Array)),D2=(e,t)=>{const n=(e&&e[Symbol.iterator]).call(e);let o;for(;(o=n.next())&&!o.done;){const a=o.value;t.call(e,a[0],a[1])}},L2=(e,t)=>{let r;const n=[];for(;(r=e.exec(t))!==null;)n.push(r);return n},F2=mo("HTMLFormElement"),z2=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(r,n,o){return n.toUpperCase()+o}),gy=(({hasOwnProperty:e})=>(t,r)=>e.call(t,r))(Object.prototype),B2=mo("RegExp"),v_=(e,t)=>{const r=Object.getOwnPropertyDescriptors(e),n={};fu(r,(o,a)=>{let i;(i=t(o,a,e))!==!1&&(n[a]=i||o)}),Object.defineProperties(e,n)},V2=e=>{v_(e,(t,r)=>{if(yn(e)&&["arguments","caller","callee"].indexOf(r)!==-1)return!1;const n=e[r];if(yn(n)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+r+"'")})}})},U2=(e,t)=>{const r={},n=o=>{o.forEach(a=>{r[a]=!0})};return Cs(e)?n(e):n(String(e).split(t)),r},W2=()=>{},$2=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t,Lp="abcdefghijklmnopqrstuvwxyz",my="0123456789",y_={DIGIT:my,ALPHA:Lp,ALPHA_DIGIT:Lp+Lp.toUpperCase()+my},H2=(e=16,t=y_.ALPHA_DIGIT)=>{let r="";const{length:n}=t;for(;e--;)r+=t[Math.random()*n|0];return r};function q2(e){return!!(e&&yn(e.append)&&e[Symbol.toStringTag]==="FormData"&&e[Symbol.iterator])}const G2=e=>{const t=new Array(10),r=(n,o)=>{if(tf(n)){if(t.indexOf(n)>=0)return;if(!("toJSON"in n)){t[o]=n;const a=CLine truncated
|
||||||
|
`).forEach(function(i){o=i.indexOf(":"),r=i.substring(0,o).trim().toLowerCase(),n=i.substring(o+1).trim(),!(!r||t[r]&&hA[r])&&(r==="set-cookie"?t[r]?t[r].push(n):t[r]=[n]:t[r]=t[r]?t[r]+", "+n:n)}),t},xy=Symbol("internals");function rl(e){return e&&String(e).trim().toLowerCase()}function kc(e){return e===!1||e==null?e:Se.isArray(e)?e.map(kc):String(e)}function mA(e){const t=Object.create(null),r=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let n;for(;n=r.exec(e);)t[n[1]]=n[2];return t}const bA=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function Fp(e,t,r,n,o){if(Se.isFunction(n))return n.call(this,t,r);if(o&&(t=r),!!Se.isString(t)){if(Se.isString(n))return t.indexOf(n)!==-1;if(Se.isRegExp(n))return n.test(t)}}function vA(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,r,n)=>r.toUpperCase()+n)}function yA(e,t){const r=Se.toCamelCase(" "+t);["get","set","has"].forEach(n=>{Object.defineProperty(e,n+r,{value:function(o,a,i){return this[n].call(this,t,o,a,i)},configurable:!0})})}class nf{constructor(t){t&&this.set(t)}set(t,r,n){const o=this;function a(u,f,g){const m=rl(f);if(!m)throw new Error("header name must be a non-empty string");const S=Se.findKey(o,m);(!S||o[S]===void 0||g===!0||g===void 0&&o[S]!==!1)&&(o[S||f]=kc(u))}const i=(u,f)=>Se.forEach(u,(g,m)=>a(g,m,f));if(Se.isPlainObject(t)||t instanceof this.constructor)i(t,r);else if(Se.isString(t)&&(t=t.trim())&&!bA(t))i(gA(t),r);else if(Se.isHeaders(t))for(const[u,f]of t.entries())a(f,u,n);else t!=null&&a(r,t,n);return this}get(t,r){if(t=rl(t),t){const n=Se.findKey(this,t);if(n){const o=this[n];if(!r)return o;if(r===!0)return mA(o);if(Se.isFunction(r))return r.call(this,o,n);if(Se.isRegExp(r))return r.exec(o);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,r){if(t=rl(t),t){const n=Se.findKey(this,t);return!!(n&&this[n]!==void 0&&(!r||Fp(this,this[n],n,r)))}return!1}delete(t,r){const n=this;let o=!1;function a(i){if(i=rl(i),i){const u=Se.findKey(n,i);u&&(!r||Fp(n,n[u],u,r))&&(delete n[u],o=!0)}}return Se.isArray(t)?t.forEach(a):a(t),o}clear(t){const r=Object.keys(this);let n=r.length,o=!1;for(;n--;){const a=r[n];(!t||Fp(this,this[a],a,t,!0))&&(delete this[a],o=!0)}return o}normalize(t){const r=this,n={};return Se.forEach(this,(o,a)=>{const i=Se.findKey(n,a);if(i){r[i]=kc(o),delete r[a];return}const u=t?vA(a):String(a).trim();u!==a&&delete r[a],r[u]=kc(o),n[u]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const r=Object.create(null);return Se.forEach(this,(n,o)=>{n!=null&&n!==!1&&(r[o]=t&&Se.isArray(n)?n.join(", "):n)}),r}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,r])=>t+": "+r).join(`
|
||||||
|
`)}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...r){const n=new this(t);return r.forEach(o=>n.set(o)),n}static accessor(t){const n=(this[xy]=this[xy]={accessors:{}}).accessors,o=this.prototype;function a(i){const u=rl(i);n[u]||(yA(o,i),n[u]=!0)}return Se.isArray(t)?t.forEach(a):a(t),this}}nf.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);Se.reduceDescriptors(nf.prototype,({value:e},t)=>{let r=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(n){this[r]=n}}});Se.freezeMethods(nf);const io=nf;function zp(e,t){const r=this||k0,n=t||r,o=io.from(n.headers);let a=n.data;return Se.forEach(e,function(u){a=u.call(r,a,o.normalize(),t?t.status:void 0)}),o.normalize(),a}function k_(e){return!!(e&&e.__CANCEL__)}function Ts(e,t,r){St.call(this,e??"canceled",St.ERR_CANCELED,t,r),this.name="CanceledError"}Se.inherits(Ts,St,{__CANCEL__:!0});function N_(e,t,r){const n=r.config.validateStatus;!r.status||!n||n(r.status)?e(r):t(new St("Request failed with status code "+r.status,[St.ERR_BAD_REQUEST,St.ERR_BAD_RESPONSE][Math.floor(r.status/100)-4],r.config,r.request,r))}function xA(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function wA(e,t){e=e||10;const r=new Array(e),n=new Array(e);let o=0,a=0,i;return t=t!==void 0?t:1e3,function(f){const g=Date.now(),m=n[a];i||(i=g),r[o]=f,n[o]=g;let S=a,O=0;for(;S!==o;)O+=r[S++],S=S%e;if(o=(o+1)%e,o===a&&(a=(a+1)%e),g-i<t)return;const T=m&&g-m;return T?Math.round(O*1e3/T):void 0}}function _A(e,t){let r=0,n=1e3/t,o,a;const i=(g,m=Date.now())=>{r=m,o=null,a&&(clearTimeout(a),a=null),e.apply(null,g)};return[(...g)=>{const m=Date.now(),S=m-r;S>=n?i(g,m):(o=g,a||(a=setTimeout(()=>{a=null,i(o)},n-S)))},()=>o&&i(o)]}const rd=(e,t,r=3)=>{let n=0;const o=wA(50,250);return _A(a=>{const i=a.loaded,u=a.lengthComputable?a.total:void 0,f=i-n,g=o(f),m=i<=u;n=i;const S={loaded:i,total:u,progress:u?i/u:void 0,bytes:f,rate:g||void 0,estimated:g&&u&&m?(u-i)/g:void 0,event:a,lengthComputable:u!=null,[t?"download":"upload"]:!0};e(S)},r)},wy=(e,t)=>{const r=e!=null;return[n=>t[0]({lengthComputable:r,total:e,loaded:n}),t[1]]},_y=e=>(...t)=>Se.asap(()=>e(...t)),SA=xn.hasStandardBrowserEnv?function(){const t=xn.navigator&&/(msie|trident)/i.test(xn.navigator.userAgent),r=document.createElement("a");let n;function o(a){let i=a;return t&&(r.setAttribute("href",i),i=r.href),r.setAttribute("href",i),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,""):"",host:r.host,search:r.search?r.search.replace(/^\?/,""):"",hash:r.hash?r.hash.replace(/^#/,""):"",hostname:r.hostname,port:r.port,pathname:r.pathname.charAt(0)==="/"?r.pathname:"/"+r.pathname}}return n=o(window.location.href),function(i){const u=Se.isString(i)?o(i):i;return u.protocol===n.protocol&&u.host===n.host}}():function(){return function(){return!0}}(),CA=xn.hasStandardBrowserEnv?{write(e,t,r,n,o,a){const i=[e+"="+encodeURIComponent(t)];Se.isNumber(r)&&i.push("expires="+new Date(r).toGMTString()),Se.isString(n)&&i.push("path="+n),Se.isString(o)&&i.push("domain="+o),a===!0&&i.push("secure"),document.cookie=i.join("; ")},read(e){const t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove(e){this.write(e,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function TA(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function PA(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function E_(e,t){return e&&!TA(t)?PA(e,t):t}const Sy=e=>e instanceof io?{...e}:e;function ai(e,t){t=t||{};const r={};function n(g,m,S){return Se.isPlainObject(g)&&Se.isPlainObject(m)?Se.merge.call({caseless:S},g,m):Se.isPlainObject(m)?Se.merge({},m):Se.isArray(m)?m.slice():m}function o(g,m,S){if(Se.isUndefined(m)){if(!Se.isUndefined(g))return n(void 0,g,S)}else return n(g,m,S)}function a(g,m){if(!Se.isUndefined(m))return n(void 0,m)}function i(g,m){if(Se.isUndefined(m)){if(!Se.isUndefined(g))return n(void 0,g)}else return n(void 0,m)}function u(g,m,S){if(S in t)return n(g,m);if(S in e)return n(void 0,g)}const f={url:a,method:a,data:a,baseURL:i,transformRequest:i,transformResponse:i,paramsSerializer:i,timeout:i,timeoutMessage:i,withCredentials:i,withXSRFToken:i,adapter:i,responseType:i,xsrfCookieName:i,xsrfHeaderName:i,onUploadProgress:i,onDownloadProgress:i,decompress:i,maxContentLength:i,maxBodyLength:i,beforeRedirect:i,transport:i,httpAgent:i,httpsAgent:i,cancelToken:i,socketPath:i,responseEncoding:i,validateStatus:u,headers:(g,m)=>o(Sy(g),Sy(m),!0)};return Se.forEach(Object.keys(Object.assign({},e,t)),function(m){const S=f[m]||o,O=S(e[m],t[m],m);Se.isUndefined(O)&&S!==u||(r[m]=O)}),r}const j_=e=>{const t=ai({},e);let{data:r,withXSRFToken:n,xsrfHeaderName:o,xsrfCookieName:a,headers:i,auth:u}=t;t.headers=i=io.from(i),t.url=T_(E_(t.baseURL,t.url),e.params,e.paramsSerializer),u&&i.set("Authorization","Basic "+btoa((u.username||"")+":"+(u.password?unescape(enco
Line truncated
|
||||||
|
`+a.map(Py).join(`
|
||||||
|
`):" "+Py(a[0]):"as no adapter specified";throw new St("There is no suitable adapter to dispatch the request "+i,"ERR_NOT_SUPPORT")}return n},adapters:$h};function Bp(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new Ts(null,e)}function Oy(e){return Bp(e),e.headers=io.from(e.headers),e.data=zp.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),M_.getAdapter(e.adapter||k0.adapter)(e).then(function(n){return Bp(e),n.data=zp.call(e,e.transformResponse,n),n.headers=io.from(n.headers),n},function(n){return k_(n)||(Bp(e),n&&n.response&&(n.response.data=zp.call(e,e.transformResponse,n.response),n.response.headers=io.from(n.response.headers))),Promise.reject(n)})}const I_="1.7.5",N0={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{N0[e]=function(n){return typeof n===e||"a"+(t<1?"n ":" ")+e}});const ky={};N0.transitional=function(t,r,n){function o(a,i){return"[Axios v"+I_+"] Transitional option '"+a+"'"+i+(n?". "+n:"")}return(a,i,u)=>{if(t===!1)throw new St(o(i," has been removed"+(r?" in "+r:"")),St.ERR_DEPRECATED);return r&&!ky[i]&&(ky[i]=!0,console.warn(o(i," has been deprecated since v"+r+" and will be removed in the near future"))),t?t(a,i,u):!0}};function FA(e,t,r){if(typeof e!="object")throw new St("options must be an object",St.ERR_BAD_OPTION_VALUE);const n=Object.keys(e);let o=n.length;for(;o-- >0;){const a=n[o],i=t[a];if(i){const u=e[a],f=u===void 0||i(u,a,e);if(f!==!0)throw new St("option "+a+" must be "+f,St.ERR_BAD_OPTION_VALUE);continue}if(r!==!0)throw new St("Unknown option "+a,St.ERR_BAD_OPTION)}}const Hh={assertOptions:FA,validators:N0},ua=Hh.validators;class od{constructor(t){this.defaults=t,this.interceptors={request:new yy,response:new yy}}async request(t,r){try{return await this._request(t,r)}catch(n){if(n instanceof Error){let o;Error.captureStackTrace?Error.captureStackTrace(o={}):o=new Error;const a=o.stack?o.stack.replace(/^.+\n/,""):"";try{n.stack?a&&!String(n.stack).endsWith(a.replace(/^.+\n.+\n/,""))&&(n.stack+=`
|
||||||
|
`+a):n.stack=a}catch{}}throw n}}_request(t,r){typeof t=="string"?(r=r||{},r.url=t):r=t||{},r=ai(this.defaults,r);const{transitional:n,paramsSerializer:o,headers:a}=r;n!==void 0&&Hh.assertOptions(n,{silentJSONParsing:ua.transitional(ua.boolean),forcedJSONParsing:ua.transitional(ua.boolean),clarifyTimeoutError:ua.transitional(ua.boolean)},!1),o!=null&&(Se.isFunction(o)?r.paramsSerializer={serialize:o}:Hh.assertOptions(o,{encode:ua.function,serialize:ua.function},!0)),r.method=(r.method||this.defaults.method||"get").toLowerCase();let i=a&&Se.merge(a.common,a[r.method]);a&&Se.forEach(["delete","get","head","post","put","patch","common"],C=>{delete a[C]}),r.headers=io.concat(i,a);const u=[];let f=!0;this.interceptors.request.forEach(function(w){typeof w.runWhen=="function"&&w.runWhen(r)===!1||(f=f&&w.synchronous,u.unshift(w.fulfilled,w.rejected))});const g=[];this.interceptors.response.forEach(function(w){g.push(w.fulfilled,w.rejected)});let m,S=0,O;if(!f){const C=[Oy.bind(this),void 0];for(C.unshift.apply(C,u),C.push.apply(C,g),O=C.length,m=Promise.resolve(r);S<O;)m=m.then(C[S++],C[S++]);return m}O=u.length;let T=r;for(S=0;S<O;){const C=u[S++],w=u[S++];try{T=C(T)}catch(b){w.call(this,b);break}}try{m=Oy.call(this,T)}catch(C){return Promise.reject(C)}for(S=0,O=g.length;S<O;)m=m.then(g[S++],g[S++]);return m}getUri(t){t=ai(this.defaults,t);const r=E_(t.baseURL,t.url);return T_(r,t.params,t.paramsSerializer)}}Se.forEach(["delete","get","head","options"],function(t){od.prototype[t]=function(r,n){return this.request(ai(n||{},{method:t,url:r,data:(n||{}).data}))}});Se.forEach(["post","put","patch"],function(t){function r(n){return function(a,i,u){return this.request(ai(u||{},{method:t,headers:n?{"Content-Type":"multipart/form-data"}:{},url:a,data:i}))}}od.prototype[t]=r(),od.prototype[t+"Form"]=r(!0)});const Nc=od;class E0{constructor(t){if(typeof t!="function")throw new TypeError("executor must be a function.");let r;this.promise=new Promise(function(a){r=a});const n=this;this.promise.then(o=>{if(!n._listeners)return;let a=n._listeners.length;for(;a-- >0;)n._listeners[a](o);n._listeners=null}),this.promise.then=o=>{let a;const i=new Promise(u=>{n.subscribe(u),a=u}).then(o);return i.cancel=function(){n.unsubscribe(a)},i},t(function(a,i,u){n.reason||(n.reason=new Ts(a,i,u),r(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const r=this._listeners.indexOf(t);r!==-1&&this._listeners.splice(r,1)}static source(){let t;return{token:new E0(function(o){t=o}),cancel:t}}}const zA=E0;function BA(e){return function(r){return e.apply(null,r)}}function VA(e){return Se.isObject(e)&&e.isAxiosError===!0}const qh={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(qh).forEach(([e,t])=>{qh[t]=e});const UA=qh;function D_(e){const t=new Nc(e),r=p_(Nc.prototype.request,t);return Se.extend(r,Nc.prototype,t,{allOwnKeys:!0}),Se.extend(r,t,null,{allOwnKeys:!0}),r.create=function(o){return D_(ai(e,o))},r}const gr=D_(k0);gr.Axios=Nc;gr.CanceledError=Ts;gr.CancelToken=zA;gr.isCancel=k_;gr.VERSION=I_;gr.toFormData=rf;gr.AxiosError=St;gr.Cancel=gr.CanceledError;gr.all=function(t){return Promise.all(t)};gr.spread=BA;gr.isAxiosError=VA;gr.mergeConfig=ai;gr.AxiosHeaders=io;gr.formToJSON=e=>O_(Se.isHTMLForm(e)?new FormData(e):e);gr.getAdapter=M_.getAdapter;gr.HttpStatusCode=UA;gr.default=gr;const Je=gr;var Gh={},L_={exports:{}},Tn={},F_={exports:{}},z_={};/**
|
||||||
|
* @license React
|
||||||
|
* scheduler.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/(function(e){function t(q,B){var H=q.length;q.push(B);e:for(;0<H;){var K=H-1>>>1,X=q[K];if(0<o(X,B))q[K]=B,q[H]=X,H=K;else break e}}function r(q){return q.length===0?null:q[0]}function n(q){if(q.length===0)return null;var B=q[0],H=q.pop();if(H!==B){q[0]=H;e:for(var K=0,X=q.length,re=X>>>1;K<re;){var me=2*(K+1)-1,de=q[me],ee=me+1,_e=q[ee];if(0>o(de,H))ee<X&&0>o(_e,de)?(q[K]=_e,q[ee]=H,K=ee):(q[K]=de,q[me]=H,K=me);else if(ee<X&&0>o(_e,H))q[K]=_e,q[ee]=H,K=ee;else break e}}return B}function o(q,B){var H=q.sortIndex-B.sortIndex;return H!==0?H:q.id-B.id}if(typeof performance=="object"&&typeof performance.now=="function"){var a=performance;e.unstable_now=function(){return a.now()}}else{var i=Date,u=i.now();e.unstable_now=function(){return i.now()-u}}var f=[],g=[],m=1,S=null,O=3,T=!1,C=!1,w=!1,b=typeof setTimeout=="function"?setTimeout:null,d=typeof clearTimeout=="function"?clearTimeout:null,s=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function c(q){for(var B=r(g);B!==null;){if(B.callback===null)n(g);else if(B.startTime<=q)n(g),B.sortIndex=B.expirationTime,t(f,B);else break;B=r(g)}}function l(q){if(w=!1,c(q),!C)if(r(f)!==null)C=!0,V(h);else{var B=r(g);B!==null&&Y(l,B.startTime-q)}}function h(q,B){C=!1,w&&(w=!1,d(j),j=-1),T=!0;var H=O;try{for(c(B),S=r(f);S!==null&&(!(S.expirationTime>B)||q&&!A());){var K=S.callback;if(typeof K=="function"){S.callback=null,O=S.priorityLevel;var X=K(S.expirationTime<=B);B=e.unstable_now(),typeof X=="function"?S.callback=X:S===r(f)&&n(f),c(B)}else n(f);S=r(f)}if(S!==null)var re=!0;else{var me=r(g);me!==null&&Y(l,me.startTime-B),re=!1}return re}finally{S=null,O=H,T=!1}}var y=!1,x=null,j=-1,k=5,N=-1;function A(){return!(e.unstable_now()-N<k)}function M(){if(x!==null){var q=e.unstable_now();N=q;var B=!0;try{B=x(!0,q)}finally{B?D():(y=!1,x=null)}}else y=!1}var D;if(typeof s=="function")D=function(){s(M)};else if(typeof MessageChannel<"u"){var L=new MessageChannel,z=L.port2;L.port1.onmessage=M,D=function(){z.postMessage(null)}}else D=function(){b(M,0)};function V(q){x=q,y||(y=!0,D())}function Y(q,B){j=b(function(){q(e.unstable_now())},B)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(q){q.callback=null},e.unstable_continueExecution=function(){C||T||(C=!0,V(h))},e.unstable_forceFrameRate=function(q){0>q||125<q?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):k=0<q?Math.floor(1e3/q):5},e.unstable_getCurrentPriorityLevel=function(){return O},e.unstable_getFirstCallbackNode=function(){return r(f)},e.unstable_next=function(q){switch(O){case 1:case 2:case 3:var B=3;break;default:B=O}var H=O;O=B;try{return q()}finally{O=H}},e.unstable_pauseExecution=function(){},e.unstable_requestPaint=function(){},e.unstable_runWithPriority=function(q,B){switch(q){case 1:case 2:case 3:case 4:case 5:break;default:q=3}var H=O;O=q;try{return B()}finally{O=H}},e.unstable_scheduleCallback=function(q,B,H){var K=e.unstable_now();switch(typeof H=="object"&&H!==null?(H=H.delay,H=typeof H=="number"&&0<H?K+H:K):H=K,q){case 1:var X=-1;break;case 2:X=250;break;case 5:X=1073741823;break;case 4:X=1e4;break;default:X=5e3}return X=H+X,q={id:m++,callback:B,priorityLevel:q,startTime:H,expirationTime:X,sortIndex:-1},H>K?(q.sortIndex=H,t(g,q),r(f)===null&&q===r(g)&&(w?(d(j),j=-1):w=!0,Y(l,H-K))):(q.sortIndex=X,t(f,q),C||T||(C=!0,V(h))),q},e.unstable_shouldYield=A,e.unstable_wrapCallback=function(q){var B=O;return function(){var H=O;O=B;try{return q.apply(this,arguments)}finally{O=H}}}})(z_);F_.exports=z_;var WA=F_.exports;/**
|
||||||
|
* @license React
|
||||||
|
* react-dom.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/var B_=P,Sn=WA;function Me(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=1;r<arguments.length;r++)t+="&args[]="+encodeURIComponent(arguments[r]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var V_=new Set,Ll={};function gi(e,t){ss(e,t),ss(e+"Capture",t)}function ss(e,t){for(Ll[e]=t,e=0;e<t.length;e++)V_.add(t[e])}var Ho=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Kh=Object.prototype.hasOwnProperty,$A=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Ny={},Ey={};function HA(e){return Kh.call(Ey,e)?!0:Kh.call(Ny,e)?!1:$A.test(e)?Ey[e]=!0:(Ny[e]=!0,!1)}function qA(e,t,r,n){if(r!==null&&r.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return n?!1:r!==null?!r.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function GA(e,t,r,n){if(t===null||typeof t>"u"||qA(e,t,r,n))return!0;if(n)return!1;if(r!==null)switch(r.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Qr(e,t,r,n,o,a,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=n,this.attributeNamespace=o,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=i}var Rr={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Rr[e]=new Qr(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Rr[t]=new Qr(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Rr[e]=new Qr(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Rr[e]=new Qr(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Rr[e]=new Qr(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Rr[e]=new Qr(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Rr[e]=new Qr(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Rr[e]=new Qr(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Rr[e]=new Qr(e,5,!1,e.toLowerCase(),null,!1,!1)});var j0=/[\-:]([a-z])/g;function A0(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(j0,A0);Rr[t]=new Qr(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(j0,A0);Rr[t]=new Qr(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(j0,A0);Rr[t]=new Qr(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Rr[e]=new Qr(e,1,!1,e.toLowerCase(),null,!1,!1)});Rr.xlinkHref=new Qr("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Rr[e]=new Qr(e,1,!1,e.toLowerCase(),null,!0,!0)});function R0(e,t,r,n){var o=Rr.hasOwnProperty(t)?Rr[t]:null;(o!==null?o.type!==0:n||!(2<t.length)||t[0]!=="o"&&t[0]!==
Line truncated
|
||||||
|
`+Vp+e}var Up=!1;function Wp(e,t){if(!e||Up)return"";Up=!0;var r=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(t,[])}catch(g){var n=g}Reflect.construct(e,[],t)}else{try{t.call()}catch(g){n=g}e.call(t.prototype)}else{try{throw Error()}catch(g){n=g}e()}}catch(g){if(g&&n&&typeof g.stack=="string"){for(var o=g.stack.split(`
|
||||||
|
`),a=n.stack.split(`
|
||||||
|
`),i=o.length-1,u=a.length-1;1<=i&&0<=u&&o[i]!==a[u];)u--;for(;1<=i&&0<=u;i--,u--)if(o[i]!==a[u]){if(i!==1||u!==1)do if(i--,u--,0>u||o[i]!==a[u]){var f=`
|
||||||
|
`+o[i].replace(" at new "," at ");return e.displayName&&f.includes("<anonymous>")&&(f=f.replace("<anonymous>",e.displayName)),f}while(1<=i&&0<=u);break}}}finally{Up=!1,Error.prepareStackTrace=r}return(e=e?e.displayName||e.name:"")?gl(e):""}function KA(e){switch(e.tag){case 5:return gl(e.type);case 16:return gl("Lazy");case 13:return gl("Suspense");case 19:return gl("SuspenseList");case 0:case 2:case 15:return e=Wp(e.type,!1),e;case 11:return e=Wp(e.type.render,!1),e;case 1:return e=Wp(e.type,!0),e;default:return""}}function Zh(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Li:return"Fragment";case Di:return"Portal";case Yh:return"Profiler";case M0:return"StrictMode";case Qh:return"Suspense";case Xh:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case W_:return(e.displayName||"Context")+".Consumer";case U_:return(e._context.displayName||"Context")+".Provider";case I0:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case D0:return t=e.displayName||null,t!==null?t:Zh(e.type)||"Memo";case ga:t=e._payload,e=e._init;try{return Zh(e(t))}catch{}}return null}function YA(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Zh(t);case 8:return t===M0?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ia(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function H_(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function QA(e){var t=H_(e)?"checked":"value",r=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),n=""+e[t];if(!e.hasOwnProperty(t)&&typeof r<"u"&&typeof r.get=="function"&&typeof r.set=="function"){var o=r.get,a=r.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(i){n=""+i,a.call(this,i)}}),Object.defineProperty(e,t,{enumerable:r.enumerable}),{getValue:function(){return n},setValue:function(i){n=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Qu(e){e._valueTracker||(e._valueTracker=QA(e))}function q_(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var r=t.getValue(),n="";return e&&(n=H_(e)?e.checked?"true":"false":e.value),e=n,e!==r?(t.setValue(e),!0):!1}function ad(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Jh(e,t){var r=t.checked;return lr({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:r??e._wrapperState.initialChecked})}function Ay(e,t){var r=t.defaultValue==null?"":t.defaultValue,n=t.checked!=null?t.checked:t.defaultChecked;r=Ia(t.value!=null?t.value:r),e._wrapperState={initialChecked:n,initialValue:r,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function G_(e,t){t=t.checked,t!=null&&R0(e,"checked",t,!1)}function eg(e,t){G_(e,t);var r=Ia(t.value),n=t.type;if(r!=null)n==="number"?(r===0&&e.value===""||e.value!=r)&&(e.value=""+r):e.value!==""+r&&(e.value=""+r);else if(n==="submit"||n==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?tg(e,t.type,r):t.hasOwnProperty("defaultValue")&&tg(e,t.type,Ia(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Ry(e,t,r){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var n=t.type;if(!(n!=="submit"&&n!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,r||t===e.value||(e.value=t),e.defaultValue=t}r=e.name,r!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,r!==""&&(e.name=r)}function tg(e,t,r){(t!=="number"||ad(e.ownerDocument)!==e)&&(r==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+r&&(e.defaultValue=""+r))}var ml=Array.isArray;function Qi(e,t,r,n){if(e=e.options,t){t={};for(var o=0;o<r.length;o++)t["$"+r[o]]=!0;for(r=0;r<e.length;r++)o=t.hasOwnProperty("$"+e[r].value),e[r].selected!==o&&(e[r].selected=o),o&&n&&(e[r].defaultSelected=!0)}else{for(r=""+Ia(r),t=null,o=0;o<e.length;o++){if(e[o].value===r){e[o].selected=!0,n&&(e[o].defaultSelected=!0);return}t!==null||e[o].disabled||(t=e[o])}t!==null&&(t.selected=!0)}}function rg(e,t){if(t.dan
Line truncated
|
||||||
|
`).replace(iM,"")}function oc(e,t,r){if(t=rx(t),rx(e)!==t&&r)throw Error(Me(425))}function pd(){}var gg=null,mg=null;function bg(e,t){return e==="textarea"||e==="noscript"||typeof t.children=="string"||typeof t.children=="number"||typeof t.dangerouslySetInnerHTML=="object"&&t.dangerouslySetInnerHTML!==null&&t.dangerouslySetInnerHTML.__html!=null}var vg=typeof setTimeout=="function"?setTimeout:void 0,sM=typeof clearTimeout=="function"?clearTimeout:void 0,nx=typeof Promise=="function"?Promise:void 0,lM=typeof queueMicrotask=="function"?queueMicrotask:typeof nx<"u"?function(e){return nx.resolve(null).then(e).catch(uM)}:vg;function uM(e){setTimeout(function(){throw e})}function rh(e,t){var r=t,n=0;do{var o=r.nextSibling;if(e.removeChild(r),o&&o.nodeType===8)if(r=o.data,r==="/$"){if(n===0){e.removeChild(o),Ul(t);return}n--}else r!=="$"&&r!=="$?"&&r!=="$!"||n++;r=o}while(r);Ul(t)}function Oa(e){for(;e!=null;e=e.nextSibling){var t=e.nodeType;if(t===1||t===3)break;if(t===8){if(t=e.data,t==="$"||t==="$!"||t==="$?")break;if(t==="/$")return null}}return e}function ox(e){e=e.previousSibling;for(var t=0;e;){if(e.nodeType===8){var r=e.data;if(r==="$"||r==="$!"||r==="$?"){if(t===0)return e;t--}else r==="/$"&&t++}e=e.previousSibling}return null}var Os=Math.random().toString(36).slice(2),Po="__reactFiber$"+Os,Gl="__reactProps$"+Os,qo="__reactContainer$"+Os,yg="__reactEvents$"+Os,cM="__reactListeners$"+Os,dM="__reactHandles$"+Os;function Za(e){var t=e[Po];if(t)return t;for(var r=e.parentNode;r;){if(t=r[qo]||r[Po]){if(r=t.alternate,t.child!==null||r!==null&&r.child!==null)for(e=ox(e);e!==null;){if(r=e[Po])return r;e=ox(e)}return t}e=r,r=e.parentNode}return null}function gu(e){return e=e[Po]||e[qo],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function Vi(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(Me(33))}function cf(e){return e[Gl]||null}var xg=[],Ui=-1;function za(e){return{current:e}}function Xt(e){0>Ui||(e.current=xg[Ui],xg[Ui]=null,Ui--)}function Kt(e,t){Ui++,xg[Ui]=e.current,e.current=t}var Da={},Ur=za(Da),sn=za(!1),ii=Da;function ls(e,t){var r=e.type.contextTypes;if(!r)return Da;var n=e.stateNode;if(n&&n.__reactInternalMemoizedUnmaskedChildContext===t)return n.__reactInternalMemoizedMaskedChildContext;var o={},a;for(a in r)o[a]=t[a];return n&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function ln(e){return e=e.childContextTypes,e!=null}function hd(){Xt(sn),Xt(Ur)}function ax(e,t,r){if(Ur.current!==Da)throw Error(Me(168));Kt(Ur,t),Kt(sn,r)}function IS(e,t,r){var n=e.stateNode;if(t=t.childContextTypes,typeof n.getChildContext!="function")return r;n=n.getChildContext();for(var o in n)if(!(o in t))throw Error(Me(108,YA(e)||"Unknown",o));return lr({},r,n)}function gd(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Da,ii=Ur.current,Kt(Ur,e),Kt(sn,sn.current),!0}function ix(e,t,r){var n=e.stateNode;if(!n)throw Error(Me(169));r?(e=IS(e,t,ii),n.__reactInternalMemoizedMergedChildContext=e,Xt(sn),Xt(Ur),Kt(Ur,e)):Xt(sn),Kt(sn,r)}var zo=null,df=!1,nh=!1;function DS(e){zo===null?zo=[e]:zo.push(e)}function fM(e){df=!0,DS(e)}function Ba(){if(!nh&&zo!==null){nh=!0;var e=0,t=Wt;try{var r=zo;for(Wt=1;e<r.length;e++){var n=r[e];do n=n(!0);while(n!==null)}zo=null,df=!1}catch(o){throw zo!==null&&(zo=zo.slice(e+1)),sS(F0,Ba),o}finally{Wt=t,nh=!1}}return null}var Wi=[],$i=0,md=null,bd=0,In=[],Dn=0,si=null,Bo=1,Vo="";function Ka(e,t){Wi[$i++]=bd,Wi[$i++]=md,md=e,bd=t}function LS(e,t,r){In[Dn++]=Bo,In[Dn++]=Vo,In[Dn++]=si,si=e;var n=Bo;e=Vo;var o=32-so(n)-1;n&=~(1<<o),r+=1;var a=32-so(t)+o;if(30<a){var i=o-o%5;a=(n&(1<<i)-1).toString(32),n>>=i,o-=i,Bo=1<<32-so(t)+o|r<<o|n,Vo=a+e}else Bo=1<<a|r<<o|n,Vo=e}function G0(e){e.return!==null&&(Ka(e,1),LS(e,1,0))}function K0(e){for(;e===md;)md=Wi[--$i],Wi[$i]=null,bd=Wi[--$i],Wi[$i]=null;for(;e===si;)si=In[--Dn],In[Dn]=null,Vo=In[--Dn],In[Dn]=null,Bo=In[--Dn],In[Dn]=null}var wn=null,bn=null,er=!1,ro=null;function FS(e,t){var r=Fn(5,null,null,0);r.elementType="DELETED",r.stateNode=t,r.return=e,t=e.deletions,t===null?(e.deletions=[r],e.flags|=16):t.push(r)}function sx(e,t){switch(e.tag){case 5:var r=e.type;return t=t.nodeType!==1||r.toLowerCase()!==t.nodeName.toLowerCase()?null:t,t!==null?(e.stateNode=t,wn=e,bn=Oa(t.firstChild),!0):!1;case 6:return t=e.pendingProps===""||t.nodeType!==3?null:t,t!==null?(e.stateNode=t,wn=e,bn=null,!0):!1;case 13:return t=t.nodeType!==8?null:t,t!==null?(r=si!==null?{id:Bo,overflow:Vo}:null,e.memoizedState={dehydrated:t,treeContext:r,retryLane:1073741824},r=Fn(18,null,null,0),r.stateNode=t,r.return=e,e.child=r,wn=e,bn=null,!0):!1;default:return!1}}function wg(e){return(e.mode&1)!==0&&(e.flags&128)===0}function _g(e){if(er){var t=bn;if(t){var r=t;if(!sx(e,t)){if(wg(e))throw Error(Me(418));t=Oa(r.nextSibling);var n=wn;t&&sx(e,t)?FS(n,r):(e.flags=e.flags&-4097|2,er=!1,wn=e)}}else{if(wg(e))throw Error(Me(418));e.flags=e.flags&-4097|2,er=!1,wn=e}}}function lx(e){
Line truncated
|
||||||
|
Error generating stack: `+a.message+`
|
||||||
|
`+a.stack}return{value:e,source:t,stack:o,digest:null}}function lh(e,t,r){return{value:e,source:null,stack:r??null,digest:t??null}}function Pg(e,t){try{console.error(t.value)}catch(r){setTimeout(function(){throw r})}}var wM=typeof WeakMap=="function"?WeakMap:Map;function fC(e,t,r){r=Uo(-1,r),r.tag=3,r.payload={element:null};var n=t.value;return r.callback=function(){Td||(Td=!0,Dg=n),Pg(e,t)},r}function pC(e,t,r){r=Uo(-1,r),r.tag=3;var n=e.type.getDerivedStateFromError;if(typeof n=="function"){var o=t.value;r.payload=function(){return n(o)},r.callback=function(){Pg(e,t)}}var a=e.stateNode;return a!==null&&typeof a.componentDidCatch=="function"&&(r.callback=function(){Pg(e,t),typeof n!="function"&&(Na===null?Na=new Set([this]):Na.add(this));var i=t.stack;this.componentDidCatch(t.value,{componentStack:i!==null?i:""})}),r}function mx(e,t,r){var n=e.pingCache;if(n===null){n=e.pingCache=new wM;var o=new Set;n.set(t,o)}else o=n.get(t),o===void 0&&(o=new Set,n.set(t,o));o.has(r)||(o.add(r),e=IM.bind(null,e,t,r),t.then(e,e))}function bx(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function vx(e,t,r,n,o){return e.mode&1?(e.flags|=65536,e.lanes=o,e):(e===t?e.flags|=65536:(e.flags|=128,r.flags|=131072,r.flags&=-52805,r.tag===1&&(r.alternate===null?r.tag=17:(t=Uo(-1,1),t.tag=2,ka(r,t,1))),r.lanes|=1),e)}var _M=Xo.ReactCurrentOwner,on=!1;function Gr(e,t,r,n){t.child=e===null?HS(t,null,r,n):cs(t,e.child,r,n)}function yx(e,t,r,n,o){r=r.render;var a=t.ref;return es(t,o),n=am(e,t,r,n,a,o),r=im(),e!==null&&!on?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Ko(e,t,o)):(er&&r&&G0(t),t.flags|=1,Gr(e,t,n,o),t.child)}function xx(e,t,r,n,o){if(e===null){var a=r.type;return typeof a=="function"&&!mm(a)&&a.defaultProps===void 0&&r.compare===null&&r.defaultProps===void 0?(t.tag=15,t.type=a,hC(e,t,a,n,o)):(e=zc(r.type,null,n,t,t.mode,o),e.ref=t.ref,e.return=t,t.child=e)}if(a=e.child,!(e.lanes&o)){var i=a.memoizedProps;if(r=r.compare,r=r!==null?r:$l,r(i,n)&&e.ref===t.ref)return Ko(e,t,o)}return t.flags|=1,e=ja(a,n),e.ref=t.ref,e.return=t,t.child=e}function hC(e,t,r,n,o){if(e!==null){var a=e.memoizedProps;if($l(a,n)&&e.ref===t.ref)if(on=!1,t.pendingProps=n=a,(e.lanes&o)!==0)e.flags&131072&&(on=!0);else return t.lanes=e.lanes,Ko(e,t,o)}return Og(e,t,r,n,o)}function gC(e,t,r){var n=t.pendingProps,o=n.children,a=e!==null?e.memoizedState:null;if(n.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},Kt(Gi,mn),mn|=r;else{if(!(r&1073741824))return e=a!==null?a.baseLanes|r:r,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,Kt(Gi,mn),mn|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},n=a!==null?a.baseLanes:r,Kt(Gi,mn),mn|=n}else a!==null?(n=a.baseLanes|r,t.memoizedState=null):n=r,Kt(Gi,mn),mn|=n;return Gr(e,t,o,r),t.child}function mC(e,t){var r=t.ref;(e===null&&r!==null||e!==null&&e.ref!==r)&&(t.flags|=512,t.flags|=2097152)}function Og(e,t,r,n,o){var a=ln(r)?ii:Ur.current;return a=ls(t,a),es(t,o),r=am(e,t,r,n,a,o),n=im(),e!==null&&!on?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Ko(e,t,o)):(er&&n&&G0(t),t.flags|=1,Gr(e,t,r,o),t.child)}function wx(e,t,r,n,o){if(ln(r)){var a=!0;gd(t)}else a=!1;if(es(t,o),t.stateNode===null)Dc(e,t),WS(t,r,n),Tg(t,r,n,o),n=!0;else if(e===null){var i=t.stateNode,u=t.memoizedProps;i.props=u;var f=i.context,g=r.contextType;typeof g=="object"&&g!==null?g=Un(g):(g=ln(r)?ii:Ur.current,g=ls(t,g));var m=r.getDerivedStateFromProps,S=typeof m=="function"||typeof i.getSnapshotBeforeUpdate=="function";S||typeof i.UNSAFE_componentWillReceiveProps!="function"&&typeof i.componentWillReceiveProps!="function"||(u!==n||f!==g)&&fx(t,i,n,g),ma=!1;var O=t.memoizedState;i.state=O,xd(t,n,i,o),f=t.memoizedState,u!==n||O!==f||sn.current||ma?(typeof m=="function"&&(Cg(t,r,m,n),f=t.memoizedState),(u=ma||dx(t,r,u,n,O,f,g))?(S||typeof i.UNSAFE_componentWillMount!="function"&&typeof i.componentWillMount!="function"||(typeof i.componentWillMount=="function"&&i.componentWillMount(),typeof i.UNSAFE_componentWillMount=="function"&&i.UNSAFE_componentWillMount()),typeof i.componentDidMount=="function"&&(t.flags|=4194308)):(typeof i.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=n,t.memoizedState=f),i.props=n,i.state=f,i.context=g,n=u):(typeof i.componentDidMount=="function"&&(t.flags|=4194308),n=!1)}else{i=t.stateNode,VS(e,t),u=t.memoizedProps,g=t.type===t.elementType?u:Jn(t.type,u),i.props=g,S=t.pendingProps,O=i.context,f=r.contextType,typeof f=="object"&&f!==null?f=Un(f):(f=ln(r)?ii:Ur.current,f=ls(t,f));var T=r.getDerivedStateFromProps;(m=typeof T=="function"||typeof i.getSnapshotBeforeUpdate=="function")||typeof i.UNSAFE_componentWillReceiveProps!="function"&&typeof i.componentWillReceiveProps!="function"||(u!==S||O!==f)&&fx(t,i,n,f),ma=!1,O=t.memoizedState,i.state=O,xd(t,n,i,o);var C=t.memoizedS
Line truncated
|
||||||
|
* @remix-run/router v1.10.0
|
||||||
|
*
|
||||||
|
* Copyright (c) Remix Software Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE.md file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @license MIT
|
||||||
|
*/function eu(){return eu=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},eu.apply(this,arguments)}var _a;(function(e){e.Pop="POP",e.Push="PUSH",e.Replace="REPLACE"})(_a||(_a={}));const Ix="popstate";function qM(e){e===void 0&&(e={});function t(n,o){let{pathname:a,search:i,hash:u}=n.location;return Bg("",{pathname:a,search:i,hash:u},o.state&&o.state.usr||null,o.state&&o.state.key||"default")}function r(n,o){return typeof o=="string"?o:Nd(o)}return KM(t,r,null,e)}function sr(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function wm(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function GM(){return Math.random().toString(36).substr(2,8)}function Dx(e,t){return{usr:e.state,key:e.key,idx:t}}function Bg(e,t,r,n){return r===void 0&&(r=null),eu({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?ks(t):t,{state:r,key:t&&t.key||n||GM()})}function Nd(e){let{pathname:t="/",search:r="",hash:n=""}=e;return r&&r!=="?"&&(t+=r.charAt(0)==="?"?r:"?"+r),n&&n!=="#"&&(t+=n.charAt(0)==="#"?n:"#"+n),t}function ks(e){let t={};if(e){let r=e.indexOf("#");r>=0&&(t.hash=e.substr(r),e=e.substr(0,r));let n=e.indexOf("?");n>=0&&(t.search=e.substr(n),e=e.substr(0,n)),e&&(t.pathname=e)}return t}function KM(e,t,r,n){n===void 0&&(n={});let{window:o=document.defaultView,v5Compat:a=!1}=n,i=o.history,u=_a.Pop,f=null,g=m();g==null&&(g=0,i.replaceState(eu({},i.state,{idx:g}),""));function m(){return(i.state||{idx:null}).idx}function S(){u=_a.Pop;let b=m(),d=b==null?null:b-g;g=b,f&&f({action:u,location:w.location,delta:d})}function O(b,d){u=_a.Push;let s=Bg(w.location,b,d);r&&r(s,b),g=m()+1;let c=Dx(s,g),l=w.createHref(s);try{i.pushState(c,"",l)}catch(h){if(h instanceof DOMException&&h.name==="DataCloneError")throw h;o.location.assign(l)}a&&f&&f({action:u,location:w.location,delta:1})}function T(b,d){u=_a.Replace;let s=Bg(w.location,b,d);r&&r(s,b),g=m();let c=Dx(s,g),l=w.createHref(s);i.replaceState(c,"",l),a&&f&&f({action:u,location:w.location,delta:0})}function C(b){let d=o.location.origin!=="null"?o.location.origin:o.location.href,s=typeof b=="string"?b:Nd(b);return sr(d,"No window.location.(origin|href) available to create URL for href: "+s),new URL(s,d)}let w={get action(){return u},get location(){return e(o,i)},listen(b){if(f)throw new Error("A history only accepts one active listener");return o.addEventListener(Ix,S),f=b,()=>{o.removeEventListener(Ix,S),f=null}},createHref(b){return t(o,b)},createURL:C,encodeLocation(b){let d=C(b);return{pathname:d.pathname,search:d.search,hash:d.hash}},push:O,replace:T,go(b){return i.go(b)}};return w}var Lx;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(Lx||(Lx={}));function YM(e,t,r){r===void 0&&(r="/");let n=typeof t=="string"?ks(t):t,o=tu(n.pathname||"/",r);if(o==null)return null;let a=BC(e);QM(a);let i=null;for(let u=0;i==null&&u<a.length;++u)i=aI(a[u],sI(o));return i}function BC(e,t,r,n){t===void 0&&(t=[]),r===void 0&&(r=[]),n===void 0&&(n="");let o=(a,i,u)=>{let f={relativePath:u===void 0?a.path||"":u,caseSensitive:a.caseSensitive===!0,childrenIndex:i,route:a};f.relativePath.startsWith("/")&&(sr(f.relativePath.startsWith(n),'Absolute route path "'+f.relativePath+'" nested under path '+('"'+n+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),f.relativePath=f.relativePath.slice(n.length));let g=Aa([n,f.relativePath]),m=r.concat(f);a.children&&a.children.length>0&&(sr(a.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+g+'".')),BC(a.children,t,m,g)),!(a.path==null&&!a.index)&&t.push({path:g,score:nI(g,a.index),routesMeta:m})};return e.forEach((a,i)=>{var u;if(a.path===""||!((u=a.path)!=null&&u.includes("?")))o(a,i);else for(let f of VC(a.path))o(a,i,f)}),t}function VC(e){let t=e.split("/");if(t.length===0)return[];let[r,...n]=t,o=r.endsWith("?"),a=r.replace(/\?$/,"");if(n.length===0)return o?[a,""]:[a];let i=VC(n.join("/")),u=[];return u.push(...i.map(f=>f===""?a:[a,f].join("/"))),o&&u.push(...i),u.map(f=>e.startsWith("/")&&f===""?"/":f)}function QM(e){e.sort((t,r)=>t.score!==r.score?r.score-t.score:oI(t.routesMeta.map(n=>n.childrenIndex),r.routesMeta.map(n=>n.childrenIndex)))}const XM=/^:\w+$/,ZM=3,JM=2,eI=1,tI=10,rI=-2,Fx=e=>e==="*";function nI(e,t){let r=e.split("/"),n=r.length;return r.some(Fx)&&(n+=rI),t&&(n+=JM),r.filter(o=>!Fx(o)).reduce((o,a)=>o+(XM.test(a)?ZM:a===""?eI:tI),n)}function oI(e,t){return e.length===t.length&&e.slice(0,-1).every((n,o)=>n===t[o])?e[e.length-1]-t[t.length-1]:0}function aI(e,t){let{routesMeta:r}=e,n={},o="/",a=[];for(let i=0;i<r.length;++i){let u=r[i],f=i===r.length-1,g=o==="/"?t:t.slice(o.length)||"/",m=Vg({path:u.relativePath,caseSensitive:u.caseSensitive,end:f},g);if(!m)return null;Object.assign(n,m.paLine truncated
|
||||||
|
* React Router v6.17.0
|
||||||
|
*
|
||||||
|
* Copyright (c) Remix Software Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE.md file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @license MIT
|
||||||
|
*/function Ed(){return Ed=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Ed.apply(this,arguments)}const wf=P.createContext(null),WC=P.createContext(null),bi=P.createContext(null),_f=P.createContext(null),Zo=P.createContext({outlet:null,matches:[],isDataRoute:!1}),$C=P.createContext(null);function mI(e,t){let{relative:r}=t===void 0?{}:t;Ns()||sr(!1);let{basename:n,navigator:o}=P.useContext(bi),{hash:a,pathname:i,search:u}=Sf(e,{relative:r}),f=i;return n!=="/"&&(f=i==="/"?n:Aa([n,i])),o.createHref({pathname:f,search:u,hash:a})}function Ns(){return P.useContext(_f)!=null}function Va(){return Ns()||sr(!1),P.useContext(_f).location}function HC(e){P.useContext(bi).static||P.useLayoutEffect(e)}function $n(){let{isDataRoute:e}=P.useContext(Zo);return e?NI():bI()}function bI(){Ns()||sr(!1);let e=P.useContext(wf),{basename:t,navigator:r}=P.useContext(bi),{matches:n}=P.useContext(Zo),{pathname:o}=Va(),a=JSON.stringify(_m(n).map(f=>f.pathnameBase)),i=P.useRef(!1);return HC(()=>{i.current=!0}),P.useCallback(function(f,g){if(g===void 0&&(g={}),!i.current)return;if(typeof f=="number"){r.go(f);return}let m=Sm(f,JSON.parse(a),o,g.relative==="path");e==null&&t!=="/"&&(m.pathname=m.pathname==="/"?t:Aa([t,m.pathname])),(g.replace?r.replace:r.push)(m,g.state,g)},[t,r,a,o,e])}function Cm(){let{matches:e}=P.useContext(Zo),t=e[e.length-1];return t?t.params:{}}function Sf(e,t){let{relative:r}=t===void 0?{}:t,{matches:n}=P.useContext(Zo),{pathname:o}=Va(),a=JSON.stringify(_m(n).map(i=>i.pathnameBase));return P.useMemo(()=>Sm(e,JSON.parse(a),o,r==="path"),[e,a,o,r])}function vI(e,t){return yI(e,t)}function yI(e,t,r){Ns()||sr(!1);let{navigator:n}=P.useContext(bi),{matches:o}=P.useContext(Zo),a=o[o.length-1],i=a?a.params:{};a&&a.pathname;let u=a?a.pathnameBase:"/";a&&a.route;let f=Va(),g;if(t){var m;let w=typeof t=="string"?ks(t):t;u==="/"||(m=w.pathname)!=null&&m.startsWith(u)||sr(!1),g=w}else g=f;let S=g.pathname||"/",O=u==="/"?S:S.slice(u.length)||"/",T=YM(e,{pathname:O}),C=CI(T&&T.map(w=>Object.assign({},w,{params:Object.assign({},i,w.params),pathname:Aa([u,n.encodeLocation?n.encodeLocation(w.pathname).pathname:w.pathname]),pathnameBase:w.pathnameBase==="/"?u:Aa([u,n.encodeLocation?n.encodeLocation(w.pathnameBase).pathname:w.pathnameBase])})),o,r);return t&&C?P.createElement(_f.Provider,{value:{location:Ed({pathname:"/",search:"",hash:"",state:null,key:"default"},g),navigationType:_a.Pop}},C):C}function xI(){let e=kI(),t=hI(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),r=e instanceof Error?e.stack:null,o={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"},a=null;return P.createElement(P.Fragment,null,P.createElement("h2",null,"Unexpected Application Error!"),P.createElement("h3",{style:{fontStyle:"italic"}},t),r?P.createElement("pre",{style:o},r):null,a)}const wI=P.createElement(xI,null);class _I extends P.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,r){return r.location!==t.location||r.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error||r.error,location:r.location,revalidation:t.revalidation||r.revalidation}}componentDidCatch(t,r){console.error("React Router caught the following error during render",t,r)}render(){return this.state.error?P.createElement(Zo.Provider,{value:this.props.routeContext},P.createElement($C.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function SI(e){let{routeContext:t,match:r,children:n}=e,o=P.useContext(wf);return o&&o.static&&o.staticContext&&(r.route.errorElement||r.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=r.route.id),P.createElement(Zo.Provider,{value:t},n)}function CI(e,t,r){var n;if(t===void 0&&(t=[]),r===void 0&&(r=null),e==null){var o;if((o=r)!=null&&o.errors)e=r.matches;else return null}let a=e,i=(n=r)==null?void 0:n.errors;if(i!=null){let u=a.findIndex(f=>f.route.id&&(i==null?void 0:i[f.route.id]));u>=0||sr(!1),a=a.slice(0,Math.min(a.length,u+1))}return a.reduceRight((u,f,g)=>{let m=f.route.id?i==null?void 0:i[f.route.id]:null,S=null;r&&(S=f.route.errorElement||wI);let O=t.concat(a.slice(0,g+1)),T=()=>{let C;return m?C=S:f.route.Component?C=P.createElement(f.route.Component,null):f.route.element?C=f.route.element:C=u,P.createElement(SI,{match:f,routeContext:{outlet:u,matches:O,isDataRoute:r!=null},children:C})};return r&&(f.route.ErrorBoundary||f.route.errorElement||g===0)?P.createElement(_I,{location:r.location,revalidation:r.revalidation,component:S,error:m,children:T(),routeContext:{outlet:null,matches:O,isDataRoute:!0}}):T()},null)}var qC=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable=Line truncated
|
||||||
|
* React Router DOM v6.17.0
|
||||||
|
*
|
||||||
|
* Copyright (c) Remix Software Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE.md file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @license MIT
|
||||||
|
*/function Ad(){return Ad=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Ad.apply(this,arguments)}function KC(e,t){if(e==null)return{};var r={},n=Object.keys(e),o,a;for(a=0;a<n.length;a++)o=n[a],!(t.indexOf(o)>=0)&&(r[o]=e[o]);return r}function AI(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function RI(e,t){return e.button===0&&(!t||t==="_self")&&!AI(e)}const MI=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","unstable_viewTransition"],II=["aria-current","caseSensitive","className","end","style","to","unstable_viewTransition","children"],DI=P.createContext({isTransitioning:!1}),LI="startTransition",zx=S0[LI];function FI(e){let{basename:t,children:r,future:n,window:o}=e,a=P.useRef();a.current==null&&(a.current=qM({window:o,v5Compat:!0}));let i=a.current,[u,f]=P.useState({action:i.action,location:i.location}),{v7_startTransition:g}=n||{},m=P.useCallback(S=>{g&&zx?zx(()=>f(S)):f(S)},[f,g]);return P.useLayoutEffect(()=>i.listen(m),[i,m]),P.createElement(jI,{basename:t,children:r,location:u.location,navigationType:u.action,navigator:i})}const zI=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",BI=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,YC=P.forwardRef(function(t,r){let{onClick:n,relative:o,reloadDocument:a,replace:i,state:u,target:f,to:g,preventScrollReset:m,unstable_viewTransition:S}=t,O=KC(t,MI),{basename:T}=P.useContext(bi),C,w=!1;if(typeof g=="string"&&BI.test(g)&&(C=g,zI))try{let c=new URL(window.location.href),l=g.startsWith("//")?new URL(c.protocol+g):new URL(g),h=tu(l.pathname,T);l.origin===c.origin&&h!=null?g=h+l.search+l.hash:w=!0}catch{}let b=mI(g,{relative:o}),d=WI(g,{replace:i,state:u,target:f,preventScrollReset:m,relative:o,unstable_viewTransition:S});function s(c){n&&n(c),c.defaultPrevented||d(c)}return P.createElement("a",Ad({},O,{href:C||b,onClick:w||a?n:s,ref:r,target:f}))}),VI=P.forwardRef(function(t,r){let{"aria-current":n="page",caseSensitive:o=!1,className:a="",end:i=!1,style:u,to:f,unstable_viewTransition:g,children:m}=t,S=KC(t,II),O=Sf(f,{relative:S.relative}),T=Va(),C=P.useContext(WC),{navigator:w}=P.useContext(bi),b=C!=null&&$I(O)&&g===!0,d=w.encodeLocation?w.encodeLocation(O).pathname:O.pathname,s=T.pathname,c=C&&C.navigation&&C.navigation.location?C.navigation.location.pathname:null;o||(s=s.toLowerCase(),c=c?c.toLowerCase():null,d=d.toLowerCase());let l=s===d||!i&&s.startsWith(d)&&s.charAt(d.length)==="/",h=c!=null&&(c===d||!i&&c.startsWith(d)&&c.charAt(d.length)==="/"),y={isActive:l,isPending:h,isTransitioning:b},x=l?n:void 0,j;typeof a=="function"?j=a(y):j=[a,l?"active":null,h?"pending":null,b?"transitioning":null].filter(Boolean).join(" ");let k=typeof u=="function"?u(y):u;return P.createElement(YC,Ad({},S,{"aria-current":x,className:j,ref:r,style:k,to:f,unstable_viewTransition:g}),typeof m=="function"?m(y):m)});var Wg;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(Wg||(Wg={}));var Bx;(function(e){e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(Bx||(Bx={}));function UI(e){let t=P.useContext(wf);return t||sr(!1),t}function WI(e,t){let{target:r,replace:n,state:o,preventScrollReset:a,relative:i,unstable_viewTransition:u}=t===void 0?{}:t,f=$n(),g=Va(),m=Sf(e,{relative:i});return P.useCallback(S=>{if(RI(S,r)){S.preventDefault();let O=n!==void 0?n:Nd(g)===Nd(m);f(e,{replace:O,state:o,preventScrollReset:a,relative:i,unstable_viewTransition:u})}},[g,f,m,n,o,r,e,a,i,u])}function $I(e,t){t===void 0&&(t={});let r=P.useContext(DI);r==null&&sr(!1);let{basename:n}=UI(Wg.useViewTransitionState),o=Sf(e,{relative:t.relative});if(!r.isTransitioning)return!1;let a=tu(r.currentLocation.pathname,n)||r.currentLocation.pathname,i=tu(r.nextLocation.pathname,n)||r.nextLocation.pathname;return Vg(o.pathname,i)!=null||Vg(o.pathname,a)!=null}function HI({title:e,titleId:t,...r},n){return P.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",ref:n,"aria-labelledby":t},r),e?P.createElement("title",{id:t},e):null,P.createElement("path",{fillRule:"evenodd",d:"M7.5 3.75A1.5 1.5 0 006 5.25v13.5a1.5 1.5 0 001.5 1.5h6a1.5 1.5 0 001.5-1.5V15a.75.75 0 011.5 0v3.75a3 3 0 01-3 3h-6a3 3 0 01-3-3V5.25a3 3 0 013-3h6a3 3 0 013 3V9A.75.75 0 0115 9V5.25a1.5 1.5 0 00-1.5-1.5h-6zm5.03 4.72a.75.75 0 010 1.06l-1.72 1.72h10.94a.75.75 0 010 1.5H10.81l1.72 1.72a.75.75 0 11-1.06 1.06l-3-3a.75.75 0 010-1.06l3-3a.75.75 0 011.06 0z",clipRule:"evenodd"}))}const qI=P.forwardRef(HI),GI=qI;function KI({title:e,titleId:t,...r},n){return P.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",rLine truncated
|
||||||
|
Copyright (c) 2018 Jed Watson.
|
||||||
|
Licensed under the MIT License (MIT), see
|
||||||
|
http://jedwatson.github.io/classnames
|
||||||
|
*/(function(e){(function(){var t={}.hasOwnProperty;function r(){for(var n=[],o=0;o<arguments.length;o++){var a=arguments[o];if(a){var i=typeof a;if(i==="string"||i==="number")n.push(a);else if(Array.isArray(a)){if(a.length){var u=r.apply(null,a);u&&n.push(u)}}else if(i==="object"){if(a.toString!==Object.prototype.toString&&!a.toString.toString().includes("[native code]")){n.push(a.toString());continue}for(var f in a)t.call(a,f)&&a[f]&&n.push(f)}}}return n.join(" ")}e.exports?(r.default=r,e.exports=r):window.classNames=r})()})(ZC);var gt=ZC.exports,JC={exports:{}},Zn={};function Pm(){for(var e,t,r=0,n="";r<arguments.length;)(e=arguments[r++])&&(t=e5(e))&&(n&&(n+=" "),n+=t);return n}function e5(e){if(typeof e=="string")return e;for(var t,r="",n=0;n<e.length;n++)e[n]&&(t=e5(e[n]))&&(r&&(r+=" "),r+=t);return r}function $g(){return $g=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},$g.apply(this,arguments)}function S4(e){var t=function(r){var n=r.theme,o=r.prefix,a={nextPart:new Map,validators:[]};return function(i,u){return u?i.map(function(f){return[f[0],f[1].map(function(g){return typeof g=="string"?u+g:typeof g=="object"?Object.fromEntries(Object.entries(g).map(function(m){return[u+m[0],m[1]]})):g})]}):i}(Object.entries(r.classGroups),o).forEach(function(i){Hg(i[1],a,i[0],n)}),a}(e);return{getClassGroupId:function(r){var n=r.split("-");return n[0]===""&&n.length!==1&&n.shift(),t5(n,t)||function(o){if(Vx.test(o)){var a=Vx.exec(o)[1],i=a==null?void 0:a.substring(0,a.indexOf(":"));if(i)return"arbitrary.."+i}}(r)},getConflictingClassGroupIds:function(r){return e.conflictingClassGroups[r]||[]}}}function t5(e,t){var r;if(e.length===0)return t.classGroupId;var n=t.nextPart.get(e[0]),o=n?t5(e.slice(1),n):void 0;if(o)return o;if(t.validators.length!==0){var a=e.join("-");return(r=t.validators.find(function(i){return(0,i.validator)(a)}))==null?void 0:r.classGroupId}}Object.defineProperty(Zn,"__esModule",{value:!0});var Vx=/^\[(.+)\]$/;function Hg(e,t,r,n){e.forEach(function(o){if(typeof o!="string"){if(typeof o=="function")return o.isThemeGetter?void Hg(o(n),t,r,n):void t.validators.push({validator:o,classGroupId:r});Object.entries(o).forEach(function(a){Hg(a[1],Ux(t,a[0]),r,n)})}else(o===""?t:Ux(t,o)).classGroupId=r})}function Ux(e,t){var r=e;return t.split("-").forEach(function(n){r.nextPart.has(n)||r.nextPart.set(n,{nextPart:new Map,validators:[]}),r=r.nextPart.get(n)}),r}function C4(e){if(e<1)return{get:function(){},set:function(){}};var t=0,r=new Map,n=new Map;function o(a,i){r.set(a,i),++t>e&&(t=0,n=r,r=new Map)}return{get:function(a){var i=r.get(a);return i!==void 0?i:(i=n.get(a))!==void 0?(o(a,i),i):void 0},set:function(a,i){r.has(a)?r.set(a,i):o(a,i)}}}function T4(e){var t=e.separator||":";return function(r){for(var n=0,o=[],a=0,i=0;i<r.length;i++){var u=r[i];n===0&&u===t[0]&&(t.length!==1&&r.slice(i,i+t.length)!==t||(o.push(r.slice(a,i)),a=i+t.length)),u==="["?n++:u==="]"&&n--}var f=o.length===0?r:r.substring(a),g=f.startsWith("!");return{modifiers:o,hasImportantModifier:g,baseClassName:g?f.substring(1):f}}}function P4(e){return $g({cache:C4(e.cacheSize),splitModifiers:T4(e)},S4(e))}var O4=/\s+/;function k4(e,t){var r=t.splitModifiers,n=t.getClassGroupId,o=t.getConflictingClassGroupIds,a=new Set;return e.trim().split(O4).map(function(i){var u=r(i),f=u.modifiers,g=u.hasImportantModifier,m=n(u.baseClassName);if(!m)return{isTailwindClass:!1,originalClassName:i};var S=function(O){if(O.length<=1)return O;var T=[],C=[];return O.forEach(function(w){w[0]==="["?(T.push.apply(T,C.sort().concat([w])),C=[]):C.push(w)}),T.push.apply(T,C.sort()),T}(f).join(":");return{isTailwindClass:!0,modifierId:g?S+"!":S,classGroupId:m,originalClassName:i}}).reverse().filter(function(i){if(!i.isTailwindClass)return!0;var u=i.modifierId,f=i.classGroupId,g=u+f;return!a.has(g)&&(a.add(g),o(f).forEach(function(m){return a.add(u+m)}),!0)}).reverse().map(function(i){return i.originalClassName}).join(" ")}function qg(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];var n,o,a,i=u;function u(g){var m=t[0],S=t.slice(1).reduce(function(O,T){return T(O)},m());return n=P4(S),o=n.cache.get,a=n.cache.set,i=f,f(g)}function f(g){var m=o(g);if(m)return m;var S=k4(g,n);return a(g,S),S}return function(){return i(Pm.apply(null,arguments))}}function Qt(e){var t=function(r){return r[e]||[]};return t.isThemeGetter=!0,t}var Ua=/^\[(.+)\]$/,N4=/^\d+\/\d+$/,E4=new Set(["px","full","screen"]),j4=/^(\d+)?(xs|sm|md|lg|xl)$/,A4=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh)/,R4=/^-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;function Rn(e){return!Number.isNaN(Number(e))||E4.has(e)||N4.test(e)||ba(e)}function ba(e){var t,r=(t=Ua.exec(e))==null?void 0:t[1];return!!r&&(r.startsWith("length:")||A4.test(r))}function r5(e){var t,r=(t=Ua.exec(e))==null?void 0:t[1];return!!r&&r.startsWLine truncated
|
||||||
|
* tabbable 6.2.0
|
||||||
|
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
|
||||||
|
*/var SF=["input:not([inert])","select:not([inert])","textarea:not([inert])","a[href]:not([inert])","button:not([inert])","[tabindex]:not(slot):not([inert])","audio[controls]:not([inert])","video[controls]:not([inert])",'[contenteditable]:not([contenteditable="false"]):not([inert])',"details>summary:first-of-type:not([inert])","details:not([inert])"],s0=SF.join(","),uO=typeof Element>"u",su=uO?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,Ud=!uO&&Element.prototype.getRootNode?function(e){var t;return e==null||(t=e.getRootNode)===null||t===void 0?void 0:t.call(e)}:function(e){return e==null?void 0:e.ownerDocument},Wd=function e(t,r){var n;r===void 0&&(r=!0);var o=t==null||(n=t.getAttribute)===null||n===void 0?void 0:n.call(t,"inert"),a=o===""||o==="true",i=a||r&&t&&e(t.parentNode);return i},CF=function(t){var r,n=t==null||(r=t.getAttribute)===null||r===void 0?void 0:r.call(t,"contenteditable");return n===""||n==="true"},TF=function(t,r,n){if(Wd(t))return[];var o=Array.prototype.slice.apply(t.querySelectorAll(s0));return r&&su.call(t,s0)&&o.unshift(t),o=o.filter(n),o},PF=function e(t,r,n){for(var o=[],a=Array.from(t);a.length;){var i=a.shift();if(!Wd(i,!1))if(i.tagName==="SLOT"){var u=i.assignedElements(),f=u.length?u:i.children,g=e(f,!0,n);n.flatten?o.push.apply(o,g):o.push({scopeParent:i,candidates:g})}else{var m=su.call(i,s0);m&&n.filter(i)&&(r||!t.includes(i))&&o.push(i);var S=i.shadowRoot||typeof n.getShadowRoot=="function"&&n.getShadowRoot(i),O=!Wd(S,!1)&&(!n.shadowRootFilter||n.shadowRootFilter(i));if(S&&O){var T=e(S===!0?i.children:S.children,!0,n);n.flatten?o.push.apply(o,T):o.push({scopeParent:i,candidates:T})}else a.unshift.apply(a,i.children)}}return o},cO=function(t){return!isNaN(parseInt(t.getAttribute("tabindex"),10))},dO=function(t){if(!t)throw new Error("No node provided");return t.tabIndex<0&&(/^(AUDIO|VIDEO|DETAILS)$/.test(t.tagName)||CF(t))&&!cO(t)?0:t.tabIndex},OF=function(t,r){var n=dO(t);return n<0&&r&&!cO(t)?0:n},kF=function(t,r){return t.tabIndex===r.tabIndex?t.documentOrder-r.documentOrder:t.tabIndex-r.tabIndex},fO=function(t){return t.tagName==="INPUT"},NF=function(t){return fO(t)&&t.type==="hidden"},EF=function(t){var r=t.tagName==="DETAILS"&&Array.prototype.slice.apply(t.children).some(function(n){return n.tagName==="SUMMARY"});return r},jF=function(t,r){for(var n=0;n<t.length;n++)if(t[n].checked&&t[n].form===r)return t[n]},AF=function(t){if(!t.name)return!0;var r=t.form||Ud(t),n=function(u){return r.querySelectorAll('input[type="radio"][name="'+u+'"]')},o;if(typeof window<"u"&&typeof window.CSS<"u"&&typeof window.CSS.escape=="function")o=n(window.CSS.escape(t.name));else try{o=n(t.name)}catch(i){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",i.message),!1}var a=jF(o,t.form);return!a||a===t},RF=function(t){return fO(t)&&t.type==="radio"},MF=function(t){return RF(t)&&!AF(t)},IF=function(t){var r,n=t&&Ud(t),o=(r=n)===null||r===void 0?void 0:r.host,a=!1;if(n&&n!==t){var i,u,f;for(a=!!((i=o)!==null&&i!==void 0&&(u=i.ownerDocument)!==null&&u!==void 0&&u.contains(o)||t!=null&&(f=t.ownerDocument)!==null&&f!==void 0&&f.contains(t));!a&&o;){var g,m,S;n=Ud(o),o=(g=n)===null||g===void 0?void 0:g.host,a=!!((m=o)!==null&&m!==void 0&&(S=m.ownerDocument)!==null&&S!==void 0&&S.contains(o))}}return a},mw=function(t){var r=t.getBoundingClientRect(),n=r.width,o=r.height;return n===0&&o===0},DF=function(t,r){var n=r.displayCheck,o=r.getShadowRoot;if(getComputedStyle(t).visibility==="hidden")return!0;var a=su.call(t,"details>summary:first-of-type"),i=a?t.parentElement:t;if(su.call(i,"details:not([open]) *"))return!0;if(!n||n==="full"||n==="legacy-full"){if(typeof o=="function"){for(var u=t;t;){var f=t.parentElement,g=Ud(t);if(f&&!f.shadowRoot&&o(f)===!0)return mw(t);t.assignedSlot?t=t.assignedSlot:!f&&g!==t.ownerDocument?t=g.host:t=f}t=u}if(IF(t))return!t.getClientRects().length;if(n!=="legacy-full")return!0}else if(n==="non-zero-area")return mw(t);return!1},LF=function(t){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(t.tagName))for(var r=t.parentElement;r;){if(r.tagName==="FIELDSET"&&r.disabled){for(var n=0;n<r.children.length;n++){var o=r.children.item(n);if(o.tagName==="LEGEND")return su.call(r,"fieldset[disabled] *")?!0:!o.contains(t)}return!0}r=r.parentElement}return!1},FF=function(t,r){return!(r.disabled||Wd(r)||NF(r)||DF(r,t)||EF(r)||LF(r))},bw=function(t,r){return!(MF(r)||dO(r)<0||!FF(t,r))},zF=function(t){var r=parseInt(t.getAttribute("tabindex"),10);return!!(isNaN(r)||r>=0)},BF=function e(t){var r=[],n=[];return t.forEach(function(o,a){var i=!!o.scopeParent,u=i?o.scopeParent:o,f=OF(u,i),g=i?e(o.candidates):u;f===0?i?r.push.apply(r,g):r.push(u):n.push({documentOrder:a,tabIndex:f,item:o,isScope:i,content:g})}),n.sort(kF).reduce(function(o,a){return a.isScope?o.push.apply(o,a.content):o.push(a.content),o},[]).concatLine truncated
|
||||||
|
|
||||||
|
More details: https://www.material-tailwind.com/docs/react/collapse
|
||||||
|
`);var k=r.default.useRef(null),N=(0,g.useTheme)().navbar,A=N.styles,M=A.base.mobileNav;l=l??{},h=h??"";var D=(0,u.twMerge)((0,i.default)((0,f.default)(M)),h),L={unmount:{height:0,opacity:0,transition:{duration:.3,times:"[0.4, 0, 0.2, 1]"}},mount:{opacity:1,height:"".concat((j=k.current)===null||j===void 0?void 0:j.scrollHeight,"px"),transition:{duration:.3,times:"[0.4, 0, 0.2, 1]"}}},z=(0,a.default)(L,l),V=n.AnimatePresence,Y=(0,o.useMergeRefs)([s,k]);return r.default.createElement(n.LazyMotion,{features:n.domAnimation},r.default.createElement(V,null,r.default.createElement(n.m.div,S({},x,{ref:Y,className:D,initial:"unmount",exit:"unmount",animate:c?"mount":"unmount",variants:z}),y)))});w.displayName="MaterialTailwind.MobileNav",w.propTypes={open:m.propTypesOpen,animate:m.propTypesAnimate,className:m.propTypesClassName,children:m.propTypesChildren};var b=w})(tk);(function(e){Object.defineProperty(e,"__esModule",{value:!0});function t(s,c){for(var l in c)Object.defineProperty(s,l,{enumerable:!0,get:c[l]})}t(e,{Navbar:function(){return b},MobileNav:function(){return g.MobileNav},default:function(){return d}});var r=T(P),n=T(ut),o=T(gt),a=lt,i=T(tr),u=T(nt),f=et,g=tk,m=Cf;function S(s,c,l){return c in s?Object.defineProperty(s,c,{value:l,enumerable:!0,configurable:!0,writable:!0}):s[c]=l,s}function O(){return O=Object.assign||function(s){for(var c=1;c<arguments.length;c++){var l=arguments[c];for(var h in l)Object.prototype.hasOwnProperty.call(l,h)&&(s[h]=l[h])}return s},O.apply(this,arguments)}function T(s){return s&&s.__esModule?s:{default:s}}function C(s,c){if(s==null)return{};var l=w(s,c),h,y;if(Object.getOwnPropertySymbols){var x=Object.getOwnPropertySymbols(s);for(y=0;y<x.length;y++)h=x[y],!(c.indexOf(h)>=0)&&Object.prototype.propertyIsEnumerable.call(s,h)&&(l[h]=s[h])}return l}function w(s,c){if(s==null)return{};var l={},h=Object.keys(s),y,x;for(x=0;x<h.length;x++)y=h[x],!(c.indexOf(y)>=0)&&(l[y]=s[y]);return l}var b=r.default.forwardRef(function(s,c){var l=s.variant,h=s.color,y=s.shadow,x=s.blurred,j=s.fullWidth,k=s.className,N=s.children,A=C(s,["variant","color","shadow","blurred","fullWidth","className","children"]),M=(0,f.useTheme)().navbar,D=M.defaultProps,L=M.valid,z=M.styles,V=z.base,Y=z.variants;l=l??D.variant,h=h??D.color,y=y??D.shadow,x=x??D.blurred,j=j??D.fullWidth,k=k??D.className;var q,B=(0,o.default)((0,u.default)(V.navbar.initial),(q={},S(q,(0,u.default)(V.navbar.shadow),y),S(q,(0,u.default)(V.navbar.blurred),x&&h==="white"),S(q,(0,u.default)(V.navbar.fullWidth),j),q)),H=(0,o.default)((0,u.default)(Y[(0,i.default)(L.variants,l,"filled")][(0,i.default)(L.colors,h,"white")])),K=(0,a.twMerge)((0,o.default)(B,H),k);return r.default.createElement("nav",O({},A,{ref:c,className:K}),N)});b.propTypes={variant:n.default.oneOf(m.propTypesVariant),color:n.default.oneOf(m.propTypesColor),shadow:m.propTypesShadow,blurred:m.propTypesBlurred,fullWidth:m.propTypesFullWidth,className:m.propTypesClassName,children:m.propTypesChildren},b.displayName="MaterialTailwind.Navbar";var d=Object.assign(b,{MobileNav:g.MobileNav})})(ek);var rk={},Hf={},Ls={};(function(e){Object.defineProperty(e,"__esModule",{value:!0});function t(b,d){for(var s in d)Object.defineProperty(b,s,{enumerable:!0,get:d[s]})}t(e,{propTypesOpen:function(){return a},propTypesHandler:function(){return i},propTypesPlacement:function(){return u},propTypesOffset:function(){return f},propTypesDismiss:function(){return g},propTypesAnimate:function(){return m},propTypesContent:function(){return S},propTypesInteractive:function(){return O},propTypesClassName:function(){return T},propTypesChildren:function(){return C},propTypesContextValue:function(){return w}});var r=o(ut),n=Zt;function o(b){return b&&b.__esModule?b:{default:b}}var a=r.default.bool,i=r.default.func,u=n.propTypesPlacements,f=n.propTypesOffsetType,g=n.propTypesDismissType,m=n.propTypesAnimation,S=r.default.node,O=r.default.bool,T=r.default.string,C=r.default.node.isRequired,w=r.default.shape({open:r.default.bool.isRequired,strategy:r.default.oneOf(["fixed","absolute"]).isRequired,x:r.default.number,y:r.default.number,context:r.default.instanceOf(Object).isRequired,reference:r.default.func.isRequired,floating:r.default.func.isRequired,getReferenceProps:r.default.func.isRequired,getFloatingProps:r.default.func.isRequired,appliedAnimation:m.isRequired,labelId:r.default.string.isRequired,descriptionId:r.default.string.isRequired}).isRequired})(Ls);(function(e){Object.defineProperty(e,"__esModule",{value:!0});function t(f,g){for(var m in g)Object.defineProperty(f,m,{enumerable:!0,get:g[m]})}t(e,{PopoverContext:function(){return a},usePopover:function(){return i},PopoverContextProvider:function(){return u}});var r=o(P),n=Ls;function o(f){return f&&f.__esModule?f:{default:f}}var a=r.default.createContext(null);a.displayName="MaterialTailwind.PopoverContext";function i(){var f=r.default.useContext(a);if(!f)throw new Error("usePopover() must be used within a Popover. It happens when you us
Line truncated
|
||||||
|
${se?"border-purple-500 ring-1 ring-purple-500/40":"border-transparent"}
|
||||||
|
${!xe||ie?"opacity-75 bg-stormGrey-200/20":""}`,children:[v.jsxs("div",{className:"flex items-center space-x-4",id:"left",children:[k&&v.jsx("input",{type:"checkbox",checked:se,onChange:()=>Ee(oe.Id,!Ue),className:`h-5 w-5 text-purple-500 focus:ring-purple-400 border-gray-600 bg-gray-900 rounded ${Ue?"":"opacity-40 cursor-not-allowed"}`,disabled:!Ue}),v.jsx("div",{className:`w-12 h-12 flex items-center justify-center rounded-full
|
||||||
|
${oe.updateStatus==="✅"?"bg-mossGreen-600":oe.updateStatus==="⚠️"?"bg-warmAmberGlow-400":"bg-sunsetCoral-500"}`}),v.jsxs("div",{children:[v.jsx("p",{className:"text-lg antialiased font-sans font-semibold leading-normal text-inherit",children:oe.Name}),v.jsxs("p",{className:"text-sm antialiased font-sans font-light leading-normal text-inherit",children:["ID: ",oe.Id]}),oe.duplicateName&&v.jsx("p",{className:"text-xs text-amber-700",children:"⚠️ Doppelter Name erkannt"})]})]}),v.jsx("div",{className:"ml-auto flex flex-col items-end gap-1 text-sm",id:"right",children:ye?v.jsxs(v.Fragment,{children:[v.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-warmAmberGlow-600",children:"Redeploy"}),v.jsx("span",{className:"text-warmAmberGlow-500",children:"läuft…"})]}):te?v.jsxs(v.Fragment,{children:[v.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-warmAmberGlow-600",children:"Redeploy"}),v.jsx("span",{className:"text-warmAmberGlow-500",children:"in Warteliste…"})]}):Oe?v.jsxs(v.Fragment,{children:[v.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-stormGrey-500",children:"System"}),v.jsx("span",{className:"text-gray-300",children:"Redeploy deaktiviert"})]}):fe?v.jsxs(v.Fragment,{children:[v.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-stormGrey-500",children:"Status"}),v.jsx("span",{className:"text-mossGreen-600",children:"Aktuell"})]}):j?v.jsx(W.Button,{onClick:()=>qe(oe.Id),disabled:L||ie,className:"disabled:opacity-50 disabled:cursor-not-allowed",children:"Redeploy"}):null})]})},oe.Id)})}),v.jsx(ju,{disabled:r||!!o})]})}const tV={initializing:"Vorbereitung","activating-maintenance":"Wartungsmodus aktivieren","executing-script":"Skript wird ausgeführt",waiting:"Warte auf Portainer",completed:"Abgeschlossen",failed:"Fehlgeschlagen"},_c=e=>{if(!e&&e!==0)return"-";const r=(n=>{if(n instanceof Date)return n;if(typeof n=="number"){const o=n>1e12?n:n*1e3;return new Date(o)}if(typeof n=="string"){const o=Number(n);if(!Number.isNaN(o)){const a=o>1e12?o:o*1e3;return new Date(a)}return new Date(n)}return null})(e);return!r||Number.isNaN(r.getTime())?String(e):r.toLocaleString("de-DE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})},Mh=()=>({host:"",port:"22",username:"",password:"",extraSshArgs:""});function rV(){var Gs,Iu;const e=$n(),{hasPermission:t,user:r}=Wr(),n=P.useCallback(()=>{},[]),{maintenance:o,update:a,script:i,ssh:u,loading:f,error:g,setMaintenanceMode:m,triggerUpdate:S,saveScript:O,resetScript:T,saveSshConfig:C,deleteSshConfig:w,testSshConnection:b,fetchSuperuserStatus:d,fetchSetupStatus:s,deleteSetupServer:c,updateSetupApiKey:l,updateSelfStackId:h,removeSuperuserAccount:y}=ea(),x=!!(r!=null&&r.isSuperuser),j=!!(x||t("maintenance-access","read")),k=!!(x||t("maintenance-access","full")),N=!!(x||t("maintenance-server-manage","read")),A=!!(x||t("maintenance-server-edit","full")),M=!!(x||t("maintenance-server-delete","full")),D=!!(x||t("maintenance-superuser-delete","full"));x||t("maintenance-portainer","read");const L=!!(x||t("maintenance-update","full"));x||t("maintenance-ssh-update","read");const z=!!(x||t("maintenance-ssh-update","full"));x||t("maintenance-duplicates","read");const V=!!(x||t("maintenance-duplicates","full")),Y=!1,q=!1,B=!!(o!=null&&o.active),H=o==null?void 0:o.message,K=(Gs=o==null?void 0:o.extra)==null?void 0:Gs.type,X=!!(a!=null&&a.running),re=B||X,[me,de]=P.useState(""),[ee,_e]=P.useState(!1),[he,pe]=P.useState(!1),[be,ve]=P.useState(""),[Ce,Ae]=P.useState(!1),[Ne,ue]=P.useState(()=>Mh()),[Ee,$e]=P.useState(!1),[Ge,tt]=P.useState(!1),[ct,qe]=P.useState(!1),[it,mt]=P.useState(!1),[We,rt]=P.useState(!1),[yt,je]=P.useState(null);P.useEffect(()=>{if(!i)return;const Pe=i.custom??i.default??i.effective??"";de(Pe)},[i]),P.useEffect(()=>{if(!u){ue(Mh()),$e(!1),tt(!1),je(null);return}ue({host:u.host??"",port:String(u.port??"22"),username:u.username??"",password:"",extraSshArgs:Array.isArray(u.extraSshArgs)?u.extraSshArgs.join(`
|
||||||
|
`):""}),$e(!!u.passwordStored),tt(!1),je(null)},[u]),P.useMemo(()=>i?i.source==="custom"&&typeof i.custom=="string"?i.custom:i.default??i.effective??"":"",[i]),i==null||i.source;const[Ke,Te]=P.useState(!0),[oe,ge]=P.useState(!1),[te,ye]=P.useState(null),[ie,se]=P.useState(""),[fe,Oe]=P.useState(!1),[xe,Ue]=P.useState(null),[Fe,Qe]=P.useState(!0),[ke,bt]=P.useState(""),[ft,At]=P.useState(""),[It,xt]=P.useState(""),[Rt,Er]=P.useState(""),[ur,$r]=P.useState(""),[rr,Hn]=P.useState(!1),[Ir,_r]=P.useState({}),[cn,dn]=P.useState(null),[J,Re]=P.useState(null),[ze,Ut]=P.useState(""),[Nt,Et]=P.useState(!1),[Ht,qt]=P.useState(""),[Pt,Xr]=P.useState([]),[mr,dr]=P.useState(!0),[On,kn]=P.useState(""),[Sr,Nn]=P.useState(!1),[ta,fn]=P.useState(null),[bo,qn]=P.useState(null),Ie=P.useRef(null),[ot,dt]=P.useState(new Map),[Xe,wt]=P.useState(!1),[Dt,nr]=P.useState(""),Lt=P.useMemo(()=>{var Pe;return((Pe=xe==null?void 0:xe.servers)==null?void 0:Pe.items)??[]},[xe]);P.useMemo(()=>{var Ve;const Pe=((Ve=xe==null?void 0:xe.apiKeys)==null?void 0:Ve.items)??[];return new Map(Pe.map(Be=>[Be.serverId,Be]))},[xe]),P.useMemo(()=>!!(xe!=null&&xe.setupComplete),[xe]);const Zr=(xe==null?void 0:xe.selfStack)??null,pn=(Zr==null?void 0:Zr.current)??"";(Iu=xe==null?void 0:xe.envDefaults)==null||Iu.selfStackId;const{page:hn,perPage:vo,perPageOptions:Ti,perPageIsAll:Wa,handlePerPageChange:Vs,setPage:Au,setTotals:Us,resetPagination:Ru}=Bs();P.useEffect(()=>()=>Ru(),[Ru]);const[Pi,Qf]=P.useState(""),[yo,Mo]=P.useState(null),[Ws,$s]=P.useState(!0),[Xf,Hs]=P.useState(""),[Zf,Oi]=P.useState(!1),[Jf,ep]=P.useState(null),$a=P.useRef(null),Gn=P.useCallback(async({silent:Pe=!1}={})=>{var Ve,Be;Te(!0),se("");try{const Le=await d(),at=!!(Le!=null&&Le.exists);ge(at),ye(at?Le.user??null:null)}catch(Le){const at=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Superuser-Status konnte nicht geladen werden";ge(!1),ye(null),se(at),Pe||n({variant:"error",title:"Statusabfrage fehlgeschlagen",description:at})}finally{Te(!1)}},[d,n]),Jr=P.useCallback(async({silent:Pe=!1}={})=>{var Ve,Be;Pe||Qe(!0),bt("");try{const Le=await s();Ue(Le),_r({})}catch(Le){const at=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Setup-Daten konnten nicht geladen werden";bt(at),Pe||n({variant:"error",title:"Setup-Daten",description:at})}finally{Qe(!1)}},[s,n]),qs=P.useCallback(async({silent:Pe=!1}={})=>{if($a.current)return $a.current;const Ve=(async()=>{var Be,Le;Pe?Oi(!0):$s(!0),Hs("");try{const Bt=(await Je.get("/api/maintenance/portainer-status")).data??{};Mo(Bt),ep(new Date)}catch(at){const Bt=((Le=(Be=at.response)==null?void 0:Be.data)==null?void 0:Le.error)||at.message||"Fehler beim Prüfen des Portainer-Status";Hs(Bt),n({variant:"error",title:"Statusaktualisierung fehlgeschlagen",description:Bt})}finally{Pe?Oi(!1):$s(!1),$a.current=null}})();return $a.current=Ve,Ve},[n]),ra=P.useCallback(async({silent:Pe=!1}={})=>{if(B||X){Xr([]),kn("Wartungsmodus aktiv – Duplikat-Verwaltung ist vorübergehend deaktiviert."),dr(!1),Nn(!1);return}if(Ie.current)return Ie.current;const Ve=(async()=>{var Be,Le,at;Pe?Nn(!0):dr(!0),kn("");try{const Ot=(await Je.get("/api/maintenance/duplicates")).data,br=Array.isArray(Ot)?Ot:(Ot==null?void 0:Ot.items)??[];Xr(br),qn(new Date)}catch(Bt){if(((Be=Bt.response)==null?void 0:Be.status)===423){const Ot="Wartungsmodus aktiv – Duplikat-Verwaltung ist vorübergehend deaktiviert.";Xr([]),kn(Ot),n({variant:"warning",title:"Duplikat-Verwaltung gesperrt",description:Ot})}else{const Ot=((at=(Le=Bt.response)==null?void 0:Le.data)==null?void 0:at.error)||Bt.message||"Fehler beim Laden der Wartungsdaten";kn(Ot),n({variant:"error",title:"Duplikate konnten nicht geladen werden",description:Ot})}}finally{Pe?Nn(!1):dr(!1),Ie.current=null}})();return Ie.current=Ve,Ve},[B,X,n]);P.useEffect(()=>{Gn({silent:!0})},[Gn]),P.useEffect(()=>{Jr()},[Jr]),P.useEffect(()=>{qs()},[qs]),P.useEffect(()=>{ra()},[ra]),P.useEffect(()=>{if(!N||Fe)return;(async()=>{var Ve,Be;if(!Lt.length){dt(new Map);return}wt(!0),nr("");try{const Le=await Promise.all(Lt.map(async at=>{var Bt,Ot;try{const Cr=(await Je.get(`/api/setup/servers/${at.id}/check`)).data??{};return[at.id,{online:!!Cr.online,portainer:Cr.portainer??{},error:null}]}catch(br){const Cr=((Ot=(Bt=br.response)==null?void 0:Bt.data)==null?void 0:Ot.error)||br.message||"Status unbekannt";return[at.id,{online:!1,portainer:{},error:Cr}]}}));dt(new Map(Le))}catch(Le){const at=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Server-Status konnte nicht geladen werden.";nr(at)}finally{wt(!1)}})()},[N,Fe,Lt,Us]);const Kn=P.useMemo(()=>{const Pe=Pi.trim().toLowerCase();return Pe?Lt.filter(Ve=>[Ve.name,Ve.url].map(Le=>String(Le||"").toLowerCase()).some(Le=>Le.includes(Pe))):Lt},[Pi,Lt]);P.useEffect(()=>{Us(Kn.length)},[Kn.length,Us]);const Ha=P.useMemo(()=>{if(Wa)return Kn;const Pe=(hn-1)*vo;return Kn.slice(Pe,Pe+vo)},[Kn,hn,vo,Wa]);P.useEffect(()=>{Ut(pn
Line truncated
|
||||||
|
Dies setzt die Superuser-Einrichtung zurück.`)))try{Oe(!0);const Le=await y(),at=Number((Le==null?void 0:Le.usersRemoved)??0);n({variant:"success",title:"Superuser gelöscht",description:at>1?`${at} Konten aus der Superuser-Gruppe wurden entfernt.`:"Superuser-Konto wurde entfernt."}),await Gn({silent:!0})}catch(Le){if(((Pe=Le.response)==null?void 0:Pe.status)===404)await Gn({silent:!0}),n({variant:"info",title:"Kein Superuser vorhanden",description:"Es ist kein Superuser mehr vorhanden."});else{const Bt=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Superuser konnte nicht gelöscht werden";n({variant:"error",title:"Löschen fehlgeschlagen",description:Bt})}}finally{Oe(!1)}},[D,fe,Ke,oe,y,Gn,n]),ap=P.useCallback(async Pe=>{var at,Bt;if(!M||J===Pe)return;const Ve=Lt.find(Ot=>Ot.id===Pe);if(!Ve)return;const Be=Ve.name||Ve.url||`Server ${Pe}`,Le=[`Server "${Be}" wirklich löschen?`,"Das System benötigt anschließend erneut einen gültigen Server im Setup."].filter(Boolean).join(`
|
||||||
|
`);if(!(typeof window<"u"&&!window.confirm(Le))){Re(Pe);try{await c(Pe),n({variant:"success",title:"Server gelöscht",description:`Server "${Be}" wurde entfernt.`}),await Jr({silent:!0})}catch(Ot){const br=((Bt=(at=Ot.response)==null?void 0:at.data)==null?void 0:Bt.error)||Ot.message||"Server konnte nicht gelöscht werden.";n({variant:"error",title:"Server löschen fehlgeschlagen",description:br})}finally{Re(null)}}},[M,c,Jr,J,Lt,n]);P.useCallback((Pe,Ve)=>{A&&_r(Be=>({...Be,[Pe]:Ve}))},[A]),P.useCallback(async Pe=>{var Be,Le;if(!A)return;const Ve=(Ir[Pe]??"").trim();if(!Ve){n({variant:"warning",title:"API-Key fehlt",description:"Bitte gib einen API-Key ein."});return}if(cn!==Pe){dn(Pe);try{await l(Pe,Ve),n({variant:"success",title:"API-Key aktualisiert",description:"Der API-Key wurde gespeichert."}),_r(at=>({...at,[Pe]:""})),await Jr({silent:!0})}catch(at){const Bt=((Le=(Be=at.response)==null?void 0:Be.data)==null?void 0:Le.error)||at.message||"API-Key konnte nicht aktualisiert werden.";n({variant:"error",title:"Aktualisierung fehlgeschlagen",description:Bt})}finally{dn(null)}}},[Ir,cn,A,Jr,n,l]),P.useCallback(Pe=>{A&&(Ut(Pe),qt(""))},[A]),P.useCallback(async()=>{var Ve,Be;if(!A||!Mu)return;Et(!0),qt("");const Pe=typeof ze=="string"?ze.trim():"";try{await h(Pe),n({variant:"success",title:"Self-Stack-ID gespeichert",description:Pe?`Self-Stack-ID wurde auf "${Pe}" gesetzt.`:"Self-Stack-ID wurde entfernt."}),await Jr({silent:!0})}catch(Le){const at=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Self-Stack-ID konnte nicht aktualisiert werden.";qt(at),n({variant:"error",title:"Self-Stack-ID",description:at})}finally{Et(!1)}},[A,Jr,Mu,ze,n,h]),P.useCallback(async()=>{var Pe,Ve;if(A&&!(!ze&&!pn)&&!(typeof window<"u"&&!window.confirm("Self-Stack-ID wirklich entfernen?"))){Et(!0),qt("");try{await h(""),Ut(""),n({variant:"success",title:"Self-Stack-ID entfernt",description:"Die Self-Stack-ID wurde gelöscht."}),await Jr({silent:!0})}catch(Be){const Le=((Ve=(Pe=Be.response)==null?void 0:Pe.data)==null?void 0:Ve.error)||Be.message||"Self-Stack-ID konnte nicht entfernt werden.";qt(Le),n({variant:"error",title:"Self-Stack-ID",description:Le})}finally{Et(!1)}}},[A,pn,Jr,ze,n,h]);const ip=P.useCallback(async Pe=>{var Ve,Be;if(k&&!(f||Ce)&&Pe!==B){if(X){n({variant:"warning",title:"Aktion nicht möglich",description:"Während eines laufenden Updates kann der Wartungsmodus nicht geändert werden."});return}Ae(!0);try{const Le=Pe&&!!K,at={active:Pe};Le&&H?at.message=H:at.message=null,await m(at),n({variant:Pe?"info":"success",title:Pe?"Wartungsmodus aktiviert":"Wartungsmodus deaktiviert",description:Pe?"Benutzer sehen jetzt die Wartungsseite.":"StackPulse steht wieder zur Verfügung."})}catch(Le){const at=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Wartungsmodus konnte nicht geändert werden";n({variant:"error",title:"Änderung fehlgeschlagen",description:at})}finally{Ae(!1)}}},[k,f,Ce,B,X,m,H,K,n]);P.useCallback(async()=>{var Ve,Be;if(!L)return;if(B||X){n({variant:"warning",title:"Update nicht möglich",description:"Während eines aktiven Wartungsmodus kann kein weiteres Update gestartet werden."});return}const Pe=(yo==null?void 0:yo.latestVersion)??(yo==null?void 0:yo.currentVersion)??"unbekannt";if(!(typeof window<"u"&&!window.confirm(`Portainer-Update starten?
|
||||||
|
Zielversion: ${Pe}.
|
||||||
|
Während des Updates befindet sich StackPulse im Wartungsmodus.
|
||||||
|
Fortfahren?`)))try{ve(""),pe(!0),await S(),n({variant:"info",title:"Update gestartet",description:"Das Portainer-Update wurde gestartet."})}catch(Le){const at=((Be=(Ve=Le.response)==null?void 0:Ve.data)==null?void 0:Be.error)||Le.message||"Portainer-Update konnte nicht gestartet werden";ve(at),n({variant:"error",title:"Update fehlgeschlagen",description:at})}finally{pe(!1)}},[L,B,X,yo,S,n]),P.useCallback(async Pe=>{var at,Bt,Ot,br;if(!V||!Pe)return;if(B||X){n({variant:"warning",title:"Aktion nicht möglich",description:"Während des Wartungsmodus sind Bereinigungen deaktiviert."});return}const Ve=(at=Pe.canonical)==null?void 0:at.Id;if(!Ve)return;const Be=(Pe.duplicates||[]).map(Cr=>Cr.Id).filter(Boolean);if(!Be.length)return;const Le=((Bt=Pe.canonical)==null?void 0:Bt.Name)||Pe.name||`Stack ${Ve}`;if(!(typeof window<"u"&&!window.confirm(`Bereinigung für "${Le}" starten?
|
||||||
|
Es werden ${Be.length} Duplikate entfernt: ${Be.join(", ")}`))){fn(String(Ve));try{const Io=(await Je.post("/api/maintenance/duplicates/cleanup",{canonicalId:Ve,duplicateIds:Be})).data??{};if(Io.success===!1)throw new Error(Io.error||"Bereinigung fehlgeschlagen");const Du=Array.isArray(Io.results)?Io.results.filter(Yn=>Yn.status==="deleted").map(Yn=>Yn.id):Be;n({variant:"success",title:"Bereinigung abgeschlossen",description:`${Le} – entfernte IDs: ${Du.join(", ")}`}),await ra({silent:!0})}catch(Cr){const Io=((br=(Ot=Cr.response)==null?void 0:Ot.data)==null?void 0:br.error)||Cr.message||"Bereinigung fehlgeschlagen";n({variant:"error",title:"Bereinigung fehlgeschlagen",description:Io})}finally{fn(null)}}},[V,ra,B,n,X]),o!=null&&o.activatedAt&&_c(o.activatedAt),o!=null&&o.updatedAt&&_c(o.updatedAt),a==null||a.status;const xo=a!=null&&a.stage?tV[a.stage]??a.stage:"–";return a==null||a.logs,a==null||a.targetVersion,a==null||a.resultVersion,a!=null&&a.startedAt&&_c(a.startedAt),a!=null&&a.finishedAt&&_c(a.finishedAt),a==null||a.message,j?v.jsxs("div",{className:"mt-12 mb-8 flex flex-col gap-12",children:[(B||X)&&v.jsx("div",{className:"rounded-lg border border-cyan-500/60 bg-cyan-900/30 px-4 py-3 text-sm text-bluegray-100",children:v.jsxs("div",{className:"flex flex-col gap-1",children:[v.jsxs("span",{children:["Wartungsmodus aktiv",H?` – ${H}`:X?" – Portainer-Update läuft":"","."]}),X&&v.jsxs("span",{className:"text-xs text-indigo-900",children:["Phase: ",xo]})]})}),j&&v.jsxs(W.Card,{children:[v.jsx(W.CardHeader,{variant:"gradient",color:"gray",className:"mb-5 p-4",children:v.jsx(W.Typography,{variant:"h6",color:"white",className:"flex items-center justify-between",children:v.jsx("span",{children:"Wartungsmodus"})})}),v.jsxs(W.CardBody,{className:"flex flex-col gap-4 p-4",children:[v.jsxs("div",{className:"flex items-start justify-between gap-4",children:[v.jsx("div",{className:"space-y-1",children:v.jsx("p",{className:"text-sm antialiased font-sans text-sm font-light leading-normal text-inherit",children:"Schaltet StackPulse für Benutzer in den Wartungsmodus."})}),v.jsx(W.Switch,{checked:B,disabled:!k||Ce||f||X,onChange:Pe=>ip(Pe.target.checked),ripple:!1,color:"amber"})]}),Ce&&v.jsx("p",{className:"text-xs text-stormGrey-500",children:"Wartungsmodus wird aktualisiert…"})]})]}),N&&v.jsxs(W.Card,{children:[v.jsx(W.CardHeader,{variant:"gradient",color:"gray",className:"mb-5 p-4",children:v.jsxs(W.Typography,{variant:"h6",color:"white",className:"flex items-center justify-between",children:[v.jsx("span",{children:"Server"}),v.jsxs(W.Typography,{variant:"small",color:"white",children:[Lt.length," vorhanden"]})]})}),v.jsxs(W.CardBody,{className:"p-4",children:[A&&v.jsxs("div",{className:"mb-8 rounded-lg border border-blue-gray-50 p-4",children:[v.jsx(W.Typography,{variant:"h6",color:"blue-gray",className:"mb-2",children:"Neuen Server hinzufügen"}),v.jsx("p",{className:"text-sm text-stormGrey-600 mb-4",children:"Hinterlege deine Portainer-Instanz. Die Verbindung wird beim Speichern automatisch geprüft."}),v.jsxs("div",{className:"grid gap-4 md:grid-cols-3",children:[v.jsx(W.Input,{label:"Servername",value:ft,onChange:Pe=>At(Pe.target.value),disabled:rr||re,crossOrigin:""}),v.jsx(W.Input,{label:"Server-URL oder IP",value:It,onChange:Pe=>xt(Pe.target.value),disabled:rr||re,crossOrigin:""}),v.jsx(W.Input,{type:"password",label:"Portainer API-Key",value:Rt,onChange:Pe=>Er(Pe.target.value),disabled:rr||re,crossOrigin:""})]}),v.jsxs("div",{className:"mt-4 flex flex-col gap-3 sm:flex-row sm:items-center",children:[v.jsx(W.Button,{color:"green",onClick:rp,disabled:rr||re,children:rr?"Verifiziere …":"Server anlegen"}),v.jsx(W.Button,{variant:"text",color:"blue-gray",onClick:np,disabled:rr,children:"Formular zurücksetzen"})]}),ur&&v.jsx("p",{className:"mt-2 text-sm text-sunsetCoral-600",children:ur})]}),v.jsxs("div",{className:"flex flex-col gap-4 md:flex-row md:items-center md:justify-between",children:[v.jsx("div",{className:"md:flex-1",children:v.jsx(W.Input,{label:"Suchen nach Name oder URL",value:Pi,onChange:tp,crossOrigin:""})}),v.jsx("div",{className:"md:mt-0 mt-4 md:flex-1",children:v.jsx(W.Select,{variant:"static",label:"Einträge pro Seite",onChange:Vs,value:vo,children:Ti.map(({value:Pe,label:Ve})=>v.jsx(W.Option,{value:Pe,children:Ve},Pe))})})]}),ke&&v.jsx("div",{className:"mt-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800",children:ke}),Dt&&!Fe&&v.jsx("div",{className:"mt-4 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800",children:Dt}),v.jsx("div",{className:"overflow-x-auto rounded-lg border border-blue-gray-50 mt-6",children:v.jsxs("table",{className:"w-full min-w-[720px] table-auto text-left",children:[v.jsx("thead",{children:v.jsxs("tr",{className:"bg-blue-gray-50/50 text-xs uppercase tracking-wide text-stormGrey-400",children:[v.jsx("th",{className:"px-6 py-4 font-semibold",children:"Name"}),v.jsx("th",{className:"px-6 py-4 font-s
Line truncated
|
||||||
|
`)},TV=(e=[])=>{if(!Array.isArray(e))return[];const t=[];for(let r=0;r<e.length;r+=4)t.push(e.slice(r,r+4));return t};function PV(){const e=$n(),{user:t,setSession:r,refreshSession:n}=Wr(),{maintenance:o,update:a}=ea(),[i,u]=P.useState(!0),[f,g]=P.useState(""),[m,S]=P.useState([]),[O,T]=P.useState(!1),[C,w]=P.useState(!1),b=!!(t!=null&&t.requiresSecurityPhraseDownload),d=!!(o!=null&&o.active);o==null||o.message;const s=!!(a!=null&&a.running);a!=null&&a.stage&&(SV[a.stage]??a.stage);const c=d||s,l=P.useMemo(()=>TV(m),[m]),h=P.useCallback(k=>{if(!k)return;const N=new Blob([k],{type:"text/plain;charset=utf-8"}),A=URL.createObjectURL(N),M=document.createElement("a");M.href=A;const D=t!=null&&t.username?`${t.username}-sicherheitsschluessel`:"security-phrase";M.download=`${D}.txt`,document.body.appendChild(M),M.click(),document.body.removeChild(M),URL.revokeObjectURL(A)},[t==null?void 0:t.username]),y=P.useCallback(async()=>{var k,N,A,M,D,L,z,V;u(!0),g("");try{const Y=await Je.get("/api/users/me/security-phrase"),q=Array.isArray((N=(k=Y.data)==null?void 0:k.item)==null?void 0:N.words)?Y.data.item.words:[];if(!q.length)throw new Error("EMPTY_SECURITY_PHRASE");S(q),w(!1)}catch(Y){if(((A=Y==null?void 0:Y.response)==null?void 0:A.status)===409||((D=(M=Y==null?void 0:Y.response)==null?void 0:M.data)==null?void 0:D.error)==="SECURITY_PHRASE_ALREADY_DOWNLOADED"){await n(),e("/dashboard/stacks",{replace:!0});return}if(((L=Y==null?void 0:Y.response)==null?void 0:L.status)===401){await n(),e("/auth/sign-in",{replace:!0});return}const q=((V=(z=Y==null?void 0:Y.response)==null?void 0:z.data)==null?void 0:V.error)||(Y==null?void 0:Y.message)||"Sicherheitsschlüssel konnte nicht geladen werden.";g(q)}finally{u(!1)}},[e,n]);P.useEffect(()=>{if(!t){e("/auth/sign-in",{replace:!0});return}if(!b){e("/dashboard/stacks",{replace:!0});return}y()},[t,b,y,e]);const x=P.useCallback(()=>{y()},[y]),j=P.useCallback(async()=>{var k,N,A,M,D,L;if(!(O||!Array.isArray(m)||m.length===0)){T(!0),g("");try{const z=CV(m);h(z);const V=await Je.post("/api/users/me/security-phrase/downloaded"),Y=((N=(k=V.data)==null?void 0:k.item)==null?void 0:N.downloadedAt)||null,q=(A=V.data)==null?void 0:A.session;q!=null&&q.user?r(q):await n(),w(!!Y),e("/dashboard/stacks",{replace:!0})}catch(z){if(((M=z==null?void 0:z.response)==null?void 0:M.status)===401){await n(),e("/auth/sign-in",{replace:!0});return}const V=((L=(D=z==null?void 0:z.response)==null?void 0:D.data)==null?void 0:L.error)||(z==null?void 0:z.message)||"Download konnte nicht bestätigt werden.";g(V)}finally{T(!1)}}},[m,O,h,n,e,r]);return b?v.jsxs("div",{className:"flex min-h-screen flex-col items-center justify-center bg-blue-gray-50/50 px-4 py-10",children:[v.jsxs("div",{className:"mb-6 text-center",children:[v.jsx(W.Typography,{variant:"h2",className:"font-semibold text-blue-gray-800",children:"Sicherheitsschlüssel sichern"}),v.jsx(W.Typography,{color:"blue-gray",className:"mt-2 max-w-3xl text-base",children:"Bitte lade den einmaligen Sicherheitsschlüssel herunter und bewahre ihn sicher auf. Er wird benötigt, um dein Passwort zurückzusetzen. Ohne den Download kannst du die Anwendung nicht weiter nutzen."})]}),v.jsx(W.Card,{className:"w-full max-w-3xl shadow-lg",children:v.jsxs(W.CardBody,{className:"space-y-6",children:[i&&v.jsx("div",{className:"flex items-center justify-center py-10",children:v.jsx(W.Spinner,{className:"h-10 w-10 text-blue-gray-500"})}),!i&&f&&v.jsx(W.Alert,{color:"red",className:"border border-red-200 bg-red-50 text-red-700",icon:v.jsx(zz,{className:"h-5 w-5"}),children:v.jsxs("div",{className:"flex items-start justify-between gap-4",children:[v.jsxs("div",{children:[v.jsx(W.Typography,{variant:"h6",color:"red",children:"Fehler"}),v.jsx(W.Typography,{color:"red",className:"text-sm",children:f})]}),v.jsx(W.Button,{size:"sm",color:"red",variant:"text",onClick:x,className:"normal-case",children:"Erneut versuchen"})]})}),!i&&!f&&v.jsxs(v.Fragment,{children:[v.jsxs("div",{className:"rounded-lg border border-blue-gray-100 bg-blue-gray-50/60 p-6",children:[v.jsx(W.Typography,{variant:"h5",className:"mb-4 text-blue-gray-800",children:"Deine Sicherheitsphrase"}),v.jsx("div",{className:"space-y-3",children:l.map((k,N)=>v.jsx("div",{className:"flex flex-wrap items-center justify-center gap-4 text-lg font-mono tracking-wide text-blue-gray-900 md:text-xl",children:k.map((A,M)=>v.jsx("span",{className:"uppercase",children:A},`phrase-${N}-${M}`))},`phrase-row-${N}`))})]}),v.jsxs("div",{className:"flex flex-col items-center justify-between gap-4 md:flex-row",children:[v.jsx("div",{className:"text-sm text-blue-gray-600",children:"Der Download startet im TXT-Format. Bewahre die Datei sicher auf – sie kann später nicht erneut angezeigt werden."}),v.jsxs(W.Button,{color:"blue",size:"md",className:"flex items-center gap-2 normal-case",onClick:j,disabled:c||O||C||m.length===0,children:[v.jsx(Dz,{className:"h-5 w-5"}),"Sicherheitsschlüssel herunterladen"]})]})]})]})})]}):null}const Lh=e=>{if(!
Line truncated
|
||||||
|
`):""}),Te(!!We.passwordStored),ge(!1),Ue(null)},[We]);const Er=P.useMemo(()=>Ce?Ce.source==="custom"&&typeof Ce.custom=="string"?Ce.custom:Ce.default??Ce.effective??"":"",[Ce]),ur=Ce?me!==Er:!1,$r=(Ce==null?void 0:Ce.source)==="custom"?"Benutzerdefiniert":"Standard",rr=C?(N.name||"").trim()!==(C.name||"")||(N.url||"").trim()!==(C.url||""):!1,Hn=P.useMemo(()=>{if(!(C!=null&&C.url))return"-";try{return new URL(C.url).hostname||C.url}catch{return C.url}},[C]),Ir=((Nn=V==null?void 0:V.portainer)==null?void 0:Nn.edition)??"-",_r=(Ir||"").toLowerCase().includes("community"),cn=((ta=V==null?void 0:V.agent)==null?void 0:ta.online)??(Ne==null?void 0:Ne.online)??null,dn=cn===!0?"Agent online":cn===!1?"Agent offline":"Unbekannt",J=P.useMemo(()=>{const Ie={host:yt.host.trim(),port:Number.parseInt(yt.port,10)||22,username:yt.username.trim(),extraSshArgs:(yt.extraSshArgs||"").split(/\r?\n/).map(dt=>dt.trim()).filter(Boolean)},ot=yt.password??"";return ot?Ie.password=ot:Ke||(Ie.password=""),Ie},[yt,Ke]),Re=P.useCallback((Ie,ot)=>{m&&A(dt=>({...dt,[Ie]:ot}))},[m]),ze=P.useCallback(async()=>{var Ie,ot,dt,Xe;if(!(!m||!r||!rr)){x(!0);try{await Je.put(`/api/setup/servers/${r}`,{name:((Ie=N.name)==null?void 0:Ie.trim())??"",url:((ot=N.url)==null?void 0:ot.trim())??""}),u({variant:"success",title:"Server gespeichert",description:"Serverdetails wurden aktualisiert."}),await ft(),await At({silent:!0})}catch(wt){const Dt=((Xe=(dt=wt.response)==null?void 0:dt.data)==null?void 0:Xe.error)||wt.message||"Server konnte nicht aktualisiert werden";u({variant:"error",title:"Speichern fehlgeschlagen",description:Dt})}finally{x(!1)}}},[m,r,rr,N,ft,At,u]),Ut=P.useCallback((Ie,ot)=>{$e(dt=>({...dt,[Ie]:ot}))},[]),Nt=P.useCallback(async()=>{var Ie,ot;if(r){mt(!0);try{await Je.put(`/api/servers/${r}/agent`,{agentUrl:Ee.agentUrl}),u({variant:"success",title:"Agent gespeichert",description:"Agent-Einstellungen wurden aktualisiert."}),await It()}catch(dt){const Xe=((ot=(Ie=dt.response)==null?void 0:Ie.data)==null?void 0:ot.error)||dt.message||"Agent konnte nicht aktualisiert werden";u({variant:"error",title:"Agent speichern fehlgeschlagen",description:Xe})}finally{mt(!1)}}},[r,Ee,It,u]),Et=P.useCallback(async()=>{var ot,dt;if(!m||!r)return;const Ie=(M||"").trim();if(!Ie){u({variant:"warning",title:"API-Key fehlt",description:"Bitte gib einen API-Key ein."});return}z(!0);try{await i(r,Ie),u({variant:"success",title:"API-Key gespeichert",description:"Der neue API-Key wurde hinterlegt."}),D(""),await ft(),await At({silent:!0})}catch(Xe){const wt=((dt=(ot=Xe.response)==null?void 0:ot.data)==null?void 0:dt.error)||Xe.message||"API-Key konnte nicht gespeichert werden";u({variant:"error",title:"Speichern fehlgeschlagen",description:wt})}finally{z(!1)}},[M,m,r,i,ft,At,u]),Ht=P.useCallback(()=>{At()},[At]),qt=P.useCallback(async()=>{var ot,dt;if(!S||!r||j===r)return;const Ie=(C==null?void 0:C.name)||(C==null?void 0:C.url)||`Server ${r}`;if(!(typeof window<"u"&&!window.confirm(`Server "${Ie}" wirklich löschen?`))){k(r);try{await a(r),u({variant:"success",title:"Server gelöscht",description:`Server "${Ie}" wurde entfernt.`}),e("/dashboard/maintenance/servers")}catch(Xe){const wt=((dt=(ot=Xe.response)==null?void 0:ot.data)==null?void 0:dt.error)||Xe.message||"Server konnte nicht gelöscht werden";u({variant:"error",title:"Löschen fehlgeschlagen",description:wt})}finally{k(null)}}},[S,a,e,r,j,C,u]),Pt=P.useCallback(async()=>{var Ie,ot;if(!(!T||!r||!Ce))try{_e(!0),ve(""),await Je.put(`/api/setup/servers/${r}/update-script`,{script:me}),await xt(),u({variant:"success",title:"Skript gespeichert",description:"Das benutzerdefinierte Portainer-Update-Skript wurde aktualisiert."})}catch(dt){const Xe=((ot=(Ie=dt.response)==null?void 0:Ie.data)==null?void 0:ot.error)||dt.message||"Skript konnte nicht gespeichert werden";ve(Xe),u({variant:"error",title:"Speichern fehlgeschlagen",description:Xe})}finally{_e(!1)}},[T,r,Ce,me,xt,u]),Xr=P.useCallback(async()=>{var Ie,ot;if(!(!T||!r))try{_e(!0),ve(""),await Je.delete(`/api/setup/servers/${r}/update-script`),await xt(),u({variant:"info",title:"Standardskript wiederhergestellt",description:"Es wird wieder das Standard-Update-Skript verwendet."})}catch(dt){const Xe=((ot=(Ie=dt.response)==null?void 0:Ie.data)==null?void 0:ot.error)||dt.message||"Standardskript konnte nicht wiederhergestellt werden";ve(Xe),u({variant:"error",title:"Zurücksetzen fehlgeschlagen",description:Xe})}finally{_e(!1)}},[T,r,xt,u]),mr=P.useCallback((Ie,ot)=>{T&&(je(dt=>({...dt,[Ie]:ot})),Ie==="password"&&Te(!1))},[T]),dr=P.useCallback(async()=>{var Ie,ot;if(!(!T||!r))try{ye(!0),await Je.put(`/api/setup/servers/${r}/ssh-config`,J),Ue(null),ge(!1),await Rt(),u({variant:"success",title:"SSH-Konfiguration gespeichert",description:"Verbindungseinstellungen wurden aktualisiert."})}catch(dt){const Xe=((ot=(Ie=dt.response)==null?void 0:Ie.data)==null?void 0:ot.error)||dt.message||"SSH-Konfiguration konnte nicht gespeichert werden";bt(Xe),u({variant:"error",ti
Line truncated
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#eee}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Roboto,sans-serif;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#bdbdbd}input::placeholder,textarea::placeholder{opacity:1;color:#bdbdbd}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(33 150 243 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(33 150 243 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 540px){.container{max-width:540px}}@media (min-width: 720px){.container{max-width:720px}}@media (min-width: 960px){.container{max-width:960px}}@media (min-width: 1140px){.container{max-width:1140px}}@media (min-width: 1320px){.container{max-width:1320px}}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.\!invisible{visibility:hidden!important}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.\!absolute{position:absolute!important}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bLine truncated
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
function $j(e,t){for(var r=0;r<t.length;r++){const n=t[r];if(typeof n!="string"&&!Array.isArray(n)){for(const o in n)if(o!=="default"&&!(o in e)){const a=Object.getOwnPropertyDescriptor(n,o);a&&Object.defineProperty(e,o,a.get?a:{enumerable:!0,get:()=>n[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))n(o);new MutationObserver(o=>{for(const a of o)if(a.type==="childList")for(const i of a.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&n(i)}).observe(document,{childList:!0,subtree:!0});function r(o){const a={};return o.integrity&&(a.integrity=o.integrity),o.referrerPolicy&&(a.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?a.credentials="include":o.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function n(o){if(o.ep)return;o.ep=!0;const a=r(o);fetch(o.href,a)}})();function t_(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function lu(e){if(e.__esModule)return e;var t=e.default;if(typeof t=="function"){var r=function n(){return this instanceof n?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};r.prototype=t.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(e).forEach(function(n){var o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,o.get?o:{enumerable:!0,get:function(){return e[n]}})}),r}var r_={exports:{}},tf={},n_={exports:{}},xt={};/**
|
|
||||||
* @license React
|
|
||||||
* react.production.min.js
|
|
||||||
*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/var uu=Symbol.for("react.element"),Hj=Symbol.for("react.portal"),qj=Symbol.for("react.fragment"),Gj=Symbol.for("react.strict_mode"),Kj=Symbol.for("react.profiler"),Yj=Symbol.for("react.provider"),Qj=Symbol.for("react.context"),Xj=Symbol.for("react.forward_ref"),Zj=Symbol.for("react.suspense"),Jj=Symbol.for("react.memo"),e2=Symbol.for("react.lazy"),uy=Symbol.iterator;function t2(e){return e===null||typeof e!="object"?null:(e=uy&&e[uy]||e["@@iterator"],typeof e=="function"?e:null)}var o_={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},a_=Object.assign,i_={};function _s(e,t,r){this.props=e,this.context=t,this.refs=i_,this.updater=r||o_}_s.prototype.isReactComponent={};_s.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};_s.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function s_(){}s_.prototype=_s.prototype;function bg(e,t,r){this.props=e,this.context=t,this.refs=i_,this.updater=r||o_}var vg=bg.prototype=new s_;vg.constructor=bg;a_(vg,_s.prototype);vg.isPureReactComponent=!0;var cy=Array.isArray,l_=Object.prototype.hasOwnProperty,yg={current:null},u_={key:!0,ref:!0,__self:!0,__source:!0};function c_(e,t,r){var n,o={},a=null,i=null;if(t!=null)for(n in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(a=""+t.key),t)l_.call(t,n)&&!u_.hasOwnProperty(n)&&(o[n]=t[n]);var c=arguments.length-2;if(c===1)o.children=r;else if(1<c){for(var f=Array(c),g=0;g<c;g++)f[g]=arguments[g+2];o.children=f}if(e&&e.defaultProps)for(n in c=e.defaultProps,c)o[n]===void 0&&(o[n]=c[n]);return{$$typeof:uu,type:e,key:a,ref:i,props:o,_owner:yg.current}}function r2(e,t){return{$$typeof:uu,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}function xg(e){return typeof e=="object"&&e!==null&&e.$$typeof===uu}function n2(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(r){return t[r]})}var dy=/\/+/g;function Dp(e,t){return typeof e=="object"&&e!==null&&e.key!=null?n2(""+e.key):t.toString(36)}function kc(e,t,r,n,o){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case uu:case Hj:i=!0}}if(i)return i=e,o=o(i),e=n===""?"."+Dp(i,0):n,cy(o)?(r="",e!=null&&(r=e.replace(dy,"$&/")+"/"),kc(o,t,r,"",function(g){return g})):o!=null&&(xg(o)&&(o=r2(o,r+(!o.key||i&&i.key===o.key?"":(""+o.key).replace(dy,"$&/")+"/")+e)),t.push(o)),1;if(i=0,n=n===""?".":n+":",cy(e))for(var c=0;c<e.length;c++){a=e[c];var f=n+Dp(a,c);i+=kc(a,t,r,f,o)}else if(f=t2(e),typeof f=="function")for(e=f.call(e),c=0;!(a=e.next()).done;)a=a.value,f=n+Dp(a,c++),i+=kc(a,t,r,f,o);else if(a==="object")throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return i}function Ju(e,t,r){if(e==null)return e;var n=[],o=0;return kc(e,n,"","",function(a){return t.call(r,a,o++)}),n}function o2(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r)},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var Br={current:null},Nc={transition:null},a2={ReactCurrentDispatcher:Br,ReactCurrentBatchConfig:Nc,ReactCurrentOwner:yg};xt.Children={map:Ju,forEach:function(e,t,r){Ju(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return Ju(e,function(){t++}),t},toArray:function(e){return Ju(e,function(t){return t})||[]},only:function(e){if(!xg(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};xt.Component=_s;xt.Fragment=qj;xt.Profiler=Kj;xt.PureComponent=bg;xt.StrictMode=Gj;xt.Suspense=Zj;xt.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=a2;xt.cloneElement=function(e,t,r){if(e==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var n=a_({},e.props),o=e.key,a=e.ref,i=e._owner;if(t!=null){if(t.ref!==void 0&&(a=t.ref,i=yg.current),t.key!==void 0&&(o=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(f in t)l_.call(t,f)&&!u_.hasOwnProperty(f)&&(n[f]=t[f]===void 0&&c!==void 0?c[f]:t[f])}var f=arguments.length-2;if(f===1)n.children=r;else if(1<f){c=Array(f);for(var g=0;g<f;g++)c[g]=arguments[g+2];n.children=c}return{$$typeof:uu,type:e.type,key:o,ref:a,props:n,_owner:i}};xt.createContext=function(e){return e={$$typeof:Qj,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null},e.Provider={$$typeof:Yj,_conLine truncated
|
|
||||||
* @license React
|
|
||||||
* react-jsx-runtime.production.min.js
|
|
||||||
*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/var i2=P,s2=Symbol.for("react.element"),l2=Symbol.for("react.fragment"),u2=Object.prototype.hasOwnProperty,c2=i2.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,d2={key:!0,ref:!0,__self:!0,__source:!0};function d_(e,t,r){var n,o={},a=null,i=null;r!==void 0&&(a=""+r),t.key!==void 0&&(a=""+t.key),t.ref!==void 0&&(i=t.ref);for(n in t)u2.call(t,n)&&!d2.hasOwnProperty(n)&&(o[n]=t[n]);if(e&&e.defaultProps)for(n in t=e.defaultProps,t)o[n]===void 0&&(o[n]=t[n]);return{$$typeof:s2,type:e,key:a,ref:i,props:o,_owner:c2.current}}tf.Fragment=l2;tf.jsx=d_;tf.jsxs=d_;r_.exports=tf;var y=r_.exports;function f_(e,t){return function(){return e.apply(t,arguments)}}const{toString:f2}=Object.prototype,{getPrototypeOf:_g}=Object,rf=(e=>t=>{const r=f2.call(t);return e[r]||(e[r]=r.slice(8,-1).toLowerCase())})(Object.create(null)),ro=e=>(e=e.toLowerCase(),t=>rf(t)===e),nf=e=>t=>typeof t===e,{isArray:Ss}=Array,Ml=nf("undefined");function p2(e){return e!==null&&!Ml(e)&&e.constructor!==null&&!Ml(e.constructor)&&ln(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const p_=ro("ArrayBuffer");function h2(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&p_(e.buffer),t}const g2=nf("string"),ln=nf("function"),h_=nf("number"),of=e=>e!==null&&typeof e=="object",m2=e=>e===!0||e===!1,Ec=e=>{if(rf(e)!=="object")return!1;const t=_g(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)},b2=ro("Date"),v2=ro("File"),y2=ro("Blob"),x2=ro("FileList"),w2=e=>of(e)&&ln(e.pipe),_2=e=>{let t;return e&&(typeof FormData=="function"&&e instanceof FormData||ln(e.append)&&((t=rf(e))==="formdata"||t==="object"&&ln(e.toString)&&e.toString()==="[object FormData]"))},S2=ro("URLSearchParams"),[C2,T2,O2,P2]=["ReadableStream","Request","Response","Headers"].map(ro),k2=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function cu(e,t,{allOwnKeys:r=!1}={}){if(e===null||typeof e>"u")return;let n,o;if(typeof e!="object"&&(e=[e]),Ss(e))for(n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else{const a=r?Object.getOwnPropertyNames(e):Object.keys(e),i=a.length;let c;for(n=0;n<i;n++)c=a[n],t.call(null,e[c],c,e)}}function g_(e,t){t=t.toLowerCase();const r=Object.keys(e);let n=r.length,o;for(;n-- >0;)if(o=r[n],t===o.toLowerCase())return o;return null}const qa=(()=>typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global)(),m_=e=>!Ml(e)&&e!==qa;function Lh(){const{caseless:e}=m_(this)&&this||{},t={},r=(n,o)=>{const a=e&&g_(t,o)||o;Ec(t[a])&&Ec(n)?t[a]=Lh(t[a],n):Ec(n)?t[a]=Lh({},n):Ss(n)?t[a]=n.slice():t[a]=n};for(let n=0,o=arguments.length;n<o;n++)arguments[n]&&cu(arguments[n],r);return t}const N2=(e,t,r,{allOwnKeys:n}={})=>(cu(t,(o,a)=>{r&&ln(o)?e[a]=f_(o,r):e[a]=o},{allOwnKeys:n}),e),E2=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),j2=(e,t,r,n)=>{e.prototype=Object.create(t.prototype,n),e.prototype.constructor=e,Object.defineProperty(e,"super",{value:t.prototype}),r&&Object.assign(e.prototype,r)},A2=(e,t,r,n)=>{let o,a,i;const c={};if(t=t||{},e==null)return t;do{for(o=Object.getOwnPropertyNames(e),a=o.length;a-- >0;)i=o[a],(!n||n(i,e,t))&&!c[i]&&(t[i]=e[i],c[i]=!0);e=r!==!1&&_g(e)}while(e&&(!r||r(e,t))&&e!==Object.prototype);return t},R2=(e,t,r)=>{e=String(e),(r===void 0||r>e.length)&&(r=e.length),r-=t.length;const n=e.indexOf(t,r);return n!==-1&&n===r},M2=e=>{if(!e)return null;if(Ss(e))return e;let t=e.length;if(!h_(t))return null;const r=new Array(t);for(;t-- >0;)r[t]=e[t];return r},I2=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&_g(Uint8Array)),D2=(e,t)=>{const n=(e&&e[Symbol.iterator]).call(e);let o;for(;(o=n.next())&&!o.done;){const a=o.value;t.call(e,a[0],a[1])}},L2=(e,t)=>{let r;const n=[];for(;(r=e.exec(t))!==null;)n.push(r);return n},F2=ro("HTMLFormElement"),z2=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(r,n,o){return n.toUpperCase()+o}),fy=(({hasOwnProperty:e})=>(t,r)=>e.call(t,r))(Object.prototype),B2=ro("RegExp"),b_=(e,t)=>{const r=Object.getOwnPropertyDescriptors(e),n={};cu(r,(o,a)=>{let i;(i=t(o,a,e))!==!1&&(n[a]=i||o)}),Object.defineProperties(e,n)},V2=e=>{b_(e,(t,r)=>{if(ln(e)&&["arguments","caller","callee"].indexOf(r)!==-1)return!1;const n=e[r];if(ln(n)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+r+"'")})}})},U2=(e,t)=>{const r={},n=o=>{o.forEach(a=>{r[a]=!0})};return Ss(e)?n(e):n(String(e).split(t)),r},W2=()=>{},$2=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t,Lp="abcdefghijklmnopqrstuvwxyz",py="0123456789",v_={DIGIT:py,ALPHA:Lp,ALPHA_DIGIT:Lp+Lp.toUpperCase()+py},H2=(e=16,t=v_.ALPHA_DIGIT)=>{let r="";const{length:n}=t;for(;e--;)r+=t[Math.random()*n|0];return r};function q2(e){return!!(e&&ln(e.append)&&e[Symbol.toStringTag]==="FormData"&&e[Symbol.iterator])}const G2=e=>{const t=new Array(10),r=(n,o)=>{if(of(n)){if(t.indexOf(n)>=0)return;if(!("toJSON"in n)){t[o]=n;const a=SLine truncated
|
|
||||||
`).forEach(function(i){o=i.indexOf(":"),r=i.substring(0,o).trim().toLowerCase(),n=i.substring(o+1).trim(),!(!r||t[r]&&hA[r])&&(r==="set-cookie"?t[r]?t[r].push(n):t[r]=[n]:t[r]=t[r]?t[r]+", "+n:n)}),t},by=Symbol("internals");function Js(e){return e&&String(e).trim().toLowerCase()}function jc(e){return e===!1||e==null?e:_e.isArray(e)?e.map(jc):String(e)}function mA(e){const t=Object.create(null),r=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let n;for(;n=r.exec(e);)t[n[1]]=n[2];return t}const bA=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function Fp(e,t,r,n,o){if(_e.isFunction(n))return n.call(this,t,r);if(o&&(t=r),!!_e.isString(t)){if(_e.isString(n))return t.indexOf(n)!==-1;if(_e.isRegExp(n))return n.test(t)}}function vA(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,r,n)=>r.toUpperCase()+n)}function yA(e,t){const r=_e.toCamelCase(" "+t);["get","set","has"].forEach(n=>{Object.defineProperty(e,n+r,{value:function(o,a,i){return this[n].call(this,t,o,a,i)},configurable:!0})})}class sf{constructor(t){t&&this.set(t)}set(t,r,n){const o=this;function a(c,f,g){const b=Js(f);if(!b)throw new Error("header name must be a non-empty string");const S=_e.findKey(o,b);(!S||o[S]===void 0||g===!0||g===void 0&&o[S]!==!1)&&(o[S||f]=jc(c))}const i=(c,f)=>_e.forEach(c,(g,b)=>a(g,b,f));if(_e.isPlainObject(t)||t instanceof this.constructor)i(t,r);else if(_e.isString(t)&&(t=t.trim())&&!bA(t))i(gA(t),r);else if(_e.isHeaders(t))for(const[c,f]of t.entries())a(f,c,n);else t!=null&&a(r,t,n);return this}get(t,r){if(t=Js(t),t){const n=_e.findKey(this,t);if(n){const o=this[n];if(!r)return o;if(r===!0)return mA(o);if(_e.isFunction(r))return r.call(this,o,n);if(_e.isRegExp(r))return r.exec(o);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,r){if(t=Js(t),t){const n=_e.findKey(this,t);return!!(n&&this[n]!==void 0&&(!r||Fp(this,this[n],n,r)))}return!1}delete(t,r){const n=this;let o=!1;function a(i){if(i=Js(i),i){const c=_e.findKey(n,i);c&&(!r||Fp(n,n[c],c,r))&&(delete n[c],o=!0)}}return _e.isArray(t)?t.forEach(a):a(t),o}clear(t){const r=Object.keys(this);let n=r.length,o=!1;for(;n--;){const a=r[n];(!t||Fp(this,this[a],a,t,!0))&&(delete this[a],o=!0)}return o}normalize(t){const r=this,n={};return _e.forEach(this,(o,a)=>{const i=_e.findKey(n,a);if(i){r[i]=jc(o),delete r[a];return}const c=t?vA(a):String(a).trim();c!==a&&delete r[a],r[c]=jc(o),n[c]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const r=Object.create(null);return _e.forEach(this,(n,o)=>{n!=null&&n!==!1&&(r[o]=t&&_e.isArray(n)?n.join(", "):n)}),r}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,r])=>t+": "+r).join(`
|
|
||||||
`)}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...r){const n=new this(t);return r.forEach(o=>n.set(o)),n}static accessor(t){const n=(this[by]=this[by]={accessors:{}}).accessors,o=this.prototype;function a(i){const c=Js(i);n[c]||(yA(o,i),n[c]=!0)}return _e.isArray(t)?t.forEach(a):a(t),this}}sf.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);_e.reduceDescriptors(sf.prototype,({value:e},t)=>{let r=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(n){this[r]=n}}});_e.freezeMethods(sf);const Gn=sf;function zp(e,t){const r=this||Og,n=t||r,o=Gn.from(n.headers);let a=n.data;return _e.forEach(e,function(c){a=c.call(r,a,o.normalize(),t?t.status:void 0)}),o.normalize(),a}function P_(e){return!!(e&&e.__CANCEL__)}function Cs(e,t,r){mt.call(this,e??"canceled",mt.ERR_CANCELED,t,r),this.name="CanceledError"}_e.inherits(Cs,mt,{__CANCEL__:!0});function k_(e,t,r){const n=r.config.validateStatus;!r.status||!n||n(r.status)?e(r):t(new mt("Request failed with status code "+r.status,[mt.ERR_BAD_REQUEST,mt.ERR_BAD_RESPONSE][Math.floor(r.status/100)-4],r.config,r.request,r))}function xA(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function wA(e,t){e=e||10;const r=new Array(e),n=new Array(e);let o=0,a=0,i;return t=t!==void 0?t:1e3,function(f){const g=Date.now(),b=n[a];i||(i=g),r[o]=f,n[o]=g;let S=a,O=0;for(;S!==o;)O+=r[S++],S=S%e;if(o=(o+1)%e,o===a&&(a=(a+1)%e),g-i<t)return;const T=b&&g-b;return T?Math.round(O*1e3/T):void 0}}function _A(e,t){let r=0,n=1e3/t,o,a;const i=(g,b=Date.now())=>{r=b,o=null,a&&(clearTimeout(a),a=null),e.apply(null,g)};return[(...g)=>{const b=Date.now(),S=b-r;S>=n?i(g,b):(o=g,a||(a=setTimeout(()=>{a=null,i(o)},n-S)))},()=>o&&i(o)]}const ad=(e,t,r=3)=>{let n=0;const o=wA(50,250);return _A(a=>{const i=a.loaded,c=a.lengthComputable?a.total:void 0,f=i-n,g=o(f),b=i<=c;n=i;const S={loaded:i,total:c,progress:c?i/c:void 0,bytes:f,rate:g||void 0,estimated:g&&c&&b?(c-i)/g:void 0,event:a,lengthComputable:c!=null,[t?"download":"upload"]:!0};e(S)},r)},vy=(e,t)=>{const r=e!=null;return[n=>t[0]({lengthComputable:r,total:e,loaded:n}),t[1]]},yy=e=>(...t)=>_e.asap(()=>e(...t)),SA=un.hasStandardBrowserEnv?function(){const t=un.navigator&&/(msie|trident)/i.test(un.navigator.userAgent),r=document.createElement("a");let n;function o(a){let i=a;return t&&(r.setAttribute("href",i),i=r.href),r.setAttribute("href",i),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,""):"",host:r.host,search:r.search?r.search.replace(/^\?/,""):"",hash:r.hash?r.hash.replace(/^#/,""):"",hostname:r.hostname,port:r.port,pathname:r.pathname.charAt(0)==="/"?r.pathname:"/"+r.pathname}}return n=o(window.location.href),function(i){const c=_e.isString(i)?o(i):i;return c.protocol===n.protocol&&c.host===n.host}}():function(){return function(){return!0}}(),CA=un.hasStandardBrowserEnv?{write(e,t,r,n,o,a){const i=[e+"="+encodeURIComponent(t)];_e.isNumber(r)&&i.push("expires="+new Date(r).toGMTString()),_e.isString(n)&&i.push("path="+n),_e.isString(o)&&i.push("domain="+o),a===!0&&i.push("secure"),document.cookie=i.join("; ")},read(e){const t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove(e){this.write(e,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function TA(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function OA(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function N_(e,t){return e&&!TA(t)?OA(e,t):t}const xy=e=>e instanceof Gn?{...e}:e;function ti(e,t){t=t||{};const r={};function n(g,b,S){return _e.isPlainObject(g)&&_e.isPlainObject(b)?_e.merge.call({caseless:S},g,b):_e.isPlainObject(b)?_e.merge({},b):_e.isArray(b)?b.slice():b}function o(g,b,S){if(_e.isUndefined(b)){if(!_e.isUndefined(g))return n(void 0,g,S)}else return n(g,b,S)}function a(g,b){if(!_e.isUndefined(b))return n(void 0,b)}function i(g,b){if(_e.isUndefined(b)){if(!_e.isUndefined(g))return n(void 0,g)}else return n(void 0,b)}function c(g,b,S){if(S in t)return n(g,b);if(S in e)return n(void 0,g)}const f={url:a,method:a,data:a,baseURL:i,transformRequest:i,transformResponse:i,paramsSerializer:i,timeout:i,timeoutMessage:i,withCredentials:i,withXSRFToken:i,adapter:i,responseType:i,xsrfCookieName:i,xsrfHeaderName:i,onUploadProgress:i,onDownloadProgress:i,decompress:i,maxContentLength:i,maxBodyLength:i,beforeRedirect:i,transport:i,httpAgent:i,httpsAgent:i,cancelToken:i,socketPath:i,responseEncoding:i,validateStatus:c,headers:(g,b)=>o(xy(g),xy(b),!0)};return _e.forEach(Object.keys(Object.assign({},e,t)),function(b){const S=f[b]||o,O=S(e[b],t[b],b);_e.isUndefined(O)&&S!==c||(r[b]=O)}),r}const E_=e=>{const t=ti({},e);let{data:r,withXSRFToken:n,xsrfHeaderName:o,xsrfCookieName:a,headers:i,auth:c}=t;t.headers=i=Gn.from(i),t.url=C_(N_(t.baseURL,t.url),e.params,e.paramsSerializer),c&&i.set("Authorization","Basic "+btoa((c.username||"")+":"+(c.password?unescape(enco
Line truncated
|
|
||||||
`+a.map(Sy).join(`
|
|
||||||
`):" "+Sy(a[0]):"as no adapter specified";throw new mt("There is no suitable adapter to dispatch the request "+i,"ERR_NOT_SUPPORT")}return n},adapters:Uh};function Bp(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new Cs(null,e)}function Cy(e){return Bp(e),e.headers=Gn.from(e.headers),e.data=zp.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),R_.getAdapter(e.adapter||Og.adapter)(e).then(function(n){return Bp(e),n.data=zp.call(e,e.transformResponse,n),n.headers=Gn.from(n.headers),n},function(n){return P_(n)||(Bp(e),n&&n.response&&(n.response.data=zp.call(e,e.transformResponse,n.response),n.response.headers=Gn.from(n.response.headers))),Promise.reject(n)})}const M_="1.7.5",Pg={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{Pg[e]=function(n){return typeof n===e||"a"+(t<1?"n ":" ")+e}});const Ty={};Pg.transitional=function(t,r,n){function o(a,i){return"[Axios v"+M_+"] Transitional option '"+a+"'"+i+(n?". "+n:"")}return(a,i,c)=>{if(t===!1)throw new mt(o(i," has been removed"+(r?" in "+r:"")),mt.ERR_DEPRECATED);return r&&!Ty[i]&&(Ty[i]=!0,console.warn(o(i," has been deprecated since v"+r+" and will be removed in the near future"))),t?t(a,i,c):!0}};function FA(e,t,r){if(typeof e!="object")throw new mt("options must be an object",mt.ERR_BAD_OPTION_VALUE);const n=Object.keys(e);let o=n.length;for(;o-- >0;){const a=n[o],i=t[a];if(i){const c=e[a],f=c===void 0||i(c,a,e);if(f!==!0)throw new mt("option "+a+" must be "+f,mt.ERR_BAD_OPTION_VALUE);continue}if(r!==!0)throw new mt("Unknown option "+a,mt.ERR_BAD_OPTION)}}const Wh={assertOptions:FA,validators:Pg},Jo=Wh.validators;class sd{constructor(t){this.defaults=t,this.interceptors={request:new my,response:new my}}async request(t,r){try{return await this._request(t,r)}catch(n){if(n instanceof Error){let o;Error.captureStackTrace?Error.captureStackTrace(o={}):o=new Error;const a=o.stack?o.stack.replace(/^.+\n/,""):"";try{n.stack?a&&!String(n.stack).endsWith(a.replace(/^.+\n.+\n/,""))&&(n.stack+=`
|
|
||||||
`+a):n.stack=a}catch{}}throw n}}_request(t,r){typeof t=="string"?(r=r||{},r.url=t):r=t||{},r=ti(this.defaults,r);const{transitional:n,paramsSerializer:o,headers:a}=r;n!==void 0&&Wh.assertOptions(n,{silentJSONParsing:Jo.transitional(Jo.boolean),forcedJSONParsing:Jo.transitional(Jo.boolean),clarifyTimeoutError:Jo.transitional(Jo.boolean)},!1),o!=null&&(_e.isFunction(o)?r.paramsSerializer={serialize:o}:Wh.assertOptions(o,{encode:Jo.function,serialize:Jo.function},!0)),r.method=(r.method||this.defaults.method||"get").toLowerCase();let i=a&&_e.merge(a.common,a[r.method]);a&&_e.forEach(["delete","get","head","post","put","patch","common"],C=>{delete a[C]}),r.headers=Gn.concat(i,a);const c=[];let f=!0;this.interceptors.request.forEach(function(x){typeof x.runWhen=="function"&&x.runWhen(r)===!1||(f=f&&x.synchronous,c.unshift(x.fulfilled,x.rejected))});const g=[];this.interceptors.response.forEach(function(x){g.push(x.fulfilled,x.rejected)});let b,S=0,O;if(!f){const C=[Cy.bind(this),void 0];for(C.unshift.apply(C,c),C.push.apply(C,g),O=C.length,b=Promise.resolve(r);S<O;)b=b.then(C[S++],C[S++]);return b}O=c.length;let T=r;for(S=0;S<O;){const C=c[S++],x=c[S++];try{T=C(T)}catch(m){x.call(this,m);break}}try{b=Cy.call(this,T)}catch(C){return Promise.reject(C)}for(S=0,O=g.length;S<O;)b=b.then(g[S++],g[S++]);return b}getUri(t){t=ti(this.defaults,t);const r=N_(t.baseURL,t.url);return C_(r,t.params,t.paramsSerializer)}}_e.forEach(["delete","get","head","options"],function(t){sd.prototype[t]=function(r,n){return this.request(ti(n||{},{method:t,url:r,data:(n||{}).data}))}});_e.forEach(["post","put","patch"],function(t){function r(n){return function(a,i,c){return this.request(ti(c||{},{method:t,headers:n?{"Content-Type":"multipart/form-data"}:{},url:a,data:i}))}}sd.prototype[t]=r(),sd.prototype[t+"Form"]=r(!0)});const Ac=sd;class kg{constructor(t){if(typeof t!="function")throw new TypeError("executor must be a function.");let r;this.promise=new Promise(function(a){r=a});const n=this;this.promise.then(o=>{if(!n._listeners)return;let a=n._listeners.length;for(;a-- >0;)n._listeners[a](o);n._listeners=null}),this.promise.then=o=>{let a;const i=new Promise(c=>{n.subscribe(c),a=c}).then(o);return i.cancel=function(){n.unsubscribe(a)},i},t(function(a,i,c){n.reason||(n.reason=new Cs(a,i,c),r(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const r=this._listeners.indexOf(t);r!==-1&&this._listeners.splice(r,1)}static source(){let t;return{token:new kg(function(o){t=o}),cancel:t}}}const zA=kg;function BA(e){return function(r){return e.apply(null,r)}}function VA(e){return _e.isObject(e)&&e.isAxiosError===!0}const $h={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries($h).forEach(([e,t])=>{$h[t]=e});const UA=$h;function I_(e){const t=new Ac(e),r=f_(Ac.prototype.request,t);return _e.extend(r,Ac.prototype,t,{allOwnKeys:!0}),_e.extend(r,t,null,{allOwnKeys:!0}),r.create=function(o){return I_(ti(e,o))},r}const ur=I_(Og);ur.Axios=Ac;ur.CanceledError=Cs;ur.CancelToken=zA;ur.isCancel=P_;ur.VERSION=M_;ur.toFormData=af;ur.AxiosError=mt;ur.Cancel=ur.CanceledError;ur.all=function(t){return Promise.all(t)};ur.spread=BA;ur.isAxiosError=VA;ur.mergeConfig=ti;ur.AxiosHeaders=Gn;ur.formToJSON=e=>O_(_e.isHTMLForm(e)?new FormData(e):e);ur.getAdapter=R_.getAdapter;ur.HttpStatusCode=UA;ur.default=ur;const lt=ur;var Hh={},D_={exports:{}},hn={},L_={exports:{}},F_={};/**
|
|
||||||
* @license React
|
|
||||||
* scheduler.production.min.js
|
|
||||||
*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/(function(e){function t(q,z){var $=q.length;q.push(z);e:for(;0<$;){var K=$-1>>>1,X=q[K];if(0<o(X,z))q[K]=z,q[$]=X,$=K;else break e}}function r(q){return q.length===0?null:q[0]}function n(q){if(q.length===0)return null;var z=q[0],$=q.pop();if($!==z){q[0]=$;e:for(var K=0,X=q.length,te=X>>>1;K<te;){var me=2*(K+1)-1,de=q[me],ee=me+1,Se=q[ee];if(0>o(de,$))ee<X&&0>o(Se,de)?(q[K]=Se,q[ee]=$,K=ee):(q[K]=de,q[me]=$,K=me);else if(ee<X&&0>o(Se,$))q[K]=Se,q[ee]=$,K=ee;else break e}}return z}function o(q,z){var $=q.sortIndex-z.sortIndex;return $!==0?$:q.id-z.id}if(typeof performance=="object"&&typeof performance.now=="function"){var a=performance;e.unstable_now=function(){return a.now()}}else{var i=Date,c=i.now();e.unstable_now=function(){return i.now()-c}}var f=[],g=[],b=1,S=null,O=3,T=!1,C=!1,x=!1,m=typeof setTimeout=="function"?setTimeout:null,d=typeof clearTimeout=="function"?clearTimeout:null,s=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function u(q){for(var z=r(g);z!==null;){if(z.callback===null)n(g);else if(z.startTime<=q)n(g),z.sortIndex=z.expirationTime,t(f,z);else break;z=r(g)}}function l(q){if(x=!1,u(q),!C)if(r(f)!==null)C=!0,U(h);else{var z=r(g);z!==null&&Y(l,z.startTime-q)}}function h(q,z){C=!1,x&&(x=!1,d(j),j=-1),T=!0;var $=O;try{for(u(z),S=r(f);S!==null&&(!(S.expirationTime>z)||q&&!A());){var K=S.callback;if(typeof K=="function"){S.callback=null,O=S.priorityLevel;var X=K(S.expirationTime<=z);z=e.unstable_now(),typeof X=="function"?S.callback=X:S===r(f)&&n(f),u(z)}else n(f);S=r(f)}if(S!==null)var te=!0;else{var me=r(g);me!==null&&Y(l,me.startTime-z),te=!1}return te}finally{S=null,O=$,T=!1}}var v=!1,w=null,j=-1,N=5,k=-1;function A(){return!(e.unstable_now()-k<N)}function M(){if(w!==null){var q=e.unstable_now();k=q;var z=!0;try{z=w(!0,q)}finally{z?D():(v=!1,w=null)}}else v=!1}var D;if(typeof s=="function")D=function(){s(M)};else if(typeof MessageChannel<"u"){var L=new MessageChannel,B=L.port2;L.port1.onmessage=M,D=function(){B.postMessage(null)}}else D=function(){m(M,0)};function U(q){w=q,v||(v=!0,D())}function Y(q,z){j=m(function(){q(e.unstable_now())},z)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(q){q.callback=null},e.unstable_continueExecution=function(){C||T||(C=!0,U(h))},e.unstable_forceFrameRate=function(q){0>q||125<q?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):N=0<q?Math.floor(1e3/q):5},e.unstable_getCurrentPriorityLevel=function(){return O},e.unstable_getFirstCallbackNode=function(){return r(f)},e.unstable_next=function(q){switch(O){case 1:case 2:case 3:var z=3;break;default:z=O}var $=O;O=z;try{return q()}finally{O=$}},e.unstable_pauseExecution=function(){},e.unstable_requestPaint=function(){},e.unstable_runWithPriority=function(q,z){switch(q){case 1:case 2:case 3:case 4:case 5:break;default:q=3}var $=O;O=q;try{return z()}finally{O=$}},e.unstable_scheduleCallback=function(q,z,$){var K=e.unstable_now();switch(typeof $=="object"&&$!==null?($=$.delay,$=typeof $=="number"&&0<$?K+$:K):$=K,q){case 1:var X=-1;break;case 2:X=250;break;case 5:X=1073741823;break;case 4:X=1e4;break;default:X=5e3}return X=$+X,q={id:b++,callback:z,priorityLevel:q,startTime:$,expirationTime:X,sortIndex:-1},$>K?(q.sortIndex=$,t(g,q),r(f)===null&&q===r(g)&&(x?(d(j),j=-1):x=!0,Y(l,$-K))):(q.sortIndex=X,t(f,q),C||T||(C=!0,U(h))),q},e.unstable_shouldYield=A,e.unstable_wrapCallback=function(q){var z=O;return function(){var $=O;O=z;try{return q.apply(this,arguments)}finally{O=$}}}})(F_);L_.exports=F_;var WA=L_.exports;/**
|
|
||||||
* @license React
|
|
||||||
* react-dom.production.min.js
|
|
||||||
*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/var z_=P,fn=WA;function Re(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=1;r<arguments.length;r++)t+="&args[]="+encodeURIComponent(arguments[r]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var B_=new Set,Il={};function di(e,t){is(e,t),is(e+"Capture",t)}function is(e,t){for(Il[e]=t,e=0;e<t.length;e++)B_.add(t[e])}var Fo=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),qh=Object.prototype.hasOwnProperty,$A=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Oy={},Py={};function HA(e){return qh.call(Py,e)?!0:qh.call(Oy,e)?!1:$A.test(e)?Py[e]=!0:(Oy[e]=!0,!1)}function qA(e,t,r,n){if(r!==null&&r.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return n?!1:r!==null?!r.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function GA(e,t,r,n){if(t===null||typeof t>"u"||qA(e,t,r,n))return!0;if(n)return!1;if(r!==null)switch(r.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Vr(e,t,r,n,o,a,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=n,this.attributeNamespace=o,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=i}var Cr={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Cr[e]=new Vr(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Cr[t]=new Vr(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Cr[e]=new Vr(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Cr[e]=new Vr(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Cr[e]=new Vr(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Cr[e]=new Vr(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Cr[e]=new Vr(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Cr[e]=new Vr(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Cr[e]=new Vr(e,5,!1,e.toLowerCase(),null,!1,!1)});var Ng=/[\-:]([a-z])/g;function Eg(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Ng,Eg);Cr[t]=new Vr(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Ng,Eg);Cr[t]=new Vr(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Ng,Eg);Cr[t]=new Vr(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Cr[e]=new Vr(e,1,!1,e.toLowerCase(),null,!1,!1)});Cr.xlinkHref=new Vr("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Cr[e]=new Vr(e,1,!1,e.toLowerCase(),null,!0,!0)});function jg(e,t,r,n){var o=Cr.hasOwnProperty(t)?Cr[t]:null;(o!==null?o.type!==0:n||!(2<t.length)||t[0]!=="o"&&t[0]!==
Line truncated
|
|
||||||
`+Vp+e}var Up=!1;function Wp(e,t){if(!e||Up)return"";Up=!0;var r=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(t,[])}catch(g){var n=g}Reflect.construct(e,[],t)}else{try{t.call()}catch(g){n=g}e.call(t.prototype)}else{try{throw Error()}catch(g){n=g}e()}}catch(g){if(g&&n&&typeof g.stack=="string"){for(var o=g.stack.split(`
|
|
||||||
`),a=n.stack.split(`
|
|
||||||
`),i=o.length-1,c=a.length-1;1<=i&&0<=c&&o[i]!==a[c];)c--;for(;1<=i&&0<=c;i--,c--)if(o[i]!==a[c]){if(i!==1||c!==1)do if(i--,c--,0>c||o[i]!==a[c]){var f=`
|
|
||||||
`+o[i].replace(" at new "," at ");return e.displayName&&f.includes("<anonymous>")&&(f=f.replace("<anonymous>",e.displayName)),f}while(1<=i&&0<=c);break}}}finally{Up=!1,Error.prepareStackTrace=r}return(e=e?e.displayName||e.name:"")?pl(e):""}function KA(e){switch(e.tag){case 5:return pl(e.type);case 16:return pl("Lazy");case 13:return pl("Suspense");case 19:return pl("SuspenseList");case 0:case 2:case 15:return e=Wp(e.type,!1),e;case 11:return e=Wp(e.type.render,!1),e;case 1:return e=Wp(e.type,!0),e;default:return""}}function Qh(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Di:return"Fragment";case Ii:return"Portal";case Gh:return"Profiler";case Ag:return"StrictMode";case Kh:return"Suspense";case Yh:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case U_:return(e.displayName||"Context")+".Consumer";case V_:return(e._context.displayName||"Context")+".Provider";case Rg:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Mg:return t=e.displayName||null,t!==null?t:Qh(e.type)||"Memo";case aa:t=e._payload,e=e._init;try{return Qh(e(t))}catch{}}return null}function YA(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Qh(t);case 8:return t===Ag?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ca(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function $_(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function QA(e){var t=$_(e)?"checked":"value",r=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),n=""+e[t];if(!e.hasOwnProperty(t)&&typeof r<"u"&&typeof r.get=="function"&&typeof r.set=="function"){var o=r.get,a=r.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(i){n=""+i,a.call(this,i)}}),Object.defineProperty(e,t,{enumerable:r.enumerable}),{getValue:function(){return n},setValue:function(i){n=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function tc(e){e._valueTracker||(e._valueTracker=QA(e))}function H_(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var r=t.getValue(),n="";return e&&(n=$_(e)?e.checked?"true":"false":e.value),e=n,e!==r?(t.setValue(e),!0):!1}function ld(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Xh(e,t){var r=t.checked;return rr({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:r??e._wrapperState.initialChecked})}function Ny(e,t){var r=t.defaultValue==null?"":t.defaultValue,n=t.checked!=null?t.checked:t.defaultChecked;r=Ca(t.value!=null?t.value:r),e._wrapperState={initialChecked:n,initialValue:r,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function q_(e,t){t=t.checked,t!=null&&jg(e,"checked",t,!1)}function Zh(e,t){q_(e,t);var r=Ca(t.value),n=t.type;if(r!=null)n==="number"?(r===0&&e.value===""||e.value!=r)&&(e.value=""+r):e.value!==""+r&&(e.value=""+r);else if(n==="submit"||n==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Jh(e,t.type,r):t.hasOwnProperty("defaultValue")&&Jh(e,t.type,Ca(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Ey(e,t,r){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var n=t.type;if(!(n!=="submit"&&n!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,r||t===e.value||(e.value=t),e.defaultValue=t}r=e.name,r!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,r!==""&&(e.name=r)}function Jh(e,t,r){(t!=="number"||ld(e.ownerDocument)!==e)&&(r==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+r&&(e.defaultValue=""+r))}var hl=Array.isArray;function Yi(e,t,r,n){if(e=e.options,t){t={};for(var o=0;o<r.length;o++)t["$"+r[o]]=!0;for(r=0;r<e.length;r++)o=t.hasOwnProperty("$"+e[r].value),e[r].selected!==o&&(e[r].selected=o),o&&n&&(e[r].defaultSelected=!0)}else{for(r=""+Ca(r),t=null,o=0;o<e.length;o++){if(e[o].value===r){e[o].selected=!0,n&&(e[o].defaultSelected=!0);return}t!==null||e[o].disabled||(t=e[o])}t!==null&&(t.selected=!0)}}function e0(e,t){if(t.dan
Line truncated
|
|
||||||
`).replace(iM,"")}function uc(e,t,r){if(t=Jy(t),Jy(e)!==t&&r)throw Error(Re(425))}function md(){}var p0=null,h0=null;function g0(e,t){return e==="textarea"||e==="noscript"||typeof t.children=="string"||typeof t.children=="number"||typeof t.dangerouslySetInnerHTML=="object"&&t.dangerouslySetInnerHTML!==null&&t.dangerouslySetInnerHTML.__html!=null}var m0=typeof setTimeout=="function"?setTimeout:void 0,sM=typeof clearTimeout=="function"?clearTimeout:void 0,ex=typeof Promise=="function"?Promise:void 0,lM=typeof queueMicrotask=="function"?queueMicrotask:typeof ex<"u"?function(e){return ex.resolve(null).then(e).catch(uM)}:m0;function uM(e){setTimeout(function(){throw e})}function rh(e,t){var r=t,n=0;do{var o=r.nextSibling;if(e.removeChild(r),o&&o.nodeType===8)if(r=o.data,r==="/$"){if(n===0){e.removeChild(o),Bl(t);return}n--}else r!=="$"&&r!=="$?"&&r!=="$!"||n++;r=o}while(r);Bl(t)}function ma(e){for(;e!=null;e=e.nextSibling){var t=e.nodeType;if(t===1||t===3)break;if(t===8){if(t=e.data,t==="$"||t==="$!"||t==="$?")break;if(t==="/$")return null}}return e}function tx(e){e=e.previousSibling;for(var t=0;e;){if(e.nodeType===8){var r=e.data;if(r==="$"||r==="$!"||r==="$?"){if(t===0)return e;t--}else r==="/$"&&t++}e=e.previousSibling}return null}var Os=Math.random().toString(36).slice(2),go="__reactFiber$"+Os,Hl="__reactProps$"+Os,zo="__reactContainer$"+Os,b0="__reactEvents$"+Os,cM="__reactListeners$"+Os,dM="__reactHandles$"+Os;function Ga(e){var t=e[go];if(t)return t;for(var r=e.parentNode;r;){if(t=r[zo]||r[go]){if(r=t.alternate,t.child!==null||r!==null&&r.child!==null)for(e=tx(e);e!==null;){if(r=e[go])return r;e=tx(e)}return t}e=r,r=e.parentNode}return null}function pu(e){return e=e[go]||e[zo],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function Bi(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(Re(33))}function pf(e){return e[Hl]||null}var v0=[],Vi=-1;function ka(e){return{current:e}}function qt(e){0>Vi||(e.current=v0[Vi],v0[Vi]=null,Vi--)}function Ut(e,t){Vi++,v0[Vi]=e.current,e.current=t}var Ta={},Rr=ka(Ta),Qr=ka(!1),ri=Ta;function ss(e,t){var r=e.type.contextTypes;if(!r)return Ta;var n=e.stateNode;if(n&&n.__reactInternalMemoizedUnmaskedChildContext===t)return n.__reactInternalMemoizedMaskedChildContext;var o={},a;for(a in r)o[a]=t[a];return n&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Xr(e){return e=e.childContextTypes,e!=null}function bd(){qt(Qr),qt(Rr)}function rx(e,t,r){if(Rr.current!==Ta)throw Error(Re(168));Ut(Rr,t),Ut(Qr,r)}function MS(e,t,r){var n=e.stateNode;if(t=t.childContextTypes,typeof n.getChildContext!="function")return r;n=n.getChildContext();for(var o in n)if(!(o in t))throw Error(Re(108,YA(e)||"Unknown",o));return rr({},r,n)}function vd(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Ta,ri=Rr.current,Ut(Rr,e),Ut(Qr,Qr.current),!0}function nx(e,t,r){var n=e.stateNode;if(!n)throw Error(Re(169));r?(e=MS(e,t,ri),n.__reactInternalMemoizedMergedChildContext=e,qt(Qr),qt(Rr),Ut(Rr,e)):qt(Qr),Ut(Qr,r)}var Ao=null,hf=!1,nh=!1;function IS(e){Ao===null?Ao=[e]:Ao.push(e)}function fM(e){hf=!0,IS(e)}function Na(){if(!nh&&Ao!==null){nh=!0;var e=0,t=Dt;try{var r=Ao;for(Dt=1;e<r.length;e++){var n=r[e];do n=n(!0);while(n!==null)}Ao=null,hf=!1}catch(o){throw Ao!==null&&(Ao=Ao.slice(e+1)),iS(Dg,Na),o}finally{Dt=t,nh=!1}}return null}var Ui=[],Wi=0,yd=null,xd=0,_n=[],Sn=0,ni=null,Ro=1,Mo="";function Wa(e,t){Ui[Wi++]=xd,Ui[Wi++]=yd,yd=e,xd=t}function DS(e,t,r){_n[Sn++]=Ro,_n[Sn++]=Mo,_n[Sn++]=ni,ni=e;var n=Ro;e=Mo;var o=32-Kn(n)-1;n&=~(1<<o),r+=1;var a=32-Kn(t)+o;if(30<a){var i=o-o%5;a=(n&(1<<i)-1).toString(32),n>>=i,o-=i,Ro=1<<32-Kn(t)+o|r<<o|n,Mo=a+e}else Ro=1<<a|r<<o|n,Mo=e}function Hg(e){e.return!==null&&(Wa(e,1),DS(e,1,0))}function qg(e){for(;e===yd;)yd=Ui[--Wi],Ui[Wi]=null,xd=Ui[--Wi],Ui[Wi]=null;for(;e===ni;)ni=_n[--Sn],_n[Sn]=null,Mo=_n[--Sn],_n[Sn]=null,Ro=_n[--Sn],_n[Sn]=null}var cn=null,an=null,Qt=!1,$n=null;function LS(e,t){var r=Tn(5,null,null,0);r.elementType="DELETED",r.stateNode=t,r.return=e,t=e.deletions,t===null?(e.deletions=[r],e.flags|=16):t.push(r)}function ox(e,t){switch(e.tag){case 5:var r=e.type;return t=t.nodeType!==1||r.toLowerCase()!==t.nodeName.toLowerCase()?null:t,t!==null?(e.stateNode=t,cn=e,an=ma(t.firstChild),!0):!1;case 6:return t=e.pendingProps===""||t.nodeType!==3?null:t,t!==null?(e.stateNode=t,cn=e,an=null,!0):!1;case 13:return t=t.nodeType!==8?null:t,t!==null?(r=ni!==null?{id:Ro,overflow:Mo}:null,e.memoizedState={dehydrated:t,treeContext:r,retryLane:1073741824},r=Tn(18,null,null,0),r.stateNode=t,r.return=e,e.child=r,cn=e,an=null,!0):!1;default:return!1}}function y0(e){return(e.mode&1)!==0&&(e.flags&128)===0}function x0(e){if(Qt){var t=an;if(t){var r=t;if(!ox(e,t)){if(y0(e))throw Error(Re(418));t=ma(r.nextSibling);var n=cn;t&&ox(e,t)?LS(n,r):(e.flags=e.flags&-4097|2,Qt=!1,cn=e)}}else{if(y0(e))throw Error(Re(418));e.flags=e.flags&-4097|2,Qt=!1,cn=e}}}function ax(e){
Line truncated
|
|
||||||
Error generating stack: `+a.message+`
|
|
||||||
`+a.stack}return{value:e,source:t,stack:o,digest:null}}function lh(e,t,r){return{value:e,source:null,stack:r??null,digest:t??null}}function C0(e,t){try{console.error(t.value)}catch(r){setTimeout(function(){throw r})}}var wM=typeof WeakMap=="function"?WeakMap:Map;function d5(e,t,r){r=Io(-1,r),r.tag=3,r.payload={element:null};var n=t.value;return r.callback=function(){kd||(kd=!0,M0=n),C0(e,t)},r}function f5(e,t,r){r=Io(-1,r),r.tag=3;var n=e.type.getDerivedStateFromError;if(typeof n=="function"){var o=t.value;r.payload=function(){return n(o)},r.callback=function(){C0(e,t)}}var a=e.stateNode;return a!==null&&typeof a.componentDidCatch=="function"&&(r.callback=function(){C0(e,t),typeof n!="function"&&(va===null?va=new Set([this]):va.add(this));var i=t.stack;this.componentDidCatch(t.value,{componentStack:i!==null?i:""})}),r}function px(e,t,r){var n=e.pingCache;if(n===null){n=e.pingCache=new wM;var o=new Set;n.set(t,o)}else o=n.get(t),o===void 0&&(o=new Set,n.set(t,o));o.has(r)||(o.add(r),e=IM.bind(null,e,t,r),t.then(e,e))}function hx(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function gx(e,t,r,n,o){return e.mode&1?(e.flags|=65536,e.lanes=o,e):(e===t?e.flags|=65536:(e.flags|=128,r.flags|=131072,r.flags&=-52805,r.tag===1&&(r.alternate===null?r.tag=17:(t=Io(-1,1),t.tag=2,ba(r,t,1))),r.lanes|=1),e)}var _M=$o.ReactCurrentOwner,Kr=!1;function Fr(e,t,r,n){t.child=e===null?$S(t,null,r,n):us(t,e.child,r,n)}function mx(e,t,r,n,o){r=r.render;var a=t.ref;return Ji(t,o),n=nm(e,t,r,n,a,o),r=om(),e!==null&&!Kr?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Vo(e,t,o)):(Qt&&r&&Hg(t),t.flags|=1,Fr(e,t,n,o),t.child)}function bx(e,t,r,n,o){if(e===null){var a=r.type;return typeof a=="function"&&!hm(a)&&a.defaultProps===void 0&&r.compare===null&&r.defaultProps===void 0?(t.tag=15,t.type=a,p5(e,t,a,n,o)):(e=Uc(r.type,null,n,t,t.mode,o),e.ref=t.ref,e.return=t,t.child=e)}if(a=e.child,!(e.lanes&o)){var i=a.memoizedProps;if(r=r.compare,r=r!==null?r:Ul,r(i,n)&&e.ref===t.ref)return Vo(e,t,o)}return t.flags|=1,e=xa(a,n),e.ref=t.ref,e.return=t,t.child=e}function p5(e,t,r,n,o){if(e!==null){var a=e.memoizedProps;if(Ul(a,n)&&e.ref===t.ref)if(Kr=!1,t.pendingProps=n=a,(e.lanes&o)!==0)e.flags&131072&&(Kr=!0);else return t.lanes=e.lanes,Vo(e,t,o)}return T0(e,t,r,n,o)}function h5(e,t,r){var n=t.pendingProps,o=n.children,a=e!==null?e.memoizedState:null;if(n.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},Ut(qi,on),on|=r;else{if(!(r&1073741824))return e=a!==null?a.baseLanes|r:r,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,Ut(qi,on),on|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},n=a!==null?a.baseLanes:r,Ut(qi,on),on|=n}else a!==null?(n=a.baseLanes|r,t.memoizedState=null):n=r,Ut(qi,on),on|=n;return Fr(e,t,o,r),t.child}function g5(e,t){var r=t.ref;(e===null&&r!==null||e!==null&&e.ref!==r)&&(t.flags|=512,t.flags|=2097152)}function T0(e,t,r,n,o){var a=Xr(r)?ri:Rr.current;return a=ss(t,a),Ji(t,o),r=nm(e,t,r,n,a,o),n=om(),e!==null&&!Kr?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Vo(e,t,o)):(Qt&&n&&Hg(t),t.flags|=1,Fr(e,t,r,o),t.child)}function vx(e,t,r,n,o){if(Xr(r)){var a=!0;vd(t)}else a=!1;if(Ji(t,o),t.stateNode===null)zc(e,t),US(t,r,n),S0(t,r,n,o),n=!0;else if(e===null){var i=t.stateNode,c=t.memoizedProps;i.props=c;var f=i.context,g=r.contextType;typeof g=="object"&&g!==null?g=Nn(g):(g=Xr(r)?ri:Rr.current,g=ss(t,g));var b=r.getDerivedStateFromProps,S=typeof b=="function"||typeof i.getSnapshotBeforeUpdate=="function";S||typeof i.UNSAFE_componentWillReceiveProps!="function"&&typeof i.componentWillReceiveProps!="function"||(c!==n||f!==g)&&ux(t,i,n,g),ia=!1;var O=t.memoizedState;i.state=O,Sd(t,n,i,o),f=t.memoizedState,c!==n||O!==f||Qr.current||ia?(typeof b=="function"&&(_0(t,r,b,n),f=t.memoizedState),(c=ia||lx(t,r,c,n,O,f,g))?(S||typeof i.UNSAFE_componentWillMount!="function"&&typeof i.componentWillMount!="function"||(typeof i.componentWillMount=="function"&&i.componentWillMount(),typeof i.UNSAFE_componentWillMount=="function"&&i.UNSAFE_componentWillMount()),typeof i.componentDidMount=="function"&&(t.flags|=4194308)):(typeof i.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=n,t.memoizedState=f),i.props=n,i.state=f,i.context=g,n=c):(typeof i.componentDidMount=="function"&&(t.flags|=4194308),n=!1)}else{i=t.stateNode,BS(e,t),c=t.memoizedProps,g=t.type===t.elementType?c:Vn(t.type,c),i.props=g,S=t.pendingProps,O=i.context,f=r.contextType,typeof f=="object"&&f!==null?f=Nn(f):(f=Xr(r)?ri:Rr.current,f=ss(t,f));var T=r.getDerivedStateFromProps;(b=typeof T=="function"||typeof i.getSnapshotBeforeUpdate=="function")||typeof i.UNSAFE_componentWillReceiveProps!="function"&&typeof i.componentWillReceiveProps!="function"||(c!==S||O!==f)&&ux(t,i,n,f),ia=!1,O=t.memoizedState,i.state=O,Sd(t,n,i,o);var C=t.memoizedS
Line truncated
|
|
||||||
* @remix-run/router v1.10.0
|
|
||||||
*
|
|
||||||
* Copyright (c) Remix Software Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE.md file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @license MIT
|
|
||||||
*/function Zl(){return Zl=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Zl.apply(this,arguments)}var fa;(function(e){e.Pop="POP",e.Push="PUSH",e.Replace="REPLACE"})(fa||(fa={}));const Ax="popstate";function qM(e){e===void 0&&(e={});function t(n,o){let{pathname:a,search:i,hash:c}=n.location;return F0("",{pathname:a,search:i,hash:c},o.state&&o.state.usr||null,o.state&&o.state.key||"default")}function r(n,o){return typeof o=="string"?o:Ad(o)}return KM(t,r,null,e)}function tr(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function ym(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function GM(){return Math.random().toString(36).substr(2,8)}function Rx(e,t){return{usr:e.state,key:e.key,idx:t}}function F0(e,t,r,n){return r===void 0&&(r=null),Zl({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?Ps(t):t,{state:r,key:t&&t.key||n||GM()})}function Ad(e){let{pathname:t="/",search:r="",hash:n=""}=e;return r&&r!=="?"&&(t+=r.charAt(0)==="?"?r:"?"+r),n&&n!=="#"&&(t+=n.charAt(0)==="#"?n:"#"+n),t}function Ps(e){let t={};if(e){let r=e.indexOf("#");r>=0&&(t.hash=e.substr(r),e=e.substr(0,r));let n=e.indexOf("?");n>=0&&(t.search=e.substr(n),e=e.substr(0,n)),e&&(t.pathname=e)}return t}function KM(e,t,r,n){n===void 0&&(n={});let{window:o=document.defaultView,v5Compat:a=!1}=n,i=o.history,c=fa.Pop,f=null,g=b();g==null&&(g=0,i.replaceState(Zl({},i.state,{idx:g}),""));function b(){return(i.state||{idx:null}).idx}function S(){c=fa.Pop;let m=b(),d=m==null?null:m-g;g=m,f&&f({action:c,location:x.location,delta:d})}function O(m,d){c=fa.Push;let s=F0(x.location,m,d);r&&r(s,m),g=b()+1;let u=Rx(s,g),l=x.createHref(s);try{i.pushState(u,"",l)}catch(h){if(h instanceof DOMException&&h.name==="DataCloneError")throw h;o.location.assign(l)}a&&f&&f({action:c,location:x.location,delta:1})}function T(m,d){c=fa.Replace;let s=F0(x.location,m,d);r&&r(s,m),g=b();let u=Rx(s,g),l=x.createHref(s);i.replaceState(u,"",l),a&&f&&f({action:c,location:x.location,delta:0})}function C(m){let d=o.location.origin!=="null"?o.location.origin:o.location.href,s=typeof m=="string"?m:Ad(m);return tr(d,"No window.location.(origin|href) available to create URL for href: "+s),new URL(s,d)}let x={get action(){return c},get location(){return e(o,i)},listen(m){if(f)throw new Error("A history only accepts one active listener");return o.addEventListener(Ax,S),f=m,()=>{o.removeEventListener(Ax,S),f=null}},createHref(m){return t(o,m)},createURL:C,encodeLocation(m){let d=C(m);return{pathname:d.pathname,search:d.search,hash:d.hash}},push:O,replace:T,go(m){return i.go(m)}};return x}var Mx;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(Mx||(Mx={}));function YM(e,t,r){r===void 0&&(r="/");let n=typeof t=="string"?Ps(t):t,o=Jl(n.pathname||"/",r);if(o==null)return null;let a=z5(e);QM(a);let i=null;for(let c=0;i==null&&c<a.length;++c)i=aI(a[c],sI(o));return i}function z5(e,t,r,n){t===void 0&&(t=[]),r===void 0&&(r=[]),n===void 0&&(n="");let o=(a,i,c)=>{let f={relativePath:c===void 0?a.path||"":c,caseSensitive:a.caseSensitive===!0,childrenIndex:i,route:a};f.relativePath.startsWith("/")&&(tr(f.relativePath.startsWith(n),'Absolute route path "'+f.relativePath+'" nested under path '+('"'+n+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),f.relativePath=f.relativePath.slice(n.length));let g=wa([n,f.relativePath]),b=r.concat(f);a.children&&a.children.length>0&&(tr(a.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+g+'".')),z5(a.children,t,b,g)),!(a.path==null&&!a.index)&&t.push({path:g,score:nI(g,a.index),routesMeta:b})};return e.forEach((a,i)=>{var c;if(a.path===""||!((c=a.path)!=null&&c.includes("?")))o(a,i);else for(let f of B5(a.path))o(a,i,f)}),t}function B5(e){let t=e.split("/");if(t.length===0)return[];let[r,...n]=t,o=r.endsWith("?"),a=r.replace(/\?$/,"");if(n.length===0)return o?[a,""]:[a];let i=B5(n.join("/")),c=[];return c.push(...i.map(f=>f===""?a:[a,f].join("/"))),o&&c.push(...i),c.map(f=>e.startsWith("/")&&f===""?"/":f)}function QM(e){e.sort((t,r)=>t.score!==r.score?r.score-t.score:oI(t.routesMeta.map(n=>n.childrenIndex),r.routesMeta.map(n=>n.childrenIndex)))}const XM=/^:\w+$/,ZM=3,JM=2,eI=1,tI=10,rI=-2,Ix=e=>e==="*";function nI(e,t){let r=e.split("/"),n=r.length;return r.some(Ix)&&(n+=rI),t&&(n+=JM),r.filter(o=>!Ix(o)).reduce((o,a)=>o+(XM.test(a)?ZM:a===""?eI:tI),n)}function oI(e,t){return e.length===t.length&&e.slice(0,-1).every((n,o)=>n===t[o])?e[e.length-1]-t[t.length-1]:0}function aI(e,t){let{routesMeta:r}=e,n={},o="/",a=[];for(let i=0;i<r.length;++i){let c=r[i],f=i===r.length-1,g=o==="/"?t:t.slice(o.length)||"/",b=z0({path:c.relativePath,caseSensitive:c.caseSensitive,end:f},g);if(!b)return null;Object.assign(n,b.paLine truncated
|
|
||||||
* React Router v6.17.0
|
|
||||||
*
|
|
||||||
* Copyright (c) Remix Software Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE.md file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @license MIT
|
|
||||||
*/function Rd(){return Rd=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Rd.apply(this,arguments)}const Cf=P.createContext(null),U5=P.createContext(null),pi=P.createContext(null),Tf=P.createContext(null),Ho=P.createContext({outlet:null,matches:[],isDataRoute:!1}),W5=P.createContext(null);function mI(e,t){let{relative:r}=t===void 0?{}:t;ks()||tr(!1);let{basename:n,navigator:o}=P.useContext(pi),{hash:a,pathname:i,search:c}=Of(e,{relative:r}),f=i;return n!=="/"&&(f=i==="/"?n:wa([n,i])),o.createHref({pathname:f,search:c,hash:a})}function ks(){return P.useContext(Tf)!=null}function Ea(){return ks()||tr(!1),P.useContext(Tf).location}function $5(e){P.useContext(pi).static||P.useLayoutEffect(e)}function So(){let{isDataRoute:e}=P.useContext(Ho);return e?NI():bI()}function bI(){ks()||tr(!1);let e=P.useContext(Cf),{basename:t,navigator:r}=P.useContext(pi),{matches:n}=P.useContext(Ho),{pathname:o}=Ea(),a=JSON.stringify(xm(n).map(f=>f.pathnameBase)),i=P.useRef(!1);return $5(()=>{i.current=!0}),P.useCallback(function(f,g){if(g===void 0&&(g={}),!i.current)return;if(typeof f=="number"){r.go(f);return}let b=wm(f,JSON.parse(a),o,g.relative==="path");e==null&&t!=="/"&&(b.pathname=b.pathname==="/"?t:wa([t,b.pathname])),(g.replace?r.replace:r.push)(b,g.state,g)},[t,r,a,o,e])}function H5(){let{matches:e}=P.useContext(Ho),t=e[e.length-1];return t?t.params:{}}function Of(e,t){let{relative:r}=t===void 0?{}:t,{matches:n}=P.useContext(Ho),{pathname:o}=Ea(),a=JSON.stringify(xm(n).map(i=>i.pathnameBase));return P.useMemo(()=>wm(e,JSON.parse(a),o,r==="path"),[e,a,o,r])}function vI(e,t){return yI(e,t)}function yI(e,t,r){ks()||tr(!1);let{navigator:n}=P.useContext(pi),{matches:o}=P.useContext(Ho),a=o[o.length-1],i=a?a.params:{};a&&a.pathname;let c=a?a.pathnameBase:"/";a&&a.route;let f=Ea(),g;if(t){var b;let x=typeof t=="string"?Ps(t):t;c==="/"||(b=x.pathname)!=null&&b.startsWith(c)||tr(!1),g=x}else g=f;let S=g.pathname||"/",O=c==="/"?S:S.slice(c.length)||"/",T=YM(e,{pathname:O}),C=CI(T&&T.map(x=>Object.assign({},x,{params:Object.assign({},i,x.params),pathname:wa([c,n.encodeLocation?n.encodeLocation(x.pathname).pathname:x.pathname]),pathnameBase:x.pathnameBase==="/"?c:wa([c,n.encodeLocation?n.encodeLocation(x.pathnameBase).pathname:x.pathnameBase])})),o,r);return t&&C?P.createElement(Tf.Provider,{value:{location:Rd({pathname:"/",search:"",hash:"",state:null,key:"default"},g),navigationType:fa.Pop}},C):C}function xI(){let e=kI(),t=hI(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),r=e instanceof Error?e.stack:null,o={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"},a=null;return P.createElement(P.Fragment,null,P.createElement("h2",null,"Unexpected Application Error!"),P.createElement("h3",{style:{fontStyle:"italic"}},t),r?P.createElement("pre",{style:o},r):null,a)}const wI=P.createElement(xI,null);class _I extends P.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,r){return r.location!==t.location||r.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error||r.error,location:r.location,revalidation:t.revalidation||r.revalidation}}componentDidCatch(t,r){console.error("React Router caught the following error during render",t,r)}render(){return this.state.error?P.createElement(Ho.Provider,{value:this.props.routeContext},P.createElement(W5.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function SI(e){let{routeContext:t,match:r,children:n}=e,o=P.useContext(Cf);return o&&o.static&&o.staticContext&&(r.route.errorElement||r.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=r.route.id),P.createElement(Ho.Provider,{value:t},n)}function CI(e,t,r){var n;if(t===void 0&&(t=[]),r===void 0&&(r=null),e==null){var o;if((o=r)!=null&&o.errors)e=r.matches;else return null}let a=e,i=(n=r)==null?void 0:n.errors;if(i!=null){let c=a.findIndex(f=>f.route.id&&(i==null?void 0:i[f.route.id]));c>=0||tr(!1),a=a.slice(0,Math.min(a.length,c+1))}return a.reduceRight((c,f,g)=>{let b=f.route.id?i==null?void 0:i[f.route.id]:null,S=null;r&&(S=f.route.errorElement||wI);let O=t.concat(a.slice(0,g+1)),T=()=>{let C;return b?C=S:f.route.Component?C=P.createElement(f.route.Component,null):f.route.element?C=f.route.element:C=c,P.createElement(SI,{match:f,routeContext:{outlet:c,matches:O,isDataRoute:r!=null},children:C})};return r&&(f.route.ErrorBoundary||f.route.errorElement||g===0)?P.createElement(_I,{location:r.location,revalidation:r.revalidation,component:S,error:b,children:T(),routeContext:{outlet:null,matches:O,isDataRoute:!0}}):T()},null)}var q5=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable=Line truncated
|
|
||||||
* React Router DOM v6.17.0
|
|
||||||
*
|
|
||||||
* Copyright (c) Remix Software Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE.md file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @license MIT
|
|
||||||
*/function Id(){return Id=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Id.apply(this,arguments)}function K5(e,t){if(e==null)return{};var r={},n=Object.keys(e),o,a;for(a=0;a<n.length;a++)o=n[a],!(t.indexOf(o)>=0)&&(r[o]=e[o]);return r}function AI(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function RI(e,t){return e.button===0&&(!t||t==="_self")&&!AI(e)}const MI=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","unstable_viewTransition"],II=["aria-current","caseSensitive","className","end","style","to","unstable_viewTransition","children"],DI=P.createContext({isTransitioning:!1}),LI="startTransition",Dx=wg[LI];function FI(e){let{basename:t,children:r,future:n,window:o}=e,a=P.useRef();a.current==null&&(a.current=qM({window:o,v5Compat:!0}));let i=a.current,[c,f]=P.useState({action:i.action,location:i.location}),{v7_startTransition:g}=n||{},b=P.useCallback(S=>{g&&Dx?Dx(()=>f(S)):f(S)},[f,g]);return P.useLayoutEffect(()=>i.listen(b),[i,b]),P.createElement(jI,{basename:t,children:r,location:c.location,navigationType:c.action,navigator:i})}const zI=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",BI=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Y5=P.forwardRef(function(t,r){let{onClick:n,relative:o,reloadDocument:a,replace:i,state:c,target:f,to:g,preventScrollReset:b,unstable_viewTransition:S}=t,O=K5(t,MI),{basename:T}=P.useContext(pi),C,x=!1;if(typeof g=="string"&&BI.test(g)&&(C=g,zI))try{let u=new URL(window.location.href),l=g.startsWith("//")?new URL(u.protocol+g):new URL(g),h=Jl(l.pathname,T);l.origin===u.origin&&h!=null?g=h+l.search+l.hash:x=!0}catch{}let m=mI(g,{relative:o}),d=WI(g,{replace:i,state:c,target:f,preventScrollReset:b,relative:o,unstable_viewTransition:S});function s(u){n&&n(u),u.defaultPrevented||d(u)}return P.createElement("a",Id({},O,{href:C||m,onClick:x||a?n:s,ref:r,target:f}))}),VI=P.forwardRef(function(t,r){let{"aria-current":n="page",caseSensitive:o=!1,className:a="",end:i=!1,style:c,to:f,unstable_viewTransition:g,children:b}=t,S=K5(t,II),O=Of(f,{relative:S.relative}),T=Ea(),C=P.useContext(U5),{navigator:x}=P.useContext(pi),m=C!=null&&$I(O)&&g===!0,d=x.encodeLocation?x.encodeLocation(O).pathname:O.pathname,s=T.pathname,u=C&&C.navigation&&C.navigation.location?C.navigation.location.pathname:null;o||(s=s.toLowerCase(),u=u?u.toLowerCase():null,d=d.toLowerCase());let l=s===d||!i&&s.startsWith(d)&&s.charAt(d.length)==="/",h=u!=null&&(u===d||!i&&u.startsWith(d)&&u.charAt(d.length)==="/"),v={isActive:l,isPending:h,isTransitioning:m},w=l?n:void 0,j;typeof a=="function"?j=a(v):j=[a,l?"active":null,h?"pending":null,m?"transitioning":null].filter(Boolean).join(" ");let N=typeof c=="function"?c(v):c;return P.createElement(Y5,Id({},S,{"aria-current":w,className:j,ref:r,style:N,to:f,unstable_viewTransition:g}),typeof b=="function"?b(v):b)});var V0;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(V0||(V0={}));var Lx;(function(e){e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(Lx||(Lx={}));function UI(e){let t=P.useContext(Cf);return t||tr(!1),t}function WI(e,t){let{target:r,replace:n,state:o,preventScrollReset:a,relative:i,unstable_viewTransition:c}=t===void 0?{}:t,f=So(),g=Ea(),b=Of(e,{relative:i});return P.useCallback(S=>{if(RI(S,r)){S.preventDefault();let O=n!==void 0?n:Ad(g)===Ad(b);f(e,{replace:O,state:o,preventScrollReset:a,relative:i,unstable_viewTransition:c})}},[g,f,b,n,o,r,e,a,i,c])}function $I(e,t){t===void 0&&(t={});let r=P.useContext(DI);r==null&&tr(!1);let{basename:n}=UI(V0.useViewTransitionState),o=Of(e,{relative:t.relative});if(!r.isTransitioning)return!1;let a=Jl(r.currentLocation.pathname,n)||r.currentLocation.pathname,i=Jl(r.nextLocation.pathname,n)||r.nextLocation.pathname;return z0(o.pathname,i)!=null||z0(o.pathname,a)!=null}function HI({title:e,titleId:t,...r},n){return P.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",ref:n,"aria-labelledby":t},r),e?P.createElement("title",{id:t},e):null,P.createElement("path",{fillRule:"evenodd",d:"M7.5 3.75A1.5 1.5 0 006 5.25v13.5a1.5 1.5 0 001.5 1.5h6a1.5 1.5 0 001.5-1.5V15a.75.75 0 011.5 0v3.75a3 3 0 01-3 3h-6a3 3 0 01-3-3V5.25a3 3 0 013-3h6a3 3 0 013 3V9A.75.75 0 0115 9V5.25a1.5 1.5 0 00-1.5-1.5h-6zm5.03 4.72a.75.75 0 010 1.06l-1.72 1.72h10.94a.75.75 0 010 1.5H10.81l1.72 1.72a.75.75 0 11-1.06 1.06l-3-3a.75.75 0 010-1.06l3-3a.75.75 0 011.06 0z",clipRule:"evenodd"}))}const qI=P.forwardRef(HI),GI=qI;function KI({title:e,titleId:t,...r},n){return P.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",rLine truncated
|
|
||||||
Copyright (c) 2018 Jed Watson.
|
|
||||||
Licensed under the MIT License (MIT), see
|
|
||||||
http://jedwatson.github.io/classnames
|
|
||||||
*/(function(e){(function(){var t={}.hasOwnProperty;function r(){for(var n=[],o=0;o<arguments.length;o++){var a=arguments[o];if(a){var i=typeof a;if(i==="string"||i==="number")n.push(a);else if(Array.isArray(a)){if(a.length){var c=r.apply(null,a);c&&n.push(c)}}else if(i==="object"){if(a.toString!==Object.prototype.toString&&!a.toString.toString().includes("[native code]")){n.push(a.toString());continue}for(var f in a)t.call(a,f)&&a[f]&&n.push(f)}}}return n.join(" ")}e.exports?(r.default=r,e.exports=r):window.classNames=r})()})(Z5);var ct=Z5.exports,J5={exports:{}},Bn={};function Sm(){for(var e,t,r=0,n="";r<arguments.length;)(e=arguments[r++])&&(t=e1(e))&&(n&&(n+=" "),n+=t);return n}function e1(e){if(typeof e=="string")return e;for(var t,r="",n=0;n<e.length;n++)e[n]&&(t=e1(e[n]))&&(r&&(r+=" "),r+=t);return r}function U0(){return U0=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},U0.apply(this,arguments)}function S4(e){var t=function(r){var n=r.theme,o=r.prefix,a={nextPart:new Map,validators:[]};return function(i,c){return c?i.map(function(f){return[f[0],f[1].map(function(g){return typeof g=="string"?c+g:typeof g=="object"?Object.fromEntries(Object.entries(g).map(function(b){return[c+b[0],b[1]]})):g})]}):i}(Object.entries(r.classGroups),o).forEach(function(i){W0(i[1],a,i[0],n)}),a}(e);return{getClassGroupId:function(r){var n=r.split("-");return n[0]===""&&n.length!==1&&n.shift(),t1(n,t)||function(o){if(Fx.test(o)){var a=Fx.exec(o)[1],i=a==null?void 0:a.substring(0,a.indexOf(":"));if(i)return"arbitrary.."+i}}(r)},getConflictingClassGroupIds:function(r){return e.conflictingClassGroups[r]||[]}}}function t1(e,t){var r;if(e.length===0)return t.classGroupId;var n=t.nextPart.get(e[0]),o=n?t1(e.slice(1),n):void 0;if(o)return o;if(t.validators.length!==0){var a=e.join("-");return(r=t.validators.find(function(i){return(0,i.validator)(a)}))==null?void 0:r.classGroupId}}Object.defineProperty(Bn,"__esModule",{value:!0});var Fx=/^\[(.+)\]$/;function W0(e,t,r,n){e.forEach(function(o){if(typeof o!="string"){if(typeof o=="function")return o.isThemeGetter?void W0(o(n),t,r,n):void t.validators.push({validator:o,classGroupId:r});Object.entries(o).forEach(function(a){W0(a[1],zx(t,a[0]),r,n)})}else(o===""?t:zx(t,o)).classGroupId=r})}function zx(e,t){var r=e;return t.split("-").forEach(function(n){r.nextPart.has(n)||r.nextPart.set(n,{nextPart:new Map,validators:[]}),r=r.nextPart.get(n)}),r}function C4(e){if(e<1)return{get:function(){},set:function(){}};var t=0,r=new Map,n=new Map;function o(a,i){r.set(a,i),++t>e&&(t=0,n=r,r=new Map)}return{get:function(a){var i=r.get(a);return i!==void 0?i:(i=n.get(a))!==void 0?(o(a,i),i):void 0},set:function(a,i){r.has(a)?r.set(a,i):o(a,i)}}}function T4(e){var t=e.separator||":";return function(r){for(var n=0,o=[],a=0,i=0;i<r.length;i++){var c=r[i];n===0&&c===t[0]&&(t.length!==1&&r.slice(i,i+t.length)!==t||(o.push(r.slice(a,i)),a=i+t.length)),c==="["?n++:c==="]"&&n--}var f=o.length===0?r:r.substring(a),g=f.startsWith("!");return{modifiers:o,hasImportantModifier:g,baseClassName:g?f.substring(1):f}}}function O4(e){return U0({cache:C4(e.cacheSize),splitModifiers:T4(e)},S4(e))}var P4=/\s+/;function k4(e,t){var r=t.splitModifiers,n=t.getClassGroupId,o=t.getConflictingClassGroupIds,a=new Set;return e.trim().split(P4).map(function(i){var c=r(i),f=c.modifiers,g=c.hasImportantModifier,b=n(c.baseClassName);if(!b)return{isTailwindClass:!1,originalClassName:i};var S=function(O){if(O.length<=1)return O;var T=[],C=[];return O.forEach(function(x){x[0]==="["?(T.push.apply(T,C.sort().concat([x])),C=[]):C.push(x)}),T.push.apply(T,C.sort()),T}(f).join(":");return{isTailwindClass:!0,modifierId:g?S+"!":S,classGroupId:b,originalClassName:i}}).reverse().filter(function(i){if(!i.isTailwindClass)return!0;var c=i.modifierId,f=i.classGroupId,g=c+f;return!a.has(g)&&(a.add(g),o(f).forEach(function(b){return a.add(c+b)}),!0)}).reverse().map(function(i){return i.originalClassName}).join(" ")}function $0(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];var n,o,a,i=c;function c(g){var b=t[0],S=t.slice(1).reduce(function(O,T){return T(O)},b());return n=O4(S),o=n.cache.get,a=n.cache.set,i=f,f(g)}function f(g){var b=o(g);if(b)return b;var S=k4(g,n);return a(g,S),S}return function(){return i(Sm.apply(null,arguments))}}function Ht(e){var t=function(r){return r[e]||[]};return t.isThemeGetter=!0,t}var ja=/^\[(.+)\]$/,N4=/^\d+\/\d+$/,E4=new Set(["px","full","screen"]),j4=/^(\d+)?(xs|sm|md|lg|xl)$/,A4=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh)/,R4=/^-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;function xn(e){return!Number.isNaN(Number(e))||E4.has(e)||N4.test(e)||sa(e)}function sa(e){var t,r=(t=ja.exec(e))==null?void 0:t[1];return!!r&&(r.startsWith("length:")||A4.test(r))}function r1(e){var t,r=(t=ja.exec(e))==null?void 0:t[1];return!!r&&r.startsWLine truncated
|
|
||||||
* tabbable 6.2.0
|
|
||||||
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
|
|
||||||
*/var SF=["input:not([inert])","select:not([inert])","textarea:not([inert])","a[href]:not([inert])","button:not([inert])","[tabindex]:not(slot):not([inert])","audio[controls]:not([inert])","video[controls]:not([inert])",'[contenteditable]:not([contenteditable="false"]):not([inert])',"details>summary:first-of-type:not([inert])","details:not([inert])"],ag=SF.join(","),uP=typeof Element>"u",au=uP?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,Hd=!uP&&Element.prototype.getRootNode?function(e){var t;return e==null||(t=e.getRootNode)===null||t===void 0?void 0:t.call(e)}:function(e){return e==null?void 0:e.ownerDocument},qd=function e(t,r){var n;r===void 0&&(r=!0);var o=t==null||(n=t.getAttribute)===null||n===void 0?void 0:n.call(t,"inert"),a=o===""||o==="true",i=a||r&&t&&e(t.parentNode);return i},CF=function(t){var r,n=t==null||(r=t.getAttribute)===null||r===void 0?void 0:r.call(t,"contenteditable");return n===""||n==="true"},TF=function(t,r,n){if(qd(t))return[];var o=Array.prototype.slice.apply(t.querySelectorAll(ag));return r&&au.call(t,ag)&&o.unshift(t),o=o.filter(n),o},OF=function e(t,r,n){for(var o=[],a=Array.from(t);a.length;){var i=a.shift();if(!qd(i,!1))if(i.tagName==="SLOT"){var c=i.assignedElements(),f=c.length?c:i.children,g=e(f,!0,n);n.flatten?o.push.apply(o,g):o.push({scopeParent:i,candidates:g})}else{var b=au.call(i,ag);b&&n.filter(i)&&(r||!t.includes(i))&&o.push(i);var S=i.shadowRoot||typeof n.getShadowRoot=="function"&&n.getShadowRoot(i),O=!qd(S,!1)&&(!n.shadowRootFilter||n.shadowRootFilter(i));if(S&&O){var T=e(S===!0?i.children:S.children,!0,n);n.flatten?o.push.apply(o,T):o.push({scopeParent:i,candidates:T})}else a.unshift.apply(a,i.children)}}return o},cP=function(t){return!isNaN(parseInt(t.getAttribute("tabindex"),10))},dP=function(t){if(!t)throw new Error("No node provided");return t.tabIndex<0&&(/^(AUDIO|VIDEO|DETAILS)$/.test(t.tagName)||CF(t))&&!cP(t)?0:t.tabIndex},PF=function(t,r){var n=dP(t);return n<0&&r&&!cP(t)?0:n},kF=function(t,r){return t.tabIndex===r.tabIndex?t.documentOrder-r.documentOrder:t.tabIndex-r.tabIndex},fP=function(t){return t.tagName==="INPUT"},NF=function(t){return fP(t)&&t.type==="hidden"},EF=function(t){var r=t.tagName==="DETAILS"&&Array.prototype.slice.apply(t.children).some(function(n){return n.tagName==="SUMMARY"});return r},jF=function(t,r){for(var n=0;n<t.length;n++)if(t[n].checked&&t[n].form===r)return t[n]},AF=function(t){if(!t.name)return!0;var r=t.form||Hd(t),n=function(c){return r.querySelectorAll('input[type="radio"][name="'+c+'"]')},o;if(typeof window<"u"&&typeof window.CSS<"u"&&typeof window.CSS.escape=="function")o=n(window.CSS.escape(t.name));else try{o=n(t.name)}catch(i){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",i.message),!1}var a=jF(o,t.form);return!a||a===t},RF=function(t){return fP(t)&&t.type==="radio"},MF=function(t){return RF(t)&&!AF(t)},IF=function(t){var r,n=t&&Hd(t),o=(r=n)===null||r===void 0?void 0:r.host,a=!1;if(n&&n!==t){var i,c,f;for(a=!!((i=o)!==null&&i!==void 0&&(c=i.ownerDocument)!==null&&c!==void 0&&c.contains(o)||t!=null&&(f=t.ownerDocument)!==null&&f!==void 0&&f.contains(t));!a&&o;){var g,b,S;n=Hd(o),o=(g=n)===null||g===void 0?void 0:g.host,a=!!((b=o)!==null&&b!==void 0&&(S=b.ownerDocument)!==null&&S!==void 0&&S.contains(o))}}return a},pw=function(t){var r=t.getBoundingClientRect(),n=r.width,o=r.height;return n===0&&o===0},DF=function(t,r){var n=r.displayCheck,o=r.getShadowRoot;if(getComputedStyle(t).visibility==="hidden")return!0;var a=au.call(t,"details>summary:first-of-type"),i=a?t.parentElement:t;if(au.call(i,"details:not([open]) *"))return!0;if(!n||n==="full"||n==="legacy-full"){if(typeof o=="function"){for(var c=t;t;){var f=t.parentElement,g=Hd(t);if(f&&!f.shadowRoot&&o(f)===!0)return pw(t);t.assignedSlot?t=t.assignedSlot:!f&&g!==t.ownerDocument?t=g.host:t=f}t=c}if(IF(t))return!t.getClientRects().length;if(n!=="legacy-full")return!0}else if(n==="non-zero-area")return pw(t);return!1},LF=function(t){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(t.tagName))for(var r=t.parentElement;r;){if(r.tagName==="FIELDSET"&&r.disabled){for(var n=0;n<r.children.length;n++){var o=r.children.item(n);if(o.tagName==="LEGEND")return au.call(r,"fieldset[disabled] *")?!0:!o.contains(t)}return!0}r=r.parentElement}return!1},FF=function(t,r){return!(r.disabled||qd(r)||NF(r)||DF(r,t)||EF(r)||LF(r))},hw=function(t,r){return!(MF(r)||dP(r)<0||!FF(t,r))},zF=function(t){var r=parseInt(t.getAttribute("tabindex"),10);return!!(isNaN(r)||r>=0)},BF=function e(t){var r=[],n=[];return t.forEach(function(o,a){var i=!!o.scopeParent,c=i?o.scopeParent:o,f=PF(c,i),g=i?e(o.candidates):c;f===0?i?r.push.apply(r,g):r.push(c):n.push({documentOrder:a,tabIndex:f,item:o,isScope:i,content:g})}),n.sort(kF).reduce(function(o,a){return a.isScope?o.push.apply(o,a.content):o.push(a.content),o},[]).concatLine truncated
|
|
||||||
|
|
||||||
More details: https://www.material-tailwind.com/docs/react/collapse
|
|
||||||
`);var N=r.default.useRef(null),k=(0,g.useTheme)().navbar,A=k.styles,M=A.base.mobileNav;l=l??{},h=h??"";var D=(0,c.twMerge)((0,i.default)((0,f.default)(M)),h),L={unmount:{height:0,opacity:0,transition:{duration:.3,times:"[0.4, 0, 0.2, 1]"}},mount:{opacity:1,height:"".concat((j=N.current)===null||j===void 0?void 0:j.scrollHeight,"px"),transition:{duration:.3,times:"[0.4, 0, 0.2, 1]"}}},B=(0,a.default)(L,l),U=n.AnimatePresence,Y=(0,o.useMergeRefs)([s,N]);return r.default.createElement(n.LazyMotion,{features:n.domAnimation},r.default.createElement(U,null,r.default.createElement(n.m.div,S({},w,{ref:Y,className:D,initial:"unmount",exit:"unmount",animate:u?"mount":"unmount",variants:B}),v)))});x.displayName="MaterialTailwind.MobileNav",x.propTypes={open:b.propTypesOpen,animate:b.propTypesAnimate,className:b.propTypesClassName,children:b.propTypesChildren};var m=x})(tk);(function(e){Object.defineProperty(e,"__esModule",{value:!0});function t(s,u){for(var l in u)Object.defineProperty(s,l,{enumerable:!0,get:u[l]})}t(e,{Navbar:function(){return m},MobileNav:function(){return g.MobileNav},default:function(){return d}});var r=T(P),n=T(nt),o=T(ct),a=rt,i=T(Xt),c=T(et),f=Ze,g=tk,b=Pf;function S(s,u,l){return u in s?Object.defineProperty(s,u,{value:l,enumerable:!0,configurable:!0,writable:!0}):s[u]=l,s}function O(){return O=Object.assign||function(s){for(var u=1;u<arguments.length;u++){var l=arguments[u];for(var h in l)Object.prototype.hasOwnProperty.call(l,h)&&(s[h]=l[h])}return s},O.apply(this,arguments)}function T(s){return s&&s.__esModule?s:{default:s}}function C(s,u){if(s==null)return{};var l=x(s,u),h,v;if(Object.getOwnPropertySymbols){var w=Object.getOwnPropertySymbols(s);for(v=0;v<w.length;v++)h=w[v],!(u.indexOf(h)>=0)&&Object.prototype.propertyIsEnumerable.call(s,h)&&(l[h]=s[h])}return l}function x(s,u){if(s==null)return{};var l={},h=Object.keys(s),v,w;for(w=0;w<h.length;w++)v=h[w],!(u.indexOf(v)>=0)&&(l[v]=s[v]);return l}var m=r.default.forwardRef(function(s,u){var l=s.variant,h=s.color,v=s.shadow,w=s.blurred,j=s.fullWidth,N=s.className,k=s.children,A=C(s,["variant","color","shadow","blurred","fullWidth","className","children"]),M=(0,f.useTheme)().navbar,D=M.defaultProps,L=M.valid,B=M.styles,U=B.base,Y=B.variants;l=l??D.variant,h=h??D.color,v=v??D.shadow,w=w??D.blurred,j=j??D.fullWidth,N=N??D.className;var q,z=(0,o.default)((0,c.default)(U.navbar.initial),(q={},S(q,(0,c.default)(U.navbar.shadow),v),S(q,(0,c.default)(U.navbar.blurred),w&&h==="white"),S(q,(0,c.default)(U.navbar.fullWidth),j),q)),$=(0,o.default)((0,c.default)(Y[(0,i.default)(L.variants,l,"filled")][(0,i.default)(L.colors,h,"white")])),K=(0,a.twMerge)((0,o.default)(z,$),N);return r.default.createElement("nav",O({},A,{ref:u,className:K}),k)});m.propTypes={variant:n.default.oneOf(b.propTypesVariant),color:n.default.oneOf(b.propTypesColor),shadow:b.propTypesShadow,blurred:b.propTypesBlurred,fullWidth:b.propTypesFullWidth,className:b.propTypesClassName,children:b.propTypesChildren},m.displayName="MaterialTailwind.Navbar";var d=Object.assign(m,{MobileNav:g.MobileNav})})(ek);var rk={},Kf={},Ds={};(function(e){Object.defineProperty(e,"__esModule",{value:!0});function t(m,d){for(var s in d)Object.defineProperty(m,s,{enumerable:!0,get:d[s]})}t(e,{propTypesOpen:function(){return a},propTypesHandler:function(){return i},propTypesPlacement:function(){return c},propTypesOffset:function(){return f},propTypesDismiss:function(){return g},propTypesAnimate:function(){return b},propTypesContent:function(){return S},propTypesInteractive:function(){return O},propTypesClassName:function(){return T},propTypesChildren:function(){return C},propTypesContextValue:function(){return x}});var r=o(nt),n=Gt;function o(m){return m&&m.__esModule?m:{default:m}}var a=r.default.bool,i=r.default.func,c=n.propTypesPlacements,f=n.propTypesOffsetType,g=n.propTypesDismissType,b=n.propTypesAnimation,S=r.default.node,O=r.default.bool,T=r.default.string,C=r.default.node.isRequired,x=r.default.shape({open:r.default.bool.isRequired,strategy:r.default.oneOf(["fixed","absolute"]).isRequired,x:r.default.number,y:r.default.number,context:r.default.instanceOf(Object).isRequired,reference:r.default.func.isRequired,floating:r.default.func.isRequired,getReferenceProps:r.default.func.isRequired,getFloatingProps:r.default.func.isRequired,appliedAnimation:b.isRequired,labelId:r.default.string.isRequired,descriptionId:r.default.string.isRequired}).isRequired})(Ds);(function(e){Object.defineProperty(e,"__esModule",{value:!0});function t(f,g){for(var b in g)Object.defineProperty(f,b,{enumerable:!0,get:g[b]})}t(e,{PopoverContext:function(){return a},usePopover:function(){return i},PopoverContextProvider:function(){return c}});var r=o(P),n=Ds;function o(f){return f&&f.__esModule?f:{default:f}}var a=r.default.createContext(null);a.displayName="MaterialTailwind.PopoverContext";function i(){var f=r.default.useContext(a);if(!f)throw new Error("usePopover() must be used within a Popover. It happens when you us
Line truncated
|
|
||||||
${ie?"border-purple-500 ring-1 ring-purple-500/40":"border-transparent"}
|
|
||||||
${!Ce||se?"opacity-75 bg-stormGrey-200/20":""}`,children:[y.jsxs("div",{className:"flex items-center space-x-4",id:"left",children:[N&&y.jsx("input",{type:"checkbox",checked:ie,onChange:()=>je(ae.Id,!Ue),className:`h-5 w-5 text-purple-500 focus:ring-purple-400 border-gray-600 bg-gray-900 rounded ${Ue?"":"opacity-40 cursor-not-allowed"}`,disabled:!Ue}),y.jsx("div",{className:`w-12 h-12 flex items-center justify-center rounded-full
|
|
||||||
${ae.updateStatus==="✅"?"bg-mossGreen-600":ae.updateStatus==="⚠️"?"bg-warmAmberGlow-400":"bg-sunsetCoral-500"}`}),y.jsxs("div",{children:[y.jsx("p",{className:"text-lg antialiased font-sans font-semibold leading-normal text-inherit",children:ae.Name}),y.jsxs("p",{className:"text-sm antialiased font-sans font-light leading-normal text-inherit",children:["ID: ",ae.Id]}),ae.duplicateName&&y.jsx("p",{className:"text-xs text-amber-700",children:"⚠️ Doppelter Name erkannt"})]})]}),y.jsx("div",{className:"ml-auto flex flex-col items-end gap-1 text-sm",id:"right",children:ve?y.jsxs(y.Fragment,{children:[y.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-warmAmberGlow-600",children:"Redeploy"}),y.jsx("span",{className:"text-warmAmberGlow-500",children:"läuft…"})]}):oe?y.jsxs(y.Fragment,{children:[y.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-warmAmberGlow-600",children:"Redeploy"}),y.jsx("span",{className:"text-warmAmberGlow-500",children:"in Warteliste…"})]}):Oe?y.jsxs(y.Fragment,{children:[y.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-stormGrey-500",children:"System"}),y.jsx("span",{className:"text-gray-300",children:"Redeploy deaktiviert"})]}):he?y.jsxs(y.Fragment,{children:[y.jsx("span",{className:"antialiased font-sans font-light leading-normal text-xs uppercase tracking-wide text-stormGrey-500",children:"Status"}),y.jsx("span",{className:"text-mossGreen-600",children:"Aktuell"})]}):j?y.jsx(H.Button,{onClick:()=>Ge(ae.Id),disabled:L||se,className:"disabled:opacity-50 disabled:cursor-not-allowed",children:"Redeploy"}):null})]})},ae.Id)})}),y.jsx(Jf,{disabled:r||!!o})]})}const tV={idle:"Bereit",running:"Läuft",success:"Erfolgreich",error:"Fehlgeschlagen"},dl={idle:"bg-stormGrey-700 text-gray-200",running:"bg-arcticBlue-600 text-white",success:"bg-mossGreen-600 text-white",error:"bg-sunsetCoral-600 text-white"},rV={initializing:"Vorbereitung","activating-maintenance":"Wartungsmodus aktivieren","executing-script":"Skript wird ausgeführt",waiting:"Warte auf Portainer",completed:"Abgeschlossen",failed:"Fehlgeschlagen"},nV={info:"text-arcticBlue-700",success:"text-mossGreen-700",warning:"text-warmAmberGlow-700",error:"text-sunsetCoral-700",stdout:"text-stormGrey-700",stderr:"text-warmAmberGlow-700",debug:"text-lavenderSmoke-700"},oV=e=>{if(!e)return"-";const t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString("de-DE",{hour:"2-digit",minute:"2-digit",second:"2-digit"})},Ua=e=>{if(!e&&e!==0)return"-";const r=(n=>{if(n instanceof Date)return n;if(typeof n=="number"){const o=n>1e12?n:n*1e3;return new Date(o)}if(typeof n=="string"){const o=Number(n);if(!Number.isNaN(o)){const a=o>1e12?o:o*1e3;return new Date(a)}return new Date(n)}return null})(e);return!r||Number.isNaN(r.getTime())?String(e):r.toLocaleString("de-DE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})},Yw=e=>e===1?"Git":e===2?"Compose":e??"-",Mh=()=>({host:"",port:"22",username:"",password:"",extraSshArgs:""});function aV(){var Ws,Vu,Uu,$s;const{hasPermission:e,user:t}=Ur(),r=P.useCallback(()=>{},[]),{maintenance:n,update:o,script:a,ssh:i,loading:c,error:f,setMaintenanceMode:g,triggerUpdate:b,saveScript:S,resetScript:O,saveSshConfig:T,deleteSshConfig:C,testSshConnection:x,fetchSuperuserStatus:m,fetchSetupStatus:d,deleteSetupServer:s,updateSetupApiKey:u,updateSelfStackId:l,removeSuperuserAccount:h}=Aa(),v=!!(t!=null&&t.isSuperuser),w=!!(v||e("maintenance-access","read")),j=!!(v||e("maintenance-access","full")),N=!!(v||e("maintenance-server-manage","read")),k=!!(v||e("maintenance-server-manage","full")),A=!!(v||e("maintenance-server-delete","full")),M=!!(v||e("maintenance-superuser-delete","full")),D=!!(v||e("maintenance-portainer","read")),L=!!(v||e("maintenance-update","full")),B=!!(v||e("maintenance-ssh-update","read")),U=!!(v||e("maintenance-ssh-update","full")),Y=!!(v||e("maintenance-duplicates","read")),q=!!(v||e("maintenance-duplicates","full")),z=!!(n!=null&&n.active),$=n==null?void 0:n.message,K=(Ws=n==null?void 0:n.extra)==null?void 0:Ws.type,X=!!(o!=null&&o.running),te=z||X,[me,de]=P.useState(""),[ee,Se]=P.useState(!1),[pe,fe]=P.useState(!1),[be,ye]=P.useState(""),[Pe,Me]=P.useState(!1),[ke,ce]=P.useState(()=>Mh()),[je,He]=P.useState(!1),[qe,Je]=P.useState(!1),[Qe,Ge]=P.useState(!1),[Xe,ht]=P.useState(!1),[Ve,ot]=P.useState(!1),[_t,Ne]=P.useState(null);P.useEffect(()=>{if(!a)return;const xe=a.custom??a.default??a.effective??"";de(xe)},[a]),P.useEffect(()=>{if(!i){ce(Mh()),He(!1),Je(!1),Ne(null);return}ce({host:i.host??"",port:String(i.port??"22"),username:i.username??"",password:"",extraSshArgs:Array.isArray(i.extraSshArgs)?i.extraSshArgs.join(`
|
|
||||||
`):""}),He(!!i.passwordStored),Je(!1),Ne(null)},[i]);const at=P.useMemo(()=>a?a.source==="custom"&&typeof a.custom=="string"?a.custom:a.default??a.effective??"":"",[a]),Te=a?me!==at:!1,ae=(a==null?void 0:a.source)==="custom"?"Benutzerdefiniert":"Standard",[ge,oe]=P.useState(!0),[ve,se]=P.useState(!1),[ie,he]=P.useState(null),[Oe,Ce]=P.useState(""),[Ue,Fe]=P.useState(!1),[Ie,Ee]=P.useState(null),[dt,ft]=P.useState(!0),[Ft,Kt]=P.useState(""),[Pt,Rt]=P.useState({}),[hr,ir]=P.useState(null),[Jr,jn]=P.useState(null),[Mr,en]=P.useState(""),[wr,no]=P.useState(!1),[An,J]=P.useState(""),[Ae,Be]=P.useState([]),[Mt,yt]=P.useState(!0),[Et,It]=P.useState(""),[or,kt]=P.useState(!1),[Rn,Ir]=P.useState(null),[gr,Mn]=P.useState(null),oo=P.useRef(null),[Ct,Ra]=P.useState(null),[To,ao]=P.useState(!0),[io,Oo]=P.useState(""),[Ma,xi]=P.useState(!1),[wi,Ia]=P.useState(null),mn=P.useRef(null),jt=P.useCallback(async({silent:xe=!1}={})=>{var Le,ze;oe(!0),Ce("");try{const We=await m(),it=!!(We!=null&&We.exists);se(it),he(it?We.user??null:null)}catch(We){const it=((ze=(Le=We.response)==null?void 0:Le.data)==null?void 0:ze.error)||We.message||"Superuser-Status konnte nicht geladen werden";se(!1),he(null),Ce(it),xe||r({variant:"error",title:"Statusabfrage fehlgeschlagen",description:it})}finally{oe(!1)}},[m,r]),Nt=P.useCallback(async({silent:xe=!1}={})=>{var Le,ze;xe||ft(!0),Kt("");try{const We=await d();Ee(We),Rt({})}catch(We){const it=((ze=(Le=We.response)==null?void 0:Le.data)==null?void 0:ze.error)||We.message||"Setup-Daten konnten nicht geladen werden";Kt(it),xe||r({variant:"error",title:"Setup-Daten",description:it})}finally{ft(!1)}},[d,r]),zt=P.useCallback(async({silent:xe=!1}={})=>{if(mn.current)return mn.current;const Le=(async()=>{var ze,We;xe?xi(!0):ao(!0),Oo("");try{const Wt=(await lt.get("/api/maintenance/portainer-status")).data??{};Ra(Wt),Ia(new Date)}catch(it){const Wt=((We=(ze=it.response)==null?void 0:ze.data)==null?void 0:We.error)||it.message||"Fehler beim Prüfen des Portainer-Status";Oo(Wt),r({variant:"error",title:"Statusaktualisierung fehlgeschlagen",description:Wt})}finally{xe?xi(!1):ao(!1),mn.current=null}})();return mn.current=Le,Le},[r]),Or=P.useCallback(async({silent:xe=!1}={})=>{if(z||X){Be([]),It("Wartungsmodus aktiv – Duplikat-Verwaltung ist vorübergehend deaktiviert."),yt(!1),kt(!1);return}if(oo.current)return oo.current;const Le=(async()=>{var ze,We,it;xe?kt(!0):yt(!0),It("");try{const Vt=(await lt.get("/api/maintenance/duplicates")).data,rn=Array.isArray(Vt)?Vt:(Vt==null?void 0:Vt.items)??[];Be(rn),Mn(new Date)}catch(Wt){if(((ze=Wt.response)==null?void 0:ze.status)===423){const Vt="Wartungsmodus aktiv – Duplikat-Verwaltung ist vorübergehend deaktiviert.";Be([]),It(Vt),r({variant:"warning",title:"Duplikat-Verwaltung gesperrt",description:Vt})}else{const Vt=((it=(We=Wt.response)==null?void 0:We.data)==null?void 0:it.error)||Wt.message||"Fehler beim Laden der Wartungsdaten";It(Vt),r({variant:"error",title:"Duplikate konnten nicht geladen werden",description:Vt})}}finally{xe?kt(!1):yt(!1),oo.current=null}})();return oo.current=Le,Le},[z,X,r]);P.useEffect(()=>{jt({silent:!0})},[jt]),P.useEffect(()=>{Nt()},[Nt]),P.useEffect(()=>{zt()},[zt]),P.useEffect(()=>{Or()},[Or]);const tn=P.useMemo(()=>{var xe;return((xe=Ie==null?void 0:Ie.servers)==null?void 0:xe.items)??[]},[Ie]),so=P.useMemo(()=>{var Le;const xe=((Le=Ie==null?void 0:Ie.apiKeys)==null?void 0:Le.items)??[];return new Map(xe.map(ze=>[ze.serverId,ze]))},[Ie]),Da=P.useMemo(()=>!!(Ie!=null&&Ie.setupComplete),[Ie]),In=(Ie==null?void 0:Ie.selfStack)??null,Dn=(In==null?void 0:In.current)??"",_i=((Vu=Ie==null?void 0:Ie.envDefaults)==null?void 0:Vu.selfStackId)??"";P.useEffect(()=>{en(Dn||""),J("")},[Dn]);const Bs=Mr!==Dn,Si=P.useMemo(()=>{const xe=Array.isArray(Ae)?Ae.length:0,Le=Array.isArray(Ae)?Ae.reduce((ze,We)=>{var it;return ze+(((it=We==null?void 0:We.duplicates)==null?void 0:it.length)||0)},0):0;return{groups:xe,duplicateCount:Le}},[Ae]),La=P.useCallback((xe,Le)=>{U&&(ce(ze=>({...ze,[xe]:Le})),xe==="password"&&He(!1))},[U]),Ci=P.useMemo(()=>{const xe={host:ke.host.trim(),port:Number.parseInt(ke.port,10)||22,username:ke.username.trim(),extraSshArgs:(ke.extraSshArgs||"").split(/\r?\n/).map(ze=>ze.trim()).filter(Boolean)},Le=ke.password??"";return Le?xe.password=Le:je||(xe.password=""),xe},[ke,je]),ep=P.useCallback(async()=>{var xe,Le;if(U&&a)try{Se(!0),await S(me),r({variant:"success",title:"Skript gespeichert",description:"Das benutzerdefinierte Portainer-Update-Skript wurde aktualisiert."})}catch(ze){const We=((Le=(xe=ze.response)==null?void 0:xe.data)==null?void 0:Le.error)||ze.message||"Skript konnte nicht gespeichert werden";r({variant:"error",title:"Speichern fehlgeschlagen",description:We})}finally{Se(!1)}},[U,S,me,a,r]),Eu=P.useCallback(async()=>{var xe,Le;if(U)try{Se(!0),await O(),r({variant:"info",title:"Standardskript wiederhergestellt",description:"Es wird wieder das Standard-Update-Skript verwendet."})}catch(ze){const We=((Le=(xe=ze.
Line truncated
|
|
||||||
Dies setzt die Superuser-Einrichtung zurück.`)))try{Fe(!0);const We=await h(),it=Number((We==null?void 0:We.usersRemoved)??0);r({variant:"success",title:"Superuser gelöscht",description:it>1?`${it} Konten aus der Superuser-Gruppe wurden entfernt.`:"Superuser-Konto wurde entfernt."}),await jt({silent:!0})}catch(We){if(((xe=We.response)==null?void 0:xe.status)===404)await jt({silent:!0}),r({variant:"info",title:"Kein Superuser vorhanden",description:"Es ist kein Superuser mehr vorhanden."});else{const Wt=((ze=(Le=We.response)==null?void 0:Le.data)==null?void 0:ze.error)||We.message||"Superuser konnte nicht gelöscht werden";r({variant:"error",title:"Löschen fehlgeschlagen",description:Wt})}}finally{Fe(!1)}},[M,Ue,ge,ve,h,jt,r]),Ru=P.useCallback(async xe=>{var it,Wt;if(!A||Jr===xe)return;const Le=tn.find(Vt=>Vt.id===xe);if(!Le)return;const ze=Le.name||Le.url||`Server ${xe}`,We=[`Server "${ze}" wirklich löschen?`,"Das System benötigt anschließend erneut einen gültigen Server im Setup."].filter(Boolean).join(`
|
|
||||||
`);if(!(typeof window<"u"&&!window.confirm(We))){jn(xe);try{await s(xe),r({variant:"success",title:"Server gelöscht",description:`Server "${ze}" wurde entfernt.`}),await Nt({silent:!0})}catch(Vt){const rn=((Wt=(it=Vt.response)==null?void 0:it.data)==null?void 0:Wt.error)||Vt.message||"Server konnte nicht gelöscht werden.";r({variant:"error",title:"Server löschen fehlgeschlagen",description:rn})}finally{jn(null)}}},[A,s,Nt,Jr,tn,r]),Mu=P.useCallback((xe,Le)=>{k&&Rt(ze=>({...ze,[xe]:Le}))},[k]),Vs=P.useCallback(async xe=>{var ze,We;if(!k)return;const Le=(Pt[xe]??"").trim();if(!Le){r({variant:"warning",title:"API-Key fehlt",description:"Bitte gib einen API-Key ein."});return}if(hr!==xe){ir(xe);try{await u(xe,Le),r({variant:"success",title:"API-Key aktualisiert",description:"Der API-Key wurde gespeichert."}),Rt(it=>({...it,[xe]:""})),await Nt({silent:!0})}catch(it){const Wt=((We=(ze=it.response)==null?void 0:ze.data)==null?void 0:We.error)||it.message||"API-Key konnte nicht aktualisiert werden.";r({variant:"error",title:"Aktualisierung fehlgeschlagen",description:Wt})}finally{ir(null)}}},[Pt,hr,k,Nt,r,u]),Iu=P.useCallback(xe=>{k&&(en(xe),J(""))},[k]),tp=P.useCallback(async()=>{var Le,ze;if(!k||!Bs)return;no(!0),J("");const xe=typeof Mr=="string"?Mr.trim():"";try{await l(xe),r({variant:"success",title:"Self-Stack-ID gespeichert",description:xe?`Self-Stack-ID wurde auf "${xe}" gesetzt.`:"Self-Stack-ID wurde entfernt."}),await Nt({silent:!0})}catch(We){const it=((ze=(Le=We.response)==null?void 0:Le.data)==null?void 0:ze.error)||We.message||"Self-Stack-ID konnte nicht aktualisiert werden.";J(it),r({variant:"error",title:"Self-Stack-ID",description:it})}finally{no(!1)}},[k,Nt,Bs,Mr,r,l]),Du=P.useCallback(async()=>{var xe,Le;if(k&&!(!Mr&&!Dn)&&!(typeof window<"u"&&!window.confirm("Self-Stack-ID wirklich entfernen?"))){no(!0),J("");try{await l(""),en(""),r({variant:"success",title:"Self-Stack-ID entfernt",description:"Die Self-Stack-ID wurde gelöscht."}),await Nt({silent:!0})}catch(ze){const We=((Le=(xe=ze.response)==null?void 0:xe.data)==null?void 0:Le.error)||ze.message||"Self-Stack-ID konnte nicht entfernt werden.";J(We),r({variant:"error",title:"Self-Stack-ID",description:We})}finally{no(!1)}}},[k,Dn,Nt,Mr,r,l]),Oi=P.useCallback(async xe=>{var Le,ze;if(j&&!(c||Pe)&&xe!==z){if(X){r({variant:"warning",title:"Aktion nicht möglich",description:"Während eines laufenden Updates kann der Wartungsmodus nicht geändert werden."});return}Me(!0);try{const We=xe&&!!K,it={active:xe};We&&$?it.message=$:it.message=null,await g(it),r({variant:xe?"info":"success",title:xe?"Wartungsmodus aktiviert":"Wartungsmodus deaktiviert",description:xe?"Benutzer sehen jetzt die Wartungsseite.":"StackPulse steht wieder zur Verfügung."})}catch(We){const it=((ze=(Le=We.response)==null?void 0:Le.data)==null?void 0:ze.error)||We.message||"Wartungsmodus konnte nicht geändert werden";r({variant:"error",title:"Änderung fehlgeschlagen",description:it})}finally{Me(!1)}}},[j,c,Pe,z,X,g,$,K,r]),rp=P.useCallback(async()=>{var Le,ze;if(!L)return;if(z||X){r({variant:"warning",title:"Update nicht möglich",description:"Während eines aktiven Wartungsmodus kann kein weiteres Update gestartet werden."});return}const xe=(Ct==null?void 0:Ct.latestVersion)??(Ct==null?void 0:Ct.currentVersion)??"unbekannt";if(!(typeof window<"u"&&!window.confirm(`Portainer-Update starten?
|
|
||||||
Zielversion: ${xe}.
|
|
||||||
Während des Updates befindet sich StackPulse im Wartungsmodus.
|
|
||||||
Fortfahren?`)))try{ye(""),fe(!0),await b(),r({variant:"info",title:"Update gestartet",description:"Das Portainer-Update wurde gestartet."})}catch(We){const it=((ze=(Le=We.response)==null?void 0:Le.data)==null?void 0:ze.error)||We.message||"Portainer-Update konnte nicht gestartet werden";ye(it),r({variant:"error",title:"Update fehlgeschlagen",description:it})}finally{fe(!1)}},[L,z,X,Ct,b,r]),Lu=P.useCallback(async xe=>{var it,Wt,Vt,rn;if(!q||!xe)return;if(z||X){r({variant:"warning",title:"Aktion nicht möglich",description:"Während des Wartungsmodus sind Bereinigungen deaktiviert."});return}const Le=(it=xe.canonical)==null?void 0:it.Id;if(!Le)return;const ze=(xe.duplicates||[]).map(ko=>ko.Id).filter(Boolean);if(!ze.length)return;const We=((Wt=xe.canonical)==null?void 0:Wt.Name)||xe.name||`Stack ${Le}`;if(!(typeof window<"u"&&!window.confirm(`Bereinigung für "${We}" starten?
|
|
||||||
Es werden ${ze.length} Duplikate entfernt: ${ze.join(", ")}`))){Ir(String(Le));try{const Wr=(await lt.post("/api/maintenance/duplicates/cleanup",{canonicalId:Le,duplicateIds:ze})).data??{};if(Wr.success===!1)throw new Error(Wr.error||"Bereinigung fehlgeschlagen");const Pi=Array.isArray(Wr.results)?Wr.results.filter(za=>za.status==="deleted").map(za=>za.id):ze;r({variant:"success",title:"Bereinigung abgeschlossen",description:`${We} – entfernte IDs: ${Pi.join(", ")}`}),await Or({silent:!0})}catch(ko){const Wr=((rn=(Vt=ko.response)==null?void 0:Vt.data)==null?void 0:rn.error)||ko.message||"Bereinigung fehlgeschlagen";r({variant:"error",title:"Bereinigung fehlgeschlagen",description:Wr})}finally{Ir(null)}}},[q,Or,z,r,X]);n!=null&&n.activatedAt&&Ua(n.activatedAt),n!=null&&n.updatedAt&&Ua(n.updatedAt);const Ln=z||X,Fa=(o==null?void 0:o.status)??(X?"running":"idle"),Us=tV[Fa]??Fa,np=dl[Fa]??dl.idle,Fu=o!=null&&o.stage?rV[o.stage]??o.stage:"–",zu=(o==null?void 0:o.logs)??[],op=(o==null?void 0:o.targetVersion)??"-",ap=(o==null?void 0:o.resultVersion)??"-",ip=o!=null&&o.startedAt?Ua(o.startedAt):"-",sp=o!=null&&o.finishedAt?Ua(o.finishedAt):"-",Bu=(o==null?void 0:o.message)??(X?"Update läuft…":""),lo=X||ee||c;return w?y.jsxs("div",{className:"mt-12 mb-8 flex flex-col gap-12",children:[(z||X)&&y.jsx("div",{className:"rounded-lg border border-cyan-500/60 bg-cyan-900/30 px-4 py-3 text-sm text-bluegray-100",children:y.jsxs("div",{className:"flex flex-col gap-1",children:[y.jsxs("span",{children:["Wartungsmodus aktiv",$?` – ${$}`:X?" – Portainer-Update läuft":"","."]}),X&&y.jsxs("span",{className:"text-xs text-indigo-900",children:["Phase: ",Fu]})]})}),w&&y.jsxs(H.Card,{children:[y.jsx(H.CardHeader,{variant:"gradient",color:"gray",className:"mb-5 p-4",children:y.jsx(H.Typography,{variant:"h6",color:"white",className:"flex items-center justify-between",children:y.jsx("span",{children:"Wartungsmodus"})})}),y.jsxs(H.CardBody,{className:"flex flex-col gap-4 p-4",children:[y.jsxs("div",{className:"flex items-start justify-between gap-4",children:[y.jsx("div",{className:"space-y-1",children:y.jsx("p",{className:"text-sm antialiased font-sans text-sm font-light leading-normal text-inherit",children:"Schaltet StackPulse für Benutzer in den Wartungsmodus."})}),y.jsx(H.Switch,{checked:z,disabled:!j||Pe||c||X,onChange:xe=>Oi(xe.target.checked),ripple:!1,color:"amber"})]}),Pe&&y.jsx("p",{className:"text-xs text-stormGrey-500",children:"Wartungsmodus wird aktualisiert…"})]})]}),N&&y.jsxs(H.Card,{children:[y.jsx(H.CardHeader,{variant:"gradient",color:"gray",className:"mb-5 p-4",children:y.jsx(H.Typography,{variant:"h6",color:"white",className:"flex items-center justify-between",children:y.jsx("span",{children:"Server & API-Keys"})})}),y.jsxs(H.CardBody,{className:"flex flex-col gap-4 p-4",children:[dt&&y.jsx("p",{className:"text-sm text-stormGrey-500",children:"Daten werden geladen…"}),!dt&&Ft&&y.jsx(H.Alert,{color:"red",className:"border border-red-200 bg-red-50 text-red-700",children:Ft}),!dt&&!Ft&&y.jsxs("div",{className:"flex flex-col gap-6",children:[y.jsxs("div",{className:"flex flex-col gap-3",children:[y.jsxs("div",{className:"flex items-center justify-between",children:[y.jsx(H.Typography,{variant:"small",color:"blue-gray",className:"font-semibold uppercase",children:"Server"}),y.jsxs(H.Typography,{variant:"small",color:"blue-gray",children:[tn.length," vorhanden"]})]}),tn.length===0?y.jsx("p",{className:"text-sm text-stormGrey-500",children:"Es sind derzeit keine Server hinterlegt."}):y.jsx("div",{className:"flex flex-col gap-3",children:tn.map(xe=>{const Le=so.get(xe.id)||null,ze=!!(Le!=null&&Le.hasKey),We=Le!=null&&Le.updatedAt?new Date(Le.updatedAt).toLocaleString("de-DE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}):null;return y.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-blue-gray-100 p-3 md:flex-row md:items-start md:justify-between",children:[y.jsxs("div",{className:"flex flex-col gap-1",children:[y.jsx("p",{className:"text-sm font-medium text-stormGrey-900",children:xe.name||"Ohne Namen"}),y.jsx("p",{className:"text-xs text-stormGrey-500 break-all",children:xe.url}),y.jsxs("p",{className:"text-xs text-stormGrey-500",children:["API-Key: ",ze?"vorhanden":"nicht hinterlegt",We?` (aktualisiert am ${We})`:""]})]}),y.jsxs("div",{className:"flex w-full flex-col gap-2 md:max-w-xs",children:[y.jsx(H.Input,{type:"password",label:"Neuer API-Key",value:Pt[xe.id]??"",onChange:it=>Mu(xe.id,it.target.value),disabled:!k||dt||hr===xe.id}),y.jsxs("div",{className:"flex items-center gap-2 justify-end",children:[y.jsx(H.Button,{variant:"text",color:"red",size:"sm",onClick:()=>Ru(xe.id),disabled:te||!A||dt||Jr===xe.id||hr===xe.id,children:Jr===xe.id?"Lösche…":"Löschen"}),y.jsx(H.Button,{color:"blue",size:"sm",onClick:()=>Vs(xe.id),disabled:te||!k||dt||hr===xe.id,children:hr===xe.id?"Speichere…":"API-Key speichern"})]})]})]},xe.id)})})]}),y.jsxs("div",{clas
Line truncated
|
|
||||||
`)},kV=(e=[])=>{if(!Array.isArray(e))return[];const t=[];for(let r=0;r<e.length;r+=4)t.push(e.slice(r,r+4));return t};function NV(){const e=So(),{user:t,setSession:r,refreshSession:n}=Ur(),{maintenance:o,update:a}=Aa(),[i,c]=P.useState(!0),[f,g]=P.useState(""),[b,S]=P.useState([]),[O,T]=P.useState(!1),[C,x]=P.useState(!1),m=!!(t!=null&&t.requiresSecurityPhraseDownload),d=!!(o!=null&&o.active);o==null||o.message;const s=!!(a!=null&&a.running);a!=null&&a.stage&&(OV[a.stage]??a.stage);const u=d||s,l=P.useMemo(()=>kV(b),[b]),h=P.useCallback(N=>{if(!N)return;const k=new Blob([N],{type:"text/plain;charset=utf-8"}),A=URL.createObjectURL(k),M=document.createElement("a");M.href=A;const D=t!=null&&t.username?`${t.username}-sicherheitsschluessel`:"security-phrase";M.download=`${D}.txt`,document.body.appendChild(M),M.click(),document.body.removeChild(M),URL.revokeObjectURL(A)},[t==null?void 0:t.username]),v=P.useCallback(async()=>{var N,k,A,M,D,L,B,U;c(!0),g("");try{const Y=await lt.get("/api/users/me/security-phrase"),q=Array.isArray((k=(N=Y.data)==null?void 0:N.item)==null?void 0:k.words)?Y.data.item.words:[];if(!q.length)throw new Error("EMPTY_SECURITY_PHRASE");S(q),x(!1)}catch(Y){if(((A=Y==null?void 0:Y.response)==null?void 0:A.status)===409||((D=(M=Y==null?void 0:Y.response)==null?void 0:M.data)==null?void 0:D.error)==="SECURITY_PHRASE_ALREADY_DOWNLOADED"){await n(),e("/dashboard/stacks",{replace:!0});return}if(((L=Y==null?void 0:Y.response)==null?void 0:L.status)===401){await n(),e("/auth/sign-in",{replace:!0});return}const q=((U=(B=Y==null?void 0:Y.response)==null?void 0:B.data)==null?void 0:U.error)||(Y==null?void 0:Y.message)||"Sicherheitsschlüssel konnte nicht geladen werden.";g(q)}finally{c(!1)}},[e,n]);P.useEffect(()=>{if(!t){e("/auth/sign-in",{replace:!0});return}if(!m){e("/dashboard/stacks",{replace:!0});return}v()},[t,m,v,e]);const w=P.useCallback(()=>{v()},[v]),j=P.useCallback(async()=>{var N,k,A,M,D,L;if(!(O||!Array.isArray(b)||b.length===0)){T(!0),g("");try{const B=PV(b);h(B);const U=await lt.post("/api/users/me/security-phrase/downloaded"),Y=((k=(N=U.data)==null?void 0:N.item)==null?void 0:k.downloadedAt)||null,q=(A=U.data)==null?void 0:A.session;q!=null&&q.user?r(q):await n(),x(!!Y),e("/dashboard/stacks",{replace:!0})}catch(B){if(((M=B==null?void 0:B.response)==null?void 0:M.status)===401){await n(),e("/auth/sign-in",{replace:!0});return}const U=((L=(D=B==null?void 0:B.response)==null?void 0:D.data)==null?void 0:L.error)||(B==null?void 0:B.message)||"Download konnte nicht bestätigt werden.";g(U)}finally{T(!1)}}},[b,O,h,n,e,r]);return m?y.jsxs("div",{className:"flex min-h-screen flex-col items-center justify-center bg-blue-gray-50/50 px-4 py-10",children:[y.jsxs("div",{className:"mb-6 text-center",children:[y.jsx(H.Typography,{variant:"h2",className:"font-semibold text-blue-gray-800",children:"Sicherheitsschlüssel sichern"}),y.jsx(H.Typography,{color:"blue-gray",className:"mt-2 max-w-3xl text-base",children:"Bitte lade den einmaligen Sicherheitsschlüssel herunter und bewahre ihn sicher auf. Er wird benötigt, um dein Passwort zurückzusetzen. Ohne den Download kannst du die Anwendung nicht weiter nutzen."})]}),y.jsx(H.Card,{className:"w-full max-w-3xl shadow-lg",children:y.jsxs(H.CardBody,{className:"space-y-6",children:[i&&y.jsx("div",{className:"flex items-center justify-center py-10",children:y.jsx(H.Spinner,{className:"h-10 w-10 text-blue-gray-500"})}),!i&&f&&y.jsx(H.Alert,{color:"red",className:"border border-red-200 bg-red-50 text-red-700",icon:y.jsx(zz,{className:"h-5 w-5"}),children:y.jsxs("div",{className:"flex items-start justify-between gap-4",children:[y.jsxs("div",{children:[y.jsx(H.Typography,{variant:"h6",color:"red",children:"Fehler"}),y.jsx(H.Typography,{color:"red",className:"text-sm",children:f})]}),y.jsx(H.Button,{size:"sm",color:"red",variant:"text",onClick:w,className:"normal-case",children:"Erneut versuchen"})]})}),!i&&!f&&y.jsxs(y.Fragment,{children:[y.jsxs("div",{className:"rounded-lg border border-blue-gray-100 bg-blue-gray-50/60 p-6",children:[y.jsx(H.Typography,{variant:"h5",className:"mb-4 text-blue-gray-800",children:"Deine Sicherheitsphrase"}),y.jsx("div",{className:"space-y-3",children:l.map((N,k)=>y.jsx("div",{className:"flex flex-wrap items-center justify-center gap-4 text-lg font-mono tracking-wide text-blue-gray-900 md:text-xl",children:N.map((A,M)=>y.jsx("span",{className:"uppercase",children:A},`phrase-${k}-${M}`))},`phrase-row-${k}`))})]}),y.jsxs("div",{className:"flex flex-col items-center justify-between gap-4 md:flex-row",children:[y.jsx("div",{className:"text-sm text-blue-gray-600",children:"Der Download startet im TXT-Format. Bewahre die Datei sicher auf – sie kann später nicht erneut angezeigt werden."}),y.jsxs(H.Button,{color:"blue",size:"md",className:"flex items-center gap-2 normal-case",onClick:j,disabled:u||O||C||b.length===0,children:[y.jsx(Dz,{className:"h-5 w-5"}),"Sicherheitsschlüssel herunterladen"]})]})]})]})})]}):null}const EV="/assets
Line truncated
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#eee}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Roboto,sans-serif;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#bdbdbd}input::placeholder,textarea::placeholder{opacity:1;color:#bdbdbd}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(33 150 243 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(33 150 243 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 540px){.container{max-width:540px}}@media (min-width: 720px){.container{max-width:720px}}@media (min-width: 960px){.container{max-width:960px}}@media (min-width: 1140px){.container{max-width:1140px}}@media (min-width: 1320px){.container{max-width:1320px}}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.\!invisible{visibility:hidden!important}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.\!absolute{position:absolute!important}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bLine truncated
|
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
<script defer data-site="YOUR_DOMAIN_HERE" src="https://api.nepcha.com/js/nepcha-analytics.js"></script>
|
<script defer data-site="YOUR_DOMAIN_HERE" src="https://api.nepcha.com/js/nepcha-analytics.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<script type="module" crossorigin src="/assets/index-71db1823.js"></script>
|
<script type="module" crossorigin src="/assets/index-027ca62d.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/index-dad5f6fa.css">
|
<link rel="stylesheet" href="/assets/index-4d48f088.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -14,6 +14,16 @@ const updateServer = db.prepare(`
|
|||||||
SET name = ?, url = ?, updated_at = CURRENT_TIMESTAMP
|
SET name = ?, url = ?, updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`);
|
`);
|
||||||
|
const selectAgentByServerId = db.prepare('SELECT * FROM server_agents WHERE server_id = ?');
|
||||||
|
const selectAllAgents = db.prepare('SELECT * FROM server_agents');
|
||||||
|
const upsertAgent = db.prepare(`
|
||||||
|
INSERT INTO server_agents (server_id, agent_url, agent_token, created_at, updated_at)
|
||||||
|
VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||||
|
ON CONFLICT(server_id) DO UPDATE SET
|
||||||
|
agent_url = excluded.agent_url,
|
||||||
|
agent_token = excluded.agent_token,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
`);
|
||||||
|
|
||||||
const deleteServerStmt = db.prepare('DELETE FROM servers WHERE id = ?');
|
const deleteServerStmt = db.prepare('DELETE FROM servers WHERE id = ?');
|
||||||
|
|
||||||
@@ -126,6 +136,96 @@ function ensureServer({ name, url }) {
|
|||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const generateAgentToken = () => `sp_${crypto.randomBytes(16).toString('hex')}`;
|
||||||
|
|
||||||
|
function getAgentConfig(serverId, { autoCreate = false } = {}) {
|
||||||
|
const id = Number(serverId);
|
||||||
|
if (!Number.isFinite(id)) {
|
||||||
|
const error = new Error('SERVER_ID_INVALID');
|
||||||
|
error.code = 'SERVER_ID_INVALID';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const server = getServerById(id);
|
||||||
|
let agent = selectAgentByServerId.get(server.id) || null;
|
||||||
|
if (!agent && autoCreate) {
|
||||||
|
const token = generateAgentToken();
|
||||||
|
upsertAgent.run(server.id, null, token);
|
||||||
|
agent = selectAgentByServerId.get(server.id) || null;
|
||||||
|
}
|
||||||
|
return agent ? { serverId: server.id, agentUrl: agent.agent_url, agentToken: agent.agent_token } : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAgentConfig(serverId, { agentUrl, agentToken } = {}) {
|
||||||
|
const id = Number(serverId);
|
||||||
|
if (!Number.isFinite(id)) {
|
||||||
|
const error = new Error('SERVER_ID_INVALID');
|
||||||
|
error.code = 'SERVER_ID_INVALID';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const server = getServerById(id);
|
||||||
|
const normalizedUrl = typeof agentUrl === 'string' && agentUrl.trim().length
|
||||||
|
? agentUrl.trim().replace(/\/+$/, '')
|
||||||
|
: null;
|
||||||
|
let normalizedToken = typeof agentToken === 'string' ? agentToken.trim() : '';
|
||||||
|
if (!normalizedToken) {
|
||||||
|
const existing = selectAgentByServerId.get(server.id);
|
||||||
|
normalizedToken = existing?.agent_token || generateAgentToken();
|
||||||
|
}
|
||||||
|
if (!normalizedToken.startsWith('sp_')) {
|
||||||
|
normalizedToken = `sp_${normalizedToken}`;
|
||||||
|
}
|
||||||
|
upsertAgent.run(server.id, normalizedUrl, normalizedToken);
|
||||||
|
const agent = selectAgentByServerId.get(server.id);
|
||||||
|
return { serverId: server.id, agentUrl: agent.agent_url, agentToken: agent.agent_token };
|
||||||
|
}
|
||||||
|
|
||||||
|
function getServerById(serverId) {
|
||||||
|
const id = Number(serverId);
|
||||||
|
if (!Number.isFinite(id)) {
|
||||||
|
const error = new Error('SERVER_ID_INVALID');
|
||||||
|
error.code = 'SERVER_ID_INVALID';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = selectServerById.get(id);
|
||||||
|
if (!server) {
|
||||||
|
const error = new Error('SERVER_NOT_FOUND');
|
||||||
|
error.code = 'SERVER_NOT_FOUND';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateServerDetails(serverId, { name, url }) {
|
||||||
|
const existing = getServerById(serverId);
|
||||||
|
const normalizedUrl = normalizeUrl(url || existing.url);
|
||||||
|
if (!normalizedUrl) {
|
||||||
|
const error = new Error('SERVER_URL_REQUIRED');
|
||||||
|
error.code = 'SERVER_URL_REQUIRED';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedName = (name || deriveServerName(normalizedUrl)).trim();
|
||||||
|
if (!normalizedName) {
|
||||||
|
const error = new Error('SERVER_NAME_REQUIRED');
|
||||||
|
error.code = 'SERVER_NAME_REQUIRED';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const other = selectServerByUrl.get(normalizedUrl);
|
||||||
|
if (other && other.id !== existing.id) {
|
||||||
|
const error = new Error('SERVER_URL_TAKEN');
|
||||||
|
error.code = 'SERVER_URL_TAKEN';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateServer.run(normalizedName, normalizedUrl, existing.id);
|
||||||
|
const updated = selectServerById.get(existing.id);
|
||||||
|
console.log(`ℹ️ [Setup] Server aktualisiert: ${updated.name} (${updated.id})`);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
function setServerApiKey({ serverId, apiKey }) {
|
function setServerApiKey({ serverId, apiKey }) {
|
||||||
const id = Number(serverId);
|
const id = Number(serverId);
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
@@ -165,6 +265,13 @@ function setServerApiKey({ serverId, apiKey }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getServerConnection(serverId) {
|
||||||
|
const server = getServerById(serverId);
|
||||||
|
const apiKeyRow = selectApiKeyByServerId.get(server.id);
|
||||||
|
const apiKey = decryptApiKey(apiKeyRow);
|
||||||
|
return { server, apiKey };
|
||||||
|
}
|
||||||
|
|
||||||
function getActiveApiKey() {
|
function getActiveApiKey() {
|
||||||
const firstServer = selectFirstServerStmt.get();
|
const firstServer = selectFirstServerStmt.get();
|
||||||
if (firstServer) {
|
if (firstServer) {
|
||||||
@@ -261,6 +368,21 @@ function ensureDefaultsFromEnv() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getServerStatus(serverId) {
|
||||||
|
const server = getServerById(serverId);
|
||||||
|
const apiKeyMeta = selectApiKeyByServerId.get(server.id) || null;
|
||||||
|
const agent = getAgentConfig(server.id, { autoCreate: true });
|
||||||
|
|
||||||
|
return {
|
||||||
|
server,
|
||||||
|
apiKey: {
|
||||||
|
hasKey: Boolean(apiKeyMeta),
|
||||||
|
updatedAt: apiKeyMeta?.updated_at ?? null
|
||||||
|
},
|
||||||
|
agent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function getSetupStatus() {
|
function getSetupStatus() {
|
||||||
const servers = selectAllServers.all();
|
const servers = selectAllServers.all();
|
||||||
const apiKeyRecords = selectAllApiKeys.all();
|
const apiKeyRecords = selectAllApiKeys.all();
|
||||||
@@ -361,7 +483,14 @@ function completeSetup({ server: serverInput }) {
|
|||||||
export {
|
export {
|
||||||
ensureDefaultsFromEnv,
|
ensureDefaultsFromEnv,
|
||||||
ensureServer,
|
ensureServer,
|
||||||
|
getServerById,
|
||||||
setServerApiKey,
|
setServerApiKey,
|
||||||
|
getAgentConfig,
|
||||||
|
setAgentConfig,
|
||||||
|
generateAgentToken,
|
||||||
|
getServerConnection,
|
||||||
|
updateServerDetails,
|
||||||
|
getServerStatus,
|
||||||
getActiveApiKey,
|
getActiveApiKey,
|
||||||
getActiveServerUrl,
|
getActiveServerUrl,
|
||||||
hasServer,
|
hasServer,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import routes from "@/routes";
|
|||||||
import { UserDetails } from "@/pages/dashboard/userDetails.jsx";
|
import { UserDetails } from "@/pages/dashboard/userDetails.jsx";
|
||||||
import { UserGroupDetail } from "@/pages/dashboard/userGroupDetail.jsx";
|
import { UserGroupDetail } from "@/pages/dashboard/userGroupDetail.jsx";
|
||||||
import { SecurityPhrase } from "@/pages/dashboard/securityPhrase.jsx";
|
import { SecurityPhrase } from "@/pages/dashboard/securityPhrase.jsx";
|
||||||
|
import { ServerDetail } from "@/pages/dashboard/serverDetail.jsx";
|
||||||
import { useMaterialTailwindController, setOpenConfigurator } from "@/components";
|
import { useMaterialTailwindController, setOpenConfigurator } from "@/components";
|
||||||
import { useAuth } from "@/components/AuthProvider.jsx";
|
import { useAuth } from "@/components/AuthProvider.jsx";
|
||||||
import PermissionGate from "@/components/PermissionGate.jsx";
|
import PermissionGate from "@/components/PermissionGate.jsx";
|
||||||
@@ -210,6 +211,14 @@ export function Dashboard() {
|
|||||||
</PermissionGate>
|
</PermissionGate>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="maintenance/servers/:serverId"
|
||||||
|
element={
|
||||||
|
<PermissionGate permission="maintenance-server-manage" requiredLevel="read">
|
||||||
|
<ServerDetail />
|
||||||
|
</PermissionGate>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
{!isSecurityPhraseRoute && (
|
{!isSecurityPhraseRoute && (
|
||||||
<div className="text-blue-gray-600">
|
<div className="text-blue-gray-600">
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ export * from "@/pages/dashboard/usergroups";
|
|||||||
export * from "@/pages/dashboard/userDetails";
|
export * from "@/pages/dashboard/userDetails";
|
||||||
export * from "@/pages/dashboard/userGroupDetail";
|
export * from "@/pages/dashboard/userGroupDetail";
|
||||||
export * from "@/pages/dashboard/securityPhrase";
|
export * from "@/pages/dashboard/securityPhrase";
|
||||||
|
export * from "@/pages/dashboard/serverDetail";
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useMaintenance } from "@/components/MaintenanceProvider";
|
import { useMaintenance } from "@/components/MaintenanceProvider";
|
||||||
import { useAuth } from "@/components/AuthProvider.jsx";
|
import { useAuth } from "@/components/AuthProvider.jsx";
|
||||||
@@ -11,8 +12,12 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Switch,
|
Switch,
|
||||||
Input,
|
Input,
|
||||||
Alert
|
Alert,
|
||||||
|
Chip,
|
||||||
|
Select,
|
||||||
|
Option
|
||||||
} from "@material-tailwind/react";
|
} from "@material-tailwind/react";
|
||||||
|
import { PaginationControls, usePage } from "@/components/PageProvider.jsx";
|
||||||
|
|
||||||
const UPDATE_STATUS_LABELS = {
|
const UPDATE_STATUS_LABELS = {
|
||||||
idle: "Bereit",
|
idle: "Bereit",
|
||||||
@@ -111,6 +116,7 @@ const createEmptySshDraft = () => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function Maintenance() {
|
export function Maintenance() {
|
||||||
|
const navigate = useNavigate();
|
||||||
const { hasPermission, user: authUser } = useAuth();
|
const { hasPermission, user: authUser } = useAuth();
|
||||||
const showToast = useCallback(() => { }, []);
|
const showToast = useCallback(() => { }, []);
|
||||||
const {
|
const {
|
||||||
@@ -139,7 +145,7 @@ export function Maintenance() {
|
|||||||
const canViewMaintenance = Boolean(isSuperuserAccount || hasPermission("maintenance-access", "read"));
|
const canViewMaintenance = Boolean(isSuperuserAccount || hasPermission("maintenance-access", "read"));
|
||||||
const canControlMaintenance = Boolean(isSuperuserAccount || hasPermission("maintenance-access", "full"));
|
const canControlMaintenance = Boolean(isSuperuserAccount || hasPermission("maintenance-access", "full"));
|
||||||
const canViewServers = Boolean(isSuperuserAccount || hasPermission("maintenance-server-manage", "read"));
|
const canViewServers = Boolean(isSuperuserAccount || hasPermission("maintenance-server-manage", "read"));
|
||||||
const canEditServers = Boolean(isSuperuserAccount || hasPermission("maintenance-server-manage", "full"));
|
const canEditServers = Boolean(isSuperuserAccount || hasPermission("maintenance-server-edit", "full"));
|
||||||
const canDeleteServers = Boolean(isSuperuserAccount || hasPermission("maintenance-server-delete", "full"));
|
const canDeleteServers = Boolean(isSuperuserAccount || hasPermission("maintenance-server-delete", "full"));
|
||||||
const canDeleteSuperuser = Boolean(isSuperuserAccount || hasPermission("maintenance-superuser-delete", "full"));
|
const canDeleteSuperuser = Boolean(isSuperuserAccount || hasPermission("maintenance-superuser-delete", "full"));
|
||||||
const canViewPortainer = Boolean(isSuperuserAccount || hasPermission("maintenance-portainer", "read"));
|
const canViewPortainer = Boolean(isSuperuserAccount || hasPermission("maintenance-portainer", "read"));
|
||||||
@@ -148,6 +154,8 @@ export function Maintenance() {
|
|||||||
const canManageSsh = Boolean(isSuperuserAccount || hasPermission("maintenance-ssh-update", "full"));
|
const canManageSsh = Boolean(isSuperuserAccount || hasPermission("maintenance-ssh-update", "full"));
|
||||||
const canViewDuplicates = Boolean(isSuperuserAccount || hasPermission("maintenance-duplicates", "read"));
|
const canViewDuplicates = Boolean(isSuperuserAccount || hasPermission("maintenance-duplicates", "read"));
|
||||||
const canManageDuplicates = Boolean(isSuperuserAccount || hasPermission("maintenance-duplicates", "full"));
|
const canManageDuplicates = Boolean(isSuperuserAccount || hasPermission("maintenance-duplicates", "full"));
|
||||||
|
const showPortainerSection = false;
|
||||||
|
const showDuplicateSection = false;
|
||||||
|
|
||||||
const maintenanceActive = Boolean(maintenanceMeta?.active);
|
const maintenanceActive = Boolean(maintenanceMeta?.active);
|
||||||
const maintenanceMessage = maintenanceMeta?.message;
|
const maintenanceMessage = maintenanceMeta?.message;
|
||||||
@@ -214,6 +222,11 @@ export function Maintenance() {
|
|||||||
const [setupResources, setSetupResources] = useState(null);
|
const [setupResources, setSetupResources] = useState(null);
|
||||||
const [setupResourcesLoading, setSetupResourcesLoading] = useState(true);
|
const [setupResourcesLoading, setSetupResourcesLoading] = useState(true);
|
||||||
const [setupResourcesError, setSetupResourcesError] = useState("");
|
const [setupResourcesError, setSetupResourcesError] = useState("");
|
||||||
|
const [createServerName, setCreateServerName] = useState("");
|
||||||
|
const [createServerUrl, setCreateServerUrl] = useState("");
|
||||||
|
const [createServerApiKey, setCreateServerApiKey] = useState("");
|
||||||
|
const [createServerError, setCreateServerError] = useState("");
|
||||||
|
const [creatingServer, setCreatingServer] = useState(false);
|
||||||
const [apiKeyDrafts, setApiKeyDrafts] = useState({});
|
const [apiKeyDrafts, setApiKeyDrafts] = useState({});
|
||||||
const [apiKeyUpdatingId, setApiKeyUpdatingId] = useState(null);
|
const [apiKeyUpdatingId, setApiKeyUpdatingId] = useState(null);
|
||||||
const [serverDeleteId, setServerDeleteId] = useState(null);
|
const [serverDeleteId, setServerDeleteId] = useState(null);
|
||||||
@@ -229,6 +242,35 @@ export function Maintenance() {
|
|||||||
const [duplicatesUpdatedAt, setDuplicatesUpdatedAt] = useState(null);
|
const [duplicatesUpdatedAt, setDuplicatesUpdatedAt] = useState(null);
|
||||||
const duplicatesRequestRef = useRef(null);
|
const duplicatesRequestRef = useRef(null);
|
||||||
|
|
||||||
|
const [serverStatuses, setServerStatuses] = useState(new Map());
|
||||||
|
const [serverStatusesLoading, setServerStatusesLoading] = useState(false);
|
||||||
|
const [serverStatusesError, setServerStatusesError] = useState("");
|
||||||
|
|
||||||
|
const setupServers = useMemo(() => setupResources?.servers?.items ?? [], [setupResources]);
|
||||||
|
const apiKeyInfoMap = useMemo(() => {
|
||||||
|
const items = setupResources?.apiKeys?.items ?? [];
|
||||||
|
return new Map(items.map((entry) => [entry.serverId, entry]));
|
||||||
|
}, [setupResources]);
|
||||||
|
const setupComplete = useMemo(() => Boolean(setupResources?.setupComplete), [setupResources]);
|
||||||
|
const selfStackInfo = setupResources?.selfStack ?? null;
|
||||||
|
const currentSelfStackValue = selfStackInfo?.current ?? "";
|
||||||
|
const envSelfStackValue = setupResources?.envDefaults?.selfStackId ?? "";
|
||||||
|
|
||||||
|
const {
|
||||||
|
page,
|
||||||
|
perPage,
|
||||||
|
perPageOptions,
|
||||||
|
perPageIsAll,
|
||||||
|
handlePerPageChange,
|
||||||
|
setPage,
|
||||||
|
setTotals,
|
||||||
|
resetPagination
|
||||||
|
} = usePage();
|
||||||
|
|
||||||
|
useEffect(() => () => resetPagination(), [resetPagination]);
|
||||||
|
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
||||||
const [portainerStatus, setPortainerStatus] = useState(null);
|
const [portainerStatus, setPortainerStatus] = useState(null);
|
||||||
const [portainerLoading, setPortainerLoading] = useState(true);
|
const [portainerLoading, setPortainerLoading] = useState(true);
|
||||||
const [portainerError, setPortainerError] = useState("");
|
const [portainerError, setPortainerError] = useState("");
|
||||||
@@ -385,15 +427,78 @@ export function Maintenance() {
|
|||||||
fetchDuplicates();
|
fetchDuplicates();
|
||||||
}, [fetchDuplicates]);
|
}, [fetchDuplicates]);
|
||||||
|
|
||||||
const setupServers = useMemo(() => setupResources?.servers?.items ?? [], [setupResources]);
|
useEffect(() => {
|
||||||
const apiKeyInfoMap = useMemo(() => {
|
if (!canViewServers || setupResourcesLoading) {
|
||||||
const items = setupResources?.apiKeys?.items ?? [];
|
return;
|
||||||
return new Map(items.map((entry) => [entry.serverId, entry]));
|
}
|
||||||
}, [setupResources]);
|
const fetchStatuses = async () => {
|
||||||
const setupComplete = useMemo(() => Boolean(setupResources?.setupComplete), [setupResources]);
|
if (!setupServers.length) {
|
||||||
const selfStackInfo = setupResources?.selfStack ?? null;
|
setServerStatuses(new Map());
|
||||||
const currentSelfStackValue = selfStackInfo?.current ?? "";
|
return;
|
||||||
const envSelfStackValue = setupResources?.envDefaults?.selfStackId ?? "";
|
}
|
||||||
|
setServerStatusesLoading(true);
|
||||||
|
setServerStatusesError("");
|
||||||
|
try {
|
||||||
|
const entries = await Promise.all(
|
||||||
|
setupServers.map(async (server) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(`/api/setup/servers/${server.id}/check`);
|
||||||
|
const payload = res.data ?? {};
|
||||||
|
return [
|
||||||
|
server.id,
|
||||||
|
{
|
||||||
|
online: Boolean(payload.online),
|
||||||
|
portainer: payload.portainer ?? {},
|
||||||
|
error: null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
} catch (err) {
|
||||||
|
const message = err.response?.data?.error || err.message || "Status unbekannt";
|
||||||
|
return [
|
||||||
|
server.id,
|
||||||
|
{
|
||||||
|
online: false,
|
||||||
|
portainer: {},
|
||||||
|
error: message
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setServerStatuses(new Map(entries));
|
||||||
|
} catch (err) {
|
||||||
|
const message = err.response?.data?.error || err.message || "Server-Status konnte nicht geladen werden.";
|
||||||
|
setServerStatusesError(message);
|
||||||
|
} finally {
|
||||||
|
setServerStatusesLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchStatuses();
|
||||||
|
}, [canViewServers, setupResourcesLoading, setupServers, setTotals]);
|
||||||
|
|
||||||
|
const filteredServers = useMemo(() => {
|
||||||
|
const query = searchQuery.trim().toLowerCase();
|
||||||
|
if (!query) {
|
||||||
|
return setupServers;
|
||||||
|
}
|
||||||
|
return setupServers.filter((server) => {
|
||||||
|
const haystacks = [server.name, server.url].map((value) => String(value || "").toLowerCase());
|
||||||
|
return haystacks.some((value) => value.includes(query));
|
||||||
|
});
|
||||||
|
}, [searchQuery, setupServers]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTotals(filteredServers.length);
|
||||||
|
}, [filteredServers.length, setTotals]);
|
||||||
|
|
||||||
|
const paginatedServers = useMemo(() => {
|
||||||
|
if (perPageIsAll) {
|
||||||
|
return filteredServers;
|
||||||
|
}
|
||||||
|
const start = (page - 1) * perPage;
|
||||||
|
return filteredServers.slice(start, start + perPage);
|
||||||
|
}, [filteredServers, page, perPage, perPageIsAll]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelfStackDraft(currentSelfStackValue || "");
|
setSelfStackDraft(currentSelfStackValue || "");
|
||||||
@@ -401,6 +506,48 @@ export function Maintenance() {
|
|||||||
}, [currentSelfStackValue]);
|
}, [currentSelfStackValue]);
|
||||||
|
|
||||||
const selfStackDirty = selfStackDraft !== currentSelfStackValue;
|
const selfStackDirty = selfStackDraft !== currentSelfStackValue;
|
||||||
|
const handleSearchChange = useCallback((event) => {
|
||||||
|
setSearchQuery(event.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (page !== 1) {
|
||||||
|
setPage(1);
|
||||||
|
}
|
||||||
|
}, [searchQuery, page, setPage]);
|
||||||
|
|
||||||
|
const handleCreateServer = useCallback(async () => {
|
||||||
|
if (!canEditServers || creatingServer) return;
|
||||||
|
const name = (createServerName || "").trim();
|
||||||
|
const url = (createServerUrl || "").trim();
|
||||||
|
const apiKey = (createServerApiKey || "").trim();
|
||||||
|
if (!url || !apiKey) {
|
||||||
|
setCreateServerError("Bitte Name, URL und API-Key angeben.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCreateServerError("");
|
||||||
|
setCreatingServer(true);
|
||||||
|
try {
|
||||||
|
await axios.post("/api/setup/servers", { name, url, apiKey });
|
||||||
|
setCreateServerName("");
|
||||||
|
setCreateServerUrl("");
|
||||||
|
setCreateServerApiKey("");
|
||||||
|
await loadSetupResources({ silent: true });
|
||||||
|
} catch (err) {
|
||||||
|
const message = err.response?.data?.message || err.response?.data?.error || err.message || "Server konnte nicht angelegt werden.";
|
||||||
|
setCreateServerError(message);
|
||||||
|
} finally {
|
||||||
|
setCreatingServer(false);
|
||||||
|
}
|
||||||
|
}, [canEditServers, createServerApiKey, createServerName, createServerUrl, creatingServer, loadSetupResources]);
|
||||||
|
|
||||||
|
const handleResetCreateServer = useCallback(() => {
|
||||||
|
if (creatingServer) return;
|
||||||
|
setCreateServerName("");
|
||||||
|
setCreateServerUrl("");
|
||||||
|
setCreateServerApiKey("");
|
||||||
|
setCreateServerError("");
|
||||||
|
}, [creatingServer]);
|
||||||
|
|
||||||
const totals = useMemo(() => {
|
const totals = useMemo(() => {
|
||||||
const groups = Array.isArray(duplicates) ? duplicates.length : 0;
|
const groups = Array.isArray(duplicates) ? duplicates.length : 0;
|
||||||
@@ -974,189 +1121,236 @@ export function Maintenance() {
|
|||||||
{canViewServers && (
|
{canViewServers && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader variant="gradient" color="gray" className="mb-5 p-4">
|
<CardHeader variant="gradient" color="gray" className="mb-5 p-4">
|
||||||
<Typography
|
<Typography variant="h6" color="white" className="flex items-center justify-between">
|
||||||
variant="h6"
|
<span>Server</span>
|
||||||
color="white"
|
<Typography variant="small" color="white">
|
||||||
className="flex items-center justify-between"
|
{setupServers.length} vorhanden
|
||||||
>
|
</Typography>
|
||||||
<span>Server & API-Keys</span>
|
|
||||||
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody className="flex flex-col gap-4 p-4">
|
<CardBody className="p-4">
|
||||||
{setupResourcesLoading && (
|
{canEditServers && (
|
||||||
<p className="text-sm text-stormGrey-500">Daten werden geladen…</p>
|
<div className="mb-8 rounded-lg border border-blue-gray-50 p-4">
|
||||||
)}
|
<Typography variant="h6" color="blue-gray" className="mb-2">
|
||||||
{!setupResourcesLoading && setupResourcesError && (
|
Neuen Server hinzufügen
|
||||||
<Alert color="red" className="border border-red-200 bg-red-50 text-red-700">
|
</Typography>
|
||||||
{setupResourcesError}
|
<p className="text-sm text-stormGrey-600 mb-4">
|
||||||
</Alert>
|
Hinterlege deine Portainer-Instanz. Die Verbindung wird beim Speichern automatisch geprüft.
|
||||||
)}
|
</p>
|
||||||
{!setupResourcesLoading && !setupResourcesError && (
|
<div className="grid gap-4 md:grid-cols-3">
|
||||||
<div className="flex flex-col gap-6">
|
<Input
|
||||||
<div className="flex flex-col gap-3">
|
label="Servername"
|
||||||
<div className="flex items-center justify-between">
|
value={createServerName}
|
||||||
<Typography variant="small" color="blue-gray" className="font-semibold uppercase">
|
onChange={(event) => setCreateServerName(event.target.value)}
|
||||||
Server
|
disabled={creatingServer || maintenanceLocked}
|
||||||
</Typography>
|
crossOrigin=""
|
||||||
<Typography variant="small" color="blue-gray">
|
/>
|
||||||
{setupServers.length} vorhanden
|
<Input
|
||||||
</Typography>
|
label="Server-URL oder IP"
|
||||||
</div>
|
value={createServerUrl}
|
||||||
{setupServers.length === 0 ? (
|
onChange={(event) => setCreateServerUrl(event.target.value)}
|
||||||
<p className="text-sm text-stormGrey-500">
|
disabled={creatingServer || maintenanceLocked}
|
||||||
Es sind derzeit keine Server hinterlegt.
|
crossOrigin=""
|
||||||
</p>
|
/>
|
||||||
) : (
|
<Input
|
||||||
<div className="flex flex-col gap-3">
|
type="password"
|
||||||
{setupServers.map((server) => {
|
label="Portainer API-Key"
|
||||||
const apiKeyInfo = apiKeyInfoMap.get(server.id) || null;
|
value={createServerApiKey}
|
||||||
const hasKey = Boolean(apiKeyInfo?.hasKey);
|
onChange={(event) => setCreateServerApiKey(event.target.value)}
|
||||||
const apiKeyUpdatedLabel = apiKeyInfo?.updatedAt
|
disabled={creatingServer || maintenanceLocked}
|
||||||
? new Date(apiKeyInfo.updatedAt).toLocaleString("de-DE", {
|
crossOrigin=""
|
||||||
year: "numeric",
|
/>
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit"
|
|
||||||
})
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={server.id}
|
|
||||||
className="flex flex-col gap-3 rounded-md border border-blue-gray-100 p-3 md:flex-row md:items-start md:justify-between"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<p className="text-sm font-medium text-stormGrey-900">
|
|
||||||
{server.name || "Ohne Namen"}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs text-stormGrey-500 break-all">
|
|
||||||
{server.url}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs text-stormGrey-500">
|
|
||||||
API-Key: {hasKey ? "vorhanden" : "nicht hinterlegt"}{apiKeyUpdatedLabel ? ` (aktualisiert am ${apiKeyUpdatedLabel})` : ""}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full flex-col gap-2 md:max-w-xs">
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
label="Neuer API-Key"
|
|
||||||
value={apiKeyDrafts[server.id] ?? ""}
|
|
||||||
onChange={(event) => handleApiKeyDraftChange(server.id, event.target.value)}
|
|
||||||
disabled={!canEditServers || setupResourcesLoading || apiKeyUpdatingId === server.id}
|
|
||||||
/>
|
|
||||||
<div className="flex items-center gap-2 justify-end">
|
|
||||||
<Button
|
|
||||||
variant="text"
|
|
||||||
color="red"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => handleDeleteServer(server.id)}
|
|
||||||
disabled={maintenanceLocked || !canDeleteServers || setupResourcesLoading || serverDeleteId === server.id || apiKeyUpdatingId === server.id}
|
|
||||||
>
|
|
||||||
{serverDeleteId === server.id ? "Lösche…" : "Löschen"}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
color="blue"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => handleApiKeyUpdate(server.id)}
|
|
||||||
disabled={maintenanceLocked || !canEditServers || setupResourcesLoading || apiKeyUpdatingId === server.id}
|
|
||||||
>
|
|
||||||
{apiKeyUpdatingId === server.id ? "Speichere…" : "API-Key speichern"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-4 flex flex-col gap-3 sm:flex-row sm:items-center">
|
||||||
<div className="flex flex-col gap-3 border-t border-blue-gray-50 pt-4">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Typography variant="small" color="blue-gray" className="font-semibold uppercase">
|
|
||||||
Self-Stack-ID
|
|
||||||
</Typography>
|
|
||||||
<p className="text-xs text-stormGrey-500">
|
|
||||||
Optional – lass das Feld leer, wenn keine Self-Stack-ID benötigt wird.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{selfStackInfo?.envProvided && (
|
|
||||||
<p className="text-xs text-stormGrey-500">
|
|
||||||
Hinweis: Eine Umgebungsvariable liefert bereits einen Standardwert.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-col gap-2 md:flex-row md:items-end">
|
|
||||||
<div className="flex-1">
|
|
||||||
<Input
|
|
||||||
label="Self-Stack-ID"
|
|
||||||
value={selfStackDraft}
|
|
||||||
onChange={(event) => handleSelfStackDraftChange(event.target.value)}
|
|
||||||
disabled={!canEditServers || setupResourcesLoading || selfStackSaving}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{canEditServers && (
|
|
||||||
<div className="flex items-center justify-end gap-2">
|
|
||||||
<Button
|
|
||||||
variant="text"
|
|
||||||
color="red"
|
|
||||||
size="sm"
|
|
||||||
onClick={handleSelfStackRemove}
|
|
||||||
disabled={maintenanceLocked || selfStackSaving || (!currentSelfStackValue && !selfStackDraft)}
|
|
||||||
>
|
|
||||||
Entfernen
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
color="blue"
|
|
||||||
size="sm"
|
|
||||||
onClick={handleSelfStackSave}
|
|
||||||
disabled={maintenanceLocked || selfStackSaving || setupResourcesLoading || !selfStackDirty}
|
|
||||||
>
|
|
||||||
{selfStackSaving ? "Speichere…" : "Self-Stack-ID speichern"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{!canEditServers && (
|
|
||||||
<p className="text-xs text-stormGrey-500">
|
|
||||||
Bearbeitung benötigt das Gruppenrecht „Server-Sektion“.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<p className="text-xs text-stormGrey-500">
|
|
||||||
Aktuell gespeichert: {currentSelfStackValue || "nicht gesetzt"}
|
|
||||||
</p>
|
|
||||||
{envSelfStackValue && (
|
|
||||||
<p className="text-xs text-stormGrey-500">
|
|
||||||
Vorgabe aus Umgebung: {envSelfStackValue}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
{selfStackError && (
|
|
||||||
<Alert color="red" className="border border-red-200 bg-red-50 text-red-700">
|
|
||||||
{selfStackError}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!setupComplete && (
|
|
||||||
<Alert color="amber" className="border border-amber-200 bg-amber-50 text-amber-800">
|
|
||||||
Das Setup ist aktuell unvollständig. Bitte öffne den Setup-Bereich, um Server und API-Key erneut festzulegen.
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex items-center justify-end">
|
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
color="green"
|
||||||
color="gray"
|
onClick={handleCreateServer}
|
||||||
size="sm"
|
disabled={creatingServer || maintenanceLocked}
|
||||||
onClick={() => loadSetupResources()}
|
|
||||||
disabled={maintenanceLocked || setupResourcesLoading}
|
|
||||||
>
|
>
|
||||||
Aktualisieren
|
{creatingServer ? "Verifiziere …" : "Server anlegen"}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
color="blue-gray"
|
||||||
|
onClick={handleResetCreateServer}
|
||||||
|
disabled={creatingServer}
|
||||||
|
>
|
||||||
|
Formular zurücksetzen
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
{createServerError && (
|
||||||
|
<p className="mt-2 text-sm text-sunsetCoral-600">{createServerError}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||||
|
<div className="md:flex-1">
|
||||||
|
<Input
|
||||||
|
label="Suchen nach Name oder URL"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
crossOrigin=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="md:mt-0 mt-4 md:flex-1">
|
||||||
|
<Select variant="static" label="Einträge pro Seite" onChange={handlePerPageChange} value={perPage}>
|
||||||
|
{perPageOptions.map(({ value, label }) => (
|
||||||
|
<Option key={value} value={value}>
|
||||||
|
{label}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{setupResourcesError && (
|
||||||
|
<div className="mt-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
|
||||||
|
{setupResourcesError}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{serverStatusesError && !setupResourcesLoading && (
|
||||||
|
<div className="mt-4 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
|
||||||
|
{serverStatusesError}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="overflow-x-auto rounded-lg border border-blue-gray-50 mt-6">
|
||||||
|
<table className="w-full min-w-[720px] table-auto text-left">
|
||||||
|
<thead>
|
||||||
|
<tr className="bg-blue-gray-50/50 text-xs uppercase tracking-wide text-stormGrey-400">
|
||||||
|
<th className="px-6 py-4 font-semibold">Name</th>
|
||||||
|
<th className="px-6 py-4 font-semibold">IP / Host</th>
|
||||||
|
<th className="px-6 py-4 font-semibold">Server Status</th>
|
||||||
|
<th className="px-6 py-4 font-semibold">Portainer Status</th>
|
||||||
|
<th className="px-6 py-4 font-semibold">Edition</th>
|
||||||
|
<th className="px-6 py-4 font-semibold text-right">Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{setupResourcesLoading ? (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={6} className="px-6 py-8 text-center text-blue-gray-400">
|
||||||
|
Server werden geladen ...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : filteredServers.length === 0 ? (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={6} className="px-6 py-8 text-center text-blue-gray-400">
|
||||||
|
Keine Server gefunden.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : (
|
||||||
|
paginatedServers.map((server, index) => {
|
||||||
|
const rowClass = index === paginatedServers.length - 1 ? "" : "border-b border-blue-gray-50";
|
||||||
|
const statusEntry = serverStatuses.get(server.id) || {};
|
||||||
|
const serverOnline = statusEntry.online === true;
|
||||||
|
const portainer = statusEntry.portainer || {};
|
||||||
|
const portainerStatus = portainer.updateAvailable === true
|
||||||
|
? "update"
|
||||||
|
: portainer.updateAvailable === false
|
||||||
|
? "ok"
|
||||||
|
: "unknown";
|
||||||
|
const portainerEdition = portainer.edition || "-";
|
||||||
|
const hostLabel = (() => {
|
||||||
|
try {
|
||||||
|
const parsed = new URL(server.url);
|
||||||
|
return parsed.hostname || server.url;
|
||||||
|
} catch {
|
||||||
|
return server.url;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return (
|
||||||
|
<tr key={server.id} className={`text-sm text-stormGrey-700 ${rowClass}`}>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<Typography variant="small" className="font-medium text-stormGrey-900">
|
||||||
|
{server.name || "–"}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="small" className="text-xs text-stormGrey-500">
|
||||||
|
{server.url}
|
||||||
|
</Typography>
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<Typography variant="small">{hostLabel || "–"}</Typography>
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
{serverStatusesLoading && !statusEntry ? (
|
||||||
|
<span className="text-xs text-stormGrey-400">Prüfe…</span>
|
||||||
|
) : (
|
||||||
|
<Chip
|
||||||
|
value={serverOnline ? "Online" : "Offline"}
|
||||||
|
size="sm"
|
||||||
|
color={serverOnline ? "green" : "red"}
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
{serverStatusesLoading && !statusEntry ? (
|
||||||
|
<span className="text-xs text-stormGrey-400">Prüfe…</span>
|
||||||
|
) : (
|
||||||
|
<Chip
|
||||||
|
value={
|
||||||
|
portainerStatus === "update"
|
||||||
|
? "Update vorhanden"
|
||||||
|
: portainerStatus === "ok"
|
||||||
|
? "Aktuell"
|
||||||
|
: "Unbekannt"
|
||||||
|
}
|
||||||
|
size="sm"
|
||||||
|
color={
|
||||||
|
portainerStatus === "update"
|
||||||
|
? "amber"
|
||||||
|
: portainerStatus === "ok"
|
||||||
|
? "green"
|
||||||
|
: "blue-gray"
|
||||||
|
}
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
{serverStatusesLoading && !statusEntry ? (
|
||||||
|
<span className="text-xs text-stormGrey-400">Prüfe…</span>
|
||||||
|
) : (
|
||||||
|
<Typography variant="small">{portainerEdition}</Typography>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<div className="flex justify-end gap-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outlined"
|
||||||
|
color="blue-gray"
|
||||||
|
onClick={() => navigate(`/dashboard/maintenance/servers/${server.id}`)}
|
||||||
|
disabled={!canEditServers}
|
||||||
|
>
|
||||||
|
Bearbeiten
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="text"
|
||||||
|
color="red"
|
||||||
|
onClick={() => handleDeleteServer(server.id)}
|
||||||
|
disabled={maintenanceLocked || !canDeleteServers || serverDeleteId === server.id}
|
||||||
|
>
|
||||||
|
{serverDeleteId === server.id ? "Lösche…" : "Löschen"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||||
|
<Typography variant="small" color="blue-gray" className="text-sm">
|
||||||
|
{perPageIsAll ? "Alle Server" : `${paginatedServers.length} von ${filteredServers.length}`} angezeigt
|
||||||
|
</Typography>
|
||||||
|
<PaginationControls />
|
||||||
|
</div>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
@@ -1220,7 +1414,7 @@ export function Maintenance() {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{canViewPortainer && (
|
{showPortainerSection && canViewPortainer && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader variant="gradient" color="gray" className="mb-5 p-4">
|
<CardHeader variant="gradient" color="gray" className="mb-5 p-4">
|
||||||
<Typography
|
<Typography
|
||||||
@@ -1624,7 +1818,7 @@ export function Maintenance() {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{canViewDuplicates && (
|
{showDuplicateSection && canViewDuplicates && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader variant="gradient" color="gray" className="mb-5 p-4">
|
<CardHeader variant="gradient" color="gray" className="mb-5 p-4">
|
||||||
<Typography
|
<Typography
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -519,8 +519,12 @@ export function UserGroupDetail() {
|
|||||||
setPermissionSelection((prev) => {
|
setPermissionSelection((prev) => {
|
||||||
const shouldResetDelete =
|
const shouldResetDelete =
|
||||||
permissionKey === "maintenance-server-manage" && nextValue !== "full";
|
permissionKey === "maintenance-server-manage" && nextValue !== "full";
|
||||||
|
const shouldResetEdit =
|
||||||
|
permissionKey === "maintenance-server-manage" && nextValue === "none";
|
||||||
|
const shouldResetDeleteFromEdit =
|
||||||
|
permissionKey === "maintenance-server-edit" && nextValue !== "full";
|
||||||
|
|
||||||
if (!shouldResetDelete && prev[permissionKey] === nextValue) {
|
if (!shouldResetDelete && !shouldResetEdit && !shouldResetDeleteFromEdit && prev[permissionKey] === nextValue) {
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,6 +536,12 @@ export function UserGroupDetail() {
|
|||||||
if (shouldResetDelete) {
|
if (shouldResetDelete) {
|
||||||
nextState["maintenance-server-delete"] = "none";
|
nextState["maintenance-server-delete"] = "none";
|
||||||
}
|
}
|
||||||
|
if (shouldResetEdit) {
|
||||||
|
nextState["maintenance-server-edit"] = "none";
|
||||||
|
}
|
||||||
|
if (shouldResetDeleteFromEdit) {
|
||||||
|
nextState["maintenance-server-delete"] = "none";
|
||||||
|
}
|
||||||
|
|
||||||
return nextState;
|
return nextState;
|
||||||
});
|
});
|
||||||
@@ -609,6 +619,7 @@ export function UserGroupDetail() {
|
|||||||
const currentValue = getPermissionValue(row.key) ?? "none";
|
const currentValue = getPermissionValue(row.key) ?? "none";
|
||||||
const displayValue = normalizePermissionLevel(row.key, currentValue);
|
const displayValue = normalizePermissionLevel(row.key, currentValue);
|
||||||
const serverManageLevel = getPermissionValue("maintenance-server-manage") ?? "none";
|
const serverManageLevel = getPermissionValue("maintenance-server-manage") ?? "none";
|
||||||
|
const serverEditLevel = getPermissionValue("maintenance-server-edit") ?? "none";
|
||||||
const { addTopBorder = true } = options;
|
const { addTopBorder = true } = options;
|
||||||
|
|
||||||
const rowClasses = [
|
const rowClasses = [
|
||||||
@@ -641,13 +652,18 @@ export function UserGroupDetail() {
|
|||||||
row.key === "maintenance-server-delete" &&
|
row.key === "maintenance-server-delete" &&
|
||||||
option.value === "full" &&
|
option.value === "full" &&
|
||||||
(LEVEL_PRIORITY[serverManageLevel] ?? 0) < LEVEL_PRIORITY.full;
|
(LEVEL_PRIORITY[serverManageLevel] ?? 0) < LEVEL_PRIORITY.full;
|
||||||
|
const requiresEditFull =
|
||||||
|
row.key === "maintenance-server-delete" &&
|
||||||
|
option.value === "full" &&
|
||||||
|
(LEVEL_PRIORITY[serverEditLevel] ?? 0) < LEVEL_PRIORITY.full;
|
||||||
const disabled =
|
const disabled =
|
||||||
!availableLevels.has(option.value) ||
|
!availableLevels.has(option.value) ||
|
||||||
permissionsLoading ||
|
permissionsLoading ||
|
||||||
savingGroup ||
|
savingGroup ||
|
||||||
!canAdjustPermissions ||
|
!canAdjustPermissions ||
|
||||||
isSuperuserGroup ||
|
isSuperuserGroup ||
|
||||||
requiresManageFull;
|
requiresManageFull ||
|
||||||
|
requiresEditFull;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import {
|
|||||||
Square3Stack3DIcon,
|
Square3Stack3DIcon,
|
||||||
WrenchScrewdriverIcon,
|
WrenchScrewdriverIcon,
|
||||||
ListBulletIcon,
|
ListBulletIcon,
|
||||||
ServerStackIcon,
|
|
||||||
RectangleStackIcon,
|
RectangleStackIcon,
|
||||||
|
ServerStackIcon,
|
||||||
ArrowLeftOnRectangleIcon,
|
ArrowLeftOnRectangleIcon,
|
||||||
UserIcon,
|
UserIcon,
|
||||||
UserGroupIcon,
|
UserGroupIcon,
|
||||||
|
|||||||
Reference in new issue
Block a user