chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:08:39 +08:00
commit a0df89c693
5252 changed files with 523444 additions and 0 deletions
@@ -0,0 +1,220 @@
import { useMutation } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import { Laptop, Network } from 'lucide-react';
import { generateKey } from '@/react/portainer/environments/environment.service/edge';
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
import { commandsTabs } from '@/react/edge/components/EdgeScriptForm/scripts';
import { useSettings } from '@/react/portainer/settings/queries';
import EdgeAgentStandardIcon from '@/react/edge/components/edge-agent-standard.svg?c';
import EdgeAgentAsyncIcon from '@/react/edge/components/edge-agent-async.svg?c';
import { ConnectivityTestModal } from '@/react/edge/components/ConnectivityTestModal/ConnectivityTestModal';
import { Widget, WidgetBody, WidgetTitle } from '@@/Widget';
import { TextTip } from '@@/Tip/TextTip';
import { BoxSelector } from '@@/BoxSelector';
import { FormSection } from '@@/form-components/FormSection';
import { CopyButton } from '@@/buttons';
import { Button } from '@@/buttons';
import { Link } from '@@/Link';
import { FormControl } from '@@/form-components/FormControl';
import { Input } from '@@/form-components/Input';
const commands = {
linux: [
commandsTabs.k8sLinux,
commandsTabs.swarmLinux,
commandsTabs.standaloneLinux,
commandsTabs.podmanLinux,
],
win: [commandsTabs.swarmWindows, commandsTabs.standaloneWindow],
};
const asyncModeOptions = [
{
icon: EdgeAgentStandardIcon,
id: 'standard',
label: 'Edge Agent Standard',
value: false,
iconType: 'badge',
},
{
icon: EdgeAgentAsyncIcon,
id: 'async',
label: 'Edge Agent Async',
value: true,
iconType: 'badge',
},
] as const;
export function AutomaticEdgeEnvCreation() {
const edgeKeyMutation = useGenerateKeyMutation();
const { mutate: generateKey, reset: resetKey } = edgeKeyMutation;
const settingsQuery = useSettings();
const [asyncMode, setAsyncMode] = useState(false);
const url = settingsQuery.data?.EdgePortainerUrl;
const settings = settingsQuery.data;
const edgeKey = edgeKeyMutation.data;
const edgeComputeConfigurationOK = validateConfiguration();
useEffect(() => {
if (edgeComputeConfigurationOK) {
generateKey();
} else {
resetKey();
}
}, [generateKey, edgeComputeConfigurationOK, resetKey]);
if (!settingsQuery.data) {
return null;
}
return (
<Widget>
<WidgetTitle icon={Laptop} title="Automatic Edge Environment Creation" />
<WidgetBody className="form-horizontal">
{!edgeComputeConfigurationOK ? (
<TextTip color="orange">
In order to use this feature, please turn on Edge Compute features{' '}
<Link
to="portainer.settings.edgeCompute"
data-cy="edge-disabled-portainer-edge-settings-link"
>
here
</Link>{' '}
and have Portainer API server URL and tunnel server address properly
configured.
</TextTip>
) : (
<>
<BoxSelector
slim
radioName="async-mode-selector"
value={asyncMode}
onChange={handleChangeAsyncMode}
options={asyncModeOptions}
/>
<EdgeKeyInfo
asyncMode={asyncMode}
edgeKey={edgeKey}
isLoading={edgeKeyMutation.isLoading}
url={url}
tunnelUrl={settings?.Edge.TunnelServerAddress}
/>
</>
)}
</WidgetBody>
</Widget>
);
function handleChangeAsyncMode(asyncMode: boolean) {
setAsyncMode(asyncMode);
}
function validateConfiguration() {
return !!(
settings &&
settings.EnableEdgeComputeFeatures &&
settings.EdgePortainerUrl &&
settings.Edge.TunnelServerAddress
);
}
}
// using mutation because we want this action to run only when required
function useGenerateKeyMutation() {
return useMutation(generateKey);
}
function EdgeKeyInfo({
isLoading,
edgeKey,
url,
tunnelUrl,
asyncMode,
}: {
isLoading: boolean;
edgeKey?: string;
url?: string;
tunnelUrl?: string;
asyncMode: boolean;
}) {
const [isConnectivityModalOpen, setIsConnectivityModalOpen] = useState(false);
if (isLoading || !edgeKey) {
return <div>Generating key for {url} ... </div>;
}
return (
<>
<hr />
<FormSection title="Edge key">
<div className="break-words">
<code>{edgeKey}</code>
</div>
<CopyButton
copyText={edgeKey}
data-cy="edge-auto-create-copy-token-button"
>
Copy token
</CopyButton>
</FormSection>
<hr />
<EdgeScriptForm
edgeInfo={{ key: edgeKey }}
commands={commands}
asyncMode={asyncMode}
showMetaFields
>
<TextTip color="blue">
Portainer Server URL{' '}
{!asyncMode ? 'and tunnel server address are' : 'is'} set{' '}
<Link
to="portainer.settings.edgeCompute"
data-cy="server-url-portainer-edge-settings-link"
>
here
</Link>
</TextTip>
<FormControl label="Portainer API server URL">
<Input value={url} readOnly data-cy="edge-auto-create-url-input" />
</FormControl>
{!asyncMode && (
<FormControl label="Portainer tunnel server address">
<Input
value={tunnelUrl}
readOnly
data-cy="edge-auto-create-tunnel-address-input"
/>
</FormControl>
)}
<Button
color="default"
className="!ml-0 mb-8"
icon={Network}
onClick={() => setIsConnectivityModalOpen(true)}
data-cy="edge-auto-create-test-connectivity-button"
>
Test connectivity
</Button>
</EdgeScriptForm>
{isConnectivityModalOpen && url && (
<ConnectivityTestModal
portainerUrl={url}
tunnelServerAddr={!asyncMode ? tunnelUrl : undefined}
onDismiss={() => setIsConnectivityModalOpen(false)}
/>
)}
</>
);
}
@@ -0,0 +1 @@
export { AutomaticEdgeEnvCreation } from './AutomaticEdgeEnvCreation';
@@ -0,0 +1,28 @@
import { withLimitToBE } from '@/react/hooks/useLimitToBE';
import { PageHeader } from '@@/PageHeader';
import { AutomaticEdgeEnvCreation } from './AutomaticEdgeEnvCreation';
export const EdgeAutoCreateScriptViewWrapper = withLimitToBE(
EdgeAutoCreateScriptView
);
function EdgeAutoCreateScriptView() {
return (
<>
<PageHeader
title="Automatic Edge Environment Creation"
breadcrumbs={[
{ label: 'Environments', link: 'portainer.endpoints' },
'Automatic Edge Environment Creation',
]}
reload
/>
<div className="mx-3">
<AutomaticEdgeEnvCreation />
</div>
</>
);
}
@@ -0,0 +1 @@
export { EdgeAutoCreateScriptViewWrapper as EdgeAutoCreateScriptView } from './EdgeAutoCreateScriptView';