1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-09 15:55:23 +02:00

refactor(environments): move environments ts code to react [EE-3443] (#7747)

This commit is contained in:
Chaim Lev-Ari 2022-10-23 09:53:25 +03:00 committed by GitHub
parent 1b12cc9f31
commit e48ceb15e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
154 changed files with 195 additions and 179 deletions

View file

@ -4,7 +4,7 @@ import { useUser } from '@/portainer/hooks/useUser';
import { Icon } from '@/react/components/Icon';
import { TeamMembership, TeamRole } from '@/react/portainer/users/teams/types';
import { useUserMembership } from '@/portainer/users/queries';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { TableContainer, TableTitle } from '@@/datatables';
import { Button } from '@@/buttons';

View file

@ -6,7 +6,7 @@ import { object } from 'yup';
import { useUser } from '@/portainer/hooks/useUser';
import { confirmAsync } from '@/portainer/services/modal.service/confirm';
import { notifySuccess } from '@/portainer/services/notifications';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { Button } from '@@/buttons';
import { LoadingButton } from '@@/buttons/LoadingButton';

View file

@ -2,7 +2,7 @@ import { useCallback } from 'react';
import { FormikErrors } from 'formik';
import { useUser } from '@/portainer/hooks/useUser';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { BoxSelector } from '@@/BoxSelector';
import { FormError } from '@@/form-components/FormError';

View file

@ -1,6 +1,6 @@
import { useTeams } from '@/react/portainer/users/teams/queries';
import { useUsers } from '@/portainer/users/queries';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
export function useLoadState(environmentId?: EnvironmentId) {
const teams = useTeams(false, environmentId);

View file

@ -0,0 +1,253 @@
import { Gpu } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { type EnvironmentGroupId } from '@/portainer/environment-groups/types';
import { type TagId } from '@/portainer/tags/types';
import { type Environment, EnvironmentCreationTypes } from '../types';
import { arrayToJson, buildUrl, json2formData } from './utils';
export interface EnvironmentMetadata {
groupId?: EnvironmentGroupId;
tagIds?: TagId[];
}
interface CreateLocalDockerEnvironment {
name: string;
socketPath?: string;
publicUrl?: string;
meta?: EnvironmentMetadata;
gpus?: Gpu[];
}
export async function createLocalDockerEnvironment({
name,
socketPath = '',
publicUrl = '',
meta = { tagIds: [] },
gpus = [],
}: CreateLocalDockerEnvironment) {
const url = prefixPath(socketPath);
return createEnvironment(
name,
EnvironmentCreationTypes.LocalDockerEnvironment,
{
url,
publicUrl,
meta,
gpus,
}
);
function prefixPath(path: string) {
if (path === '') {
return path;
}
// Windows named pipe
if (path.startsWith('//./pipe/')) {
return `npipe://${path}`;
}
return `unix://${path}`;
}
}
interface CreateLocalKubernetesEnvironment {
name: string;
meta?: EnvironmentMetadata;
}
export async function createLocalKubernetesEnvironment({
name,
meta = { tagIds: [] },
}: CreateLocalKubernetesEnvironment) {
return createEnvironment(
name,
EnvironmentCreationTypes.LocalKubernetesEnvironment,
{ meta, tls: { skipClientVerify: true, skipVerify: true } }
);
}
interface AzureSettings {
applicationId: string;
tenantId: string;
authenticationKey: string;
}
interface CreateAzureEnvironment {
name: string;
azure: AzureSettings;
meta?: EnvironmentMetadata;
}
export async function createAzureEnvironment({
name,
azure,
meta = { tagIds: [] },
}: CreateAzureEnvironment) {
return createEnvironment(name, EnvironmentCreationTypes.AzureEnvironment, {
meta,
azure,
});
}
interface TLSSettings {
skipVerify?: boolean;
skipClientVerify?: boolean;
caCertFile?: File;
certFile?: File;
keyFile?: File;
}
export interface EnvironmentOptions {
url?: string;
publicUrl?: string;
meta?: EnvironmentMetadata;
azure?: AzureSettings;
tls?: TLSSettings;
isEdgeDevice?: boolean;
gpus?: Gpu[];
pollFrequency?: number;
}
interface CreateRemoteEnvironment {
name: string;
creationType: Exclude<
EnvironmentCreationTypes,
EnvironmentCreationTypes.EdgeAgentEnvironment
>;
url: string;
options?: Omit<EnvironmentOptions, 'url'>;
}
export async function createRemoteEnvironment({
creationType,
name,
url,
options = {},
}: CreateRemoteEnvironment) {
return createEnvironment(name, creationType, {
...options,
url: `tcp://${url}`,
});
}
export interface CreateAgentEnvironmentValues {
name: string;
environmentUrl: string;
meta: EnvironmentMetadata;
gpus: Gpu[];
}
export function createAgentEnvironment({
name,
environmentUrl,
meta = { tagIds: [] },
}: CreateAgentEnvironmentValues) {
return createRemoteEnvironment({
name,
url: environmentUrl,
creationType: EnvironmentCreationTypes.AgentEnvironment,
options: {
meta,
tls: {
skipVerify: true,
skipClientVerify: true,
},
},
});
}
interface CreateEdgeAgentEnvironment {
name: string;
portainerUrl: string;
meta?: EnvironmentMetadata;
pollFrequency: number;
gpus?: Gpu[];
isEdgeDevice?: boolean;
}
export function createEdgeAgentEnvironment({
name,
portainerUrl,
meta = { tagIds: [] },
gpus = [],
isEdgeDevice,
pollFrequency,
}: CreateEdgeAgentEnvironment) {
return createEnvironment(
name,
EnvironmentCreationTypes.EdgeAgentEnvironment,
{
url: portainerUrl,
tls: {
skipVerify: true,
skipClientVerify: true,
},
gpus,
isEdgeDevice,
pollFrequency,
meta,
}
);
}
async function createEnvironment(
name: string,
creationType: EnvironmentCreationTypes,
options?: EnvironmentOptions
) {
let payload: Record<string, unknown> = {
Name: name,
EndpointCreationType: creationType,
};
if (options) {
const { groupId, tagIds = [] } = options.meta || {};
payload = {
...payload,
URL: options.url,
PublicURL: options.publicUrl,
GroupID: groupId,
TagIds: arrayToJson(tagIds),
CheckinInterval: options.pollFrequency,
IsEdgeDevice: options.isEdgeDevice,
Gpus: arrayToJson(options.gpus),
};
const { tls, azure } = options;
if (tls) {
payload = {
...payload,
TLS: true,
TLSSkipVerify: tls.skipVerify,
TLSSkipClientVerify: tls.skipClientVerify,
TLSCACertFile: tls.caCertFile,
TLSCertFile: tls.certFile,
TLSKeyFile: tls.keyFile,
};
}
if (azure) {
payload = {
...payload,
AzureApplicationID: azure.applicationId,
AzureTenantID: azure.tenantId,
AzureAuthenticationKey: azure.authenticationKey,
};
}
}
const formPayload = json2formData(payload);
try {
const { data } = await axios.post<Environment>(buildUrl(), formPayload);
return data;
} catch (e) {
throw parseAxiosError(e as Error);
}
}

View file

@ -0,0 +1,16 @@
import axios, { parseAxiosError } from '@/portainer/services/axios';
interface GenerateUrlResponse {
edgeKey: string;
}
export async function generateKey() {
try {
const { data } = await axios.post<GenerateUrlResponse>(
`/endpoints/edge/generate-key`
);
return data.edgeKey;
} catch (err) {
throw parseAxiosError(err as Error, 'Unable to generate key');
}
}

View file

@ -0,0 +1,255 @@
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { type EnvironmentGroupId } from '@/portainer/environment-groups/types';
import { type TagId } from '@/portainer/tags/types';
import { UserId } from '@/portainer/users/types';
import { TeamId } from '@/react/portainer/users/teams/types';
import type {
Environment,
EnvironmentId,
EnvironmentType,
EnvironmentSecuritySettings,
EnvironmentStatus,
} from '../types';
import { buildUrl } from './utils';
export interface EnvironmentsQueryParams {
search?: string;
types?: EnvironmentType[] | readonly EnvironmentType[];
tagIds?: TagId[];
endpointIds?: EnvironmentId[];
tagsPartialMatch?: boolean;
groupIds?: EnvironmentGroupId[];
status?: EnvironmentStatus[];
edgeDevice?: boolean;
edgeDeviceUntrusted?: boolean;
excludeSnapshots?: boolean;
provisioned?: boolean;
name?: string;
agentVersions?: string[];
}
export interface GetEnvironmentsOptions {
start?: number;
limit?: number;
sort?: { by?: string; order?: 'asc' | 'desc' };
query?: EnvironmentsQueryParams;
}
export async function getEnvironments(
{
start,
limit,
sort = { by: '', order: 'asc' },
query = {},
}: GetEnvironmentsOptions = { query: {} }
) {
if (query.tagIds && query.tagIds.length === 0) {
return { totalCount: 0, value: <Environment[]>[] };
}
const url = buildUrl();
const params: Record<string, unknown> = {
start,
limit,
sort: sort.by,
order: sort.order,
...query,
};
try {
const response = await axios.get<Environment[]>(url, { params });
const totalCount = response.headers['x-total-count'];
const totalAvailable = response.headers['x-total-available'];
return {
totalCount: parseInt(totalCount, 10),
value: response.data,
totalAvailable: parseInt(totalAvailable, 10),
};
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getAgentVersions() {
try {
const response = await axios.get<string[]>(
buildUrl(undefined, 'agent_versions')
);
return response.data;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getEndpoint(id: EnvironmentId) {
try {
const { data: endpoint } = await axios.get<Environment>(buildUrl(id));
return endpoint;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function snapshotEndpoints() {
try {
await axios.post<void>(buildUrl(undefined, 'snapshot'));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function snapshotEndpoint(id: EnvironmentId) {
try {
await axios.post<void>(buildUrl(id, 'snapshot'));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function endpointsByGroup(
groupId: EnvironmentGroupId,
start: number,
limit: number,
query: Omit<EnvironmentsQueryParams, 'groupIds'>
) {
return getEnvironments({
start,
limit,
query: { groupIds: [groupId], ...query },
});
}
export async function disassociateEndpoint(id: EnvironmentId) {
try {
await axios.delete(buildUrl(id, 'association'));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
interface UpdatePayload {
TLSCACert?: File;
TLSCert?: File;
TLSKey?: File;
Name: string;
PublicURL: string;
GroupID: EnvironmentGroupId;
TagIds: TagId[];
EdgeCheckinInterval: number;
TLS: boolean;
TLSSkipVerify: boolean;
TLSSkipClientVerify: boolean;
AzureApplicationID: string;
AzureTenantID: string;
AzureAuthenticationKey: string;
}
async function uploadTLSFilesForEndpoint(
id: EnvironmentId,
tlscaCert?: File,
tlsCert?: File,
tlsKey?: File
) {
await Promise.all([
uploadCert('ca', tlscaCert),
uploadCert('cert', tlsCert),
uploadCert('key', tlsKey),
]);
function uploadCert(type: 'ca' | 'cert' | 'key', cert?: File) {
if (!cert) {
return null;
}
try {
return axios.post<void>(`upload/tls/${type}`, cert, {
params: { folder: id },
});
} catch (e) {
throw parseAxiosError(e as Error);
}
}
}
export async function updateEndpoint(
id: EnvironmentId,
payload: UpdatePayload
) {
try {
await uploadTLSFilesForEndpoint(
id,
payload.TLSCACert,
payload.TLSCert,
payload.TLSKey
);
const { data: endpoint } = await axios.put<Environment>(
buildUrl(id),
payload
);
return endpoint;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to update environment');
}
}
export async function deleteEndpoint(id: EnvironmentId) {
try {
await axios.delete(buildUrl(id));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function updatePoolAccess(
id: EnvironmentId,
resourcePool: string,
usersToAdd: UserId[],
teamsToAdd: TeamId[],
usersToRemove: UserId[],
teamsToRemove: TeamId[]
) {
try {
await axios.put<void>(`${buildUrl(id, 'pools')}/${resourcePool}/access`, {
usersToAdd,
teamsToAdd,
usersToRemove,
teamsToRemove,
});
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function forceUpdateService(
id: EnvironmentId,
serviceID: string,
pullImage: boolean
) {
try {
await axios.put(buildUrl(id, 'forceupdateservice'), {
serviceID,
pullImage,
});
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function updateSettings(
id: EnvironmentId,
settings: EnvironmentSecuritySettings
) {
try {
await axios.put(buildUrl(id, 'settings'), settings);
} catch (e) {
throw parseAxiosError(e as Error);
}
}

View file

@ -0,0 +1,77 @@
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { TeamId } from '@/react/portainer/users/teams/types';
import { UserId } from '@/portainer/users/types';
import { EnvironmentId } from '../types';
import { buildUrl } from './utils';
export type RoleId = number;
interface AccessPolicy {
RoleId: RoleId;
}
type UserAccessPolicies = Record<UserId, AccessPolicy>; // map[UserID]AccessPolicy
type TeamAccessPolicies = Record<TeamId, AccessPolicy>;
export type RegistryId = number;
export interface Registry {
Id: RegistryId;
Name: string;
}
interface RegistryAccess {
UserAccessPolicies: UserAccessPolicies;
TeamAccessPolicies: TeamAccessPolicies;
Namespaces: string[];
}
export async function updateEnvironmentRegistryAccess(
id: EnvironmentId,
registryId: RegistryId,
access: RegistryAccess
) {
try {
await axios.put<void>(buildRegistryUrl(id, registryId), access);
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getEnvironmentRegistries(
id: EnvironmentId,
namespace: string
) {
try {
const { data } = await axios.get<Registry[]>(buildRegistryUrl(id), {
params: { namespace },
});
return data;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getEnvironmentRegistry(
endpointId: EnvironmentId,
registryId: RegistryId
) {
try {
const { data } = await axios.get<Registry>(
buildRegistryUrl(endpointId, registryId)
);
return data;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
function buildRegistryUrl(id: EnvironmentId, registryId?: RegistryId) {
let url = `${buildUrl(id)}/registries`;
if (registryId) {
url += `/${registryId}`;
}
return url;
}

View file

@ -0,0 +1,36 @@
import { EnvironmentId } from '../types';
export function buildUrl(id?: EnvironmentId, action?: string) {
let baseUrl = 'endpoints';
if (id) {
baseUrl += `/${id}`;
}
if (action) {
baseUrl += `/${action}`;
}
return baseUrl;
}
export function arrayToJson<T>(arr?: Array<T>) {
if (!arr) {
return '';
}
return JSON.stringify(arr);
}
export function json2formData(json: Record<string, unknown>) {
const formData = new FormData();
Object.entries(json).forEach(([key, value]) => {
if (typeof value === 'undefined' || value === null) {
return;
}
formData.append(key, value as string);
});
return formData;
}

View file

@ -0,0 +1,17 @@
import { useStatus } from '@/portainer/services/api/status.service';
import { useSettings } from '@/react/portainer/settings/queries';
export function useAgentDetails() {
const settingsQuery = useSettings((settings) => settings.AgentSecret);
const versionQuery = useStatus((status) => status.Version);
if (!versionQuery.isSuccess || !settingsQuery.isSuccess) {
return null;
}
const agentVersion = versionQuery.data;
const agentSecret = settingsQuery.data;
return { agentVersion, agentSecret };
}

View file

@ -0,0 +1,7 @@
import { useQuery } from 'react-query';
import { getAgentVersions } from '../environment.service';
export function useAgentVersionsList() {
return useQuery(['environments', 'agentVersions'], () => getAgentVersions());
}

View file

@ -0,0 +1,61 @@
import { useQueryClient, useMutation, MutationFunction } from 'react-query';
import {
createRemoteEnvironment,
createLocalDockerEnvironment,
createAzureEnvironment,
createAgentEnvironment,
createEdgeAgentEnvironment,
createLocalKubernetesEnvironment,
} from '../environment.service/create';
export function useCreateAzureEnvironmentMutation() {
return useGenericCreationMutation(createAzureEnvironment);
}
export function useCreateLocalDockerEnvironmentMutation() {
return useGenericCreationMutation(createLocalDockerEnvironment);
}
export function useCreateLocalKubernetesEnvironmentMutation() {
return useGenericCreationMutation(createLocalKubernetesEnvironment);
}
export function useCreateRemoteEnvironmentMutation(
creationType: Parameters<typeof createRemoteEnvironment>[0]['creationType']
) {
return useGenericCreationMutation(
(
params: Omit<
Parameters<typeof createRemoteEnvironment>[0],
'creationType'
>
) => createRemoteEnvironment({ creationType, ...params })
);
}
export function useCreateAgentEnvironmentMutation() {
return useGenericCreationMutation(createAgentEnvironment);
}
export function useCreateEdgeAgentEnvironmentMutation() {
return useGenericCreationMutation(createEdgeAgentEnvironment);
}
function useGenericCreationMutation<TData = unknown, TVariables = void>(
mutation: MutationFunction<TData, TVariables>
) {
const queryClient = useQueryClient();
return useMutation(mutation, {
onSuccess() {
return queryClient.invalidateQueries(['environments']);
},
meta: {
error: {
title: 'Failure',
message: 'Unable to create environment',
},
},
});
}

View file

@ -0,0 +1,13 @@
import { useQuery } from 'react-query';
import { getEndpoint } from '@/react/portainer/environments/environment.service';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { withError } from '@/react-tools/react-query';
export function useEnvironment(id?: EnvironmentId) {
return useQuery(['environments', id], () => (id ? getEndpoint(id) : null), {
...withError('Failed loading environment'),
staleTime: 50,
enabled: !!id,
});
}

View file

@ -0,0 +1,82 @@
import { useQuery } from 'react-query';
import { withError } from '@/react-tools/react-query';
import { EnvironmentStatus } from '../types';
import {
EnvironmentsQueryParams,
getEnvironments,
} from '../environment.service';
export const ENVIRONMENTS_POLLING_INTERVAL = 30000; // in ms
export interface Query extends EnvironmentsQueryParams {
page?: number;
pageLimit?: number;
sort?: string;
order?: 'asc' | 'desc';
}
type GetEndpointsResponse = Awaited<ReturnType<typeof getEnvironments>>;
export function refetchIfAnyOffline(data?: GetEndpointsResponse) {
if (!data) {
return false;
}
const hasOfflineEnvironment = data.value.some(
(env) => env.Status === EnvironmentStatus.Down
);
if (!hasOfflineEnvironment) {
return false;
}
return ENVIRONMENTS_POLLING_INTERVAL;
}
export function useEnvironmentList(
{ page = 1, pageLimit = 100, sort, order, ...query }: Query = {},
refetchInterval?:
| number
| false
| ((data?: GetEndpointsResponse) => false | number),
staleTime = 0,
enabled = true
) {
const { isLoading, data } = useQuery(
[
'environments',
{
page,
pageLimit,
sort,
order,
...query,
},
],
async () => {
const start = (page - 1) * pageLimit + 1;
return getEnvironments({
start,
limit: pageLimit,
sort: { by: sort, order },
query,
});
},
{
staleTime,
keepPreviousData: true,
refetchInterval,
enabled,
...withError('Failure retrieving environments'),
}
);
return {
isLoading,
environments: data ? data.value : [],
totalCount: data ? data.totalCount : 0,
totalAvailable: data ? data.totalAvailable : 0,
};
}

View file

@ -0,0 +1,149 @@
import { TagId } from '@/portainer/tags/types';
import { EnvironmentGroupId } from '@/portainer/environment-groups/types';
export type EnvironmentId = number;
export enum EnvironmentType {
// Docker represents an environment(endpoint) connected to a Docker environment(endpoint)
Docker = 1,
// AgentOnDocker represents an environment(endpoint) connected to a Portainer agent deployed on a Docker environment(endpoint)
AgentOnDocker,
// Azure represents an environment(endpoint) connected to an Azure environment(endpoint)
Azure,
// EdgeAgentOnDocker represents an environment(endpoint) connected to an Edge agent deployed on a Docker environment(endpoint)
EdgeAgentOnDocker,
// KubernetesLocal represents an environment(endpoint) connected to a local Kubernetes environment(endpoint)
KubernetesLocal,
// AgentOnKubernetes represents an environment(endpoint) connected to a Portainer agent deployed on a Kubernetes environment(endpoint)
AgentOnKubernetes,
// EdgeAgentOnKubernetes represents an environment(endpoint) connected to an Edge agent deployed on a Kubernetes environment(endpoint)
EdgeAgentOnKubernetes,
}
export const EdgeTypes = [
EnvironmentType.EdgeAgentOnDocker,
EnvironmentType.EdgeAgentOnKubernetes,
] as const;
export enum EnvironmentStatus {
Up = 1,
Down,
}
export interface DockerSnapshot {
TotalCPU: number;
TotalMemory: number;
NodeCount: number;
ImageCount: number;
VolumeCount: number;
RunningContainerCount: number;
StoppedContainerCount: number;
HealthyContainerCount: number;
UnhealthyContainerCount: number;
Time: number;
StackCount: number;
ServiceCount: number;
Swarm: boolean;
DockerVersion: string;
GpuUseAll: boolean;
GpuUseList: string[];
}
export interface KubernetesSnapshot {
KubernetesVersion: string;
TotalCPU: number;
TotalMemory: number;
Time: number;
NodeCount: number;
}
export type IngressClass = {
Name: string;
Type: string;
};
export interface KubernetesConfiguration {
UseLoadBalancer?: boolean;
UseServerMetrics?: boolean;
EnableResourceOverCommit?: boolean;
ResourceOverCommitPercentage?: number;
RestrictDefaultNamespace?: boolean;
IngressClasses: IngressClass[];
IngressAvailabilityPerNamespace: boolean;
}
export interface KubernetesSettings {
Snapshots?: KubernetesSnapshot[] | null;
Configuration: KubernetesConfiguration;
}
export type EnvironmentEdge = {
AsyncMode: boolean;
PingInterval: number;
SnapshotInterval: number;
CommandInterval: number;
};
export interface EnvironmentSecuritySettings {
// Whether non-administrator should be able to use bind mounts when creating containers
allowBindMountsForRegularUsers: boolean;
// Whether non-administrator should be able to use privileged mode when creating containers
allowPrivilegedModeForRegularUsers: boolean;
// Whether non-administrator should be able to browse volumes
allowVolumeBrowserForRegularUsers: boolean;
// Whether non-administrator should be able to use the host pid
allowHostNamespaceForRegularUsers: boolean;
// Whether non-administrator should be able to use device mapping
allowDeviceMappingForRegularUsers: boolean;
// Whether non-administrator should be able to manage stacks
allowStackManagementForRegularUsers: boolean;
// Whether non-administrator should be able to use container capabilities
allowContainerCapabilitiesForRegularUsers: boolean;
// Whether non-administrator should be able to use sysctl settings
allowSysctlSettingForRegularUsers: boolean;
// Whether host management features are enabled
enableHostManagementFeatures: boolean;
}
export type Environment = {
Agent: { Version: string };
Id: EnvironmentId;
Type: EnvironmentType;
TagIds: TagId[];
GroupId: EnvironmentGroupId;
EdgeID?: string;
EdgeKey: string;
EdgeCheckinInterval?: number;
QueryDate?: number;
LastCheckInDate?: number;
Name: string;
Status: EnvironmentStatus;
URL: string;
Snapshots: DockerSnapshot[];
Kubernetes: KubernetesSettings;
PublicURL?: string;
IsEdgeDevice?: boolean;
UserTrusted: boolean;
AMTDeviceGUID?: string;
Edge: EnvironmentEdge;
SecuritySettings: EnvironmentSecuritySettings;
Gpus: { name: string; value: string }[];
};
/**
* TS reference of endpoint_create.go#EndpointCreationType iota
*/
export enum EnvironmentCreationTypes {
LocalDockerEnvironment = 1,
AgentEnvironment,
AzureEnvironment,
EdgeAgentEnvironment,
LocalKubernetesEnvironment,
KubeConfigEnvironment,
}
export enum PlatformType {
Docker,
Kubernetes,
Azure,
}

View file

@ -1,7 +1,7 @@
import _ from 'lodash';
import { Clock } from 'react-feather';
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { useEdgeGroups } from '@/react/edge/edge-groups/queries/useEdgeGroups';
import { EdgeGroup } from '@/react/edge/edge-groups/types';

View file

@ -1,6 +1,6 @@
import _ from 'lodash';
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { TextTip } from '@@/Tip/TextTip';

View file

@ -2,7 +2,7 @@ import { useField } from 'formik';
import _ from 'lodash';
import { useState, ChangeEvent } from 'react';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { Select } from '@@/form-components/Input';
import { Checkbox } from '@@/form-components/Checkbox';

View file

@ -1,8 +1,8 @@
import { useFormikContext } from 'formik';
import { useCurrentStateAndParams } from '@uirouter/react';
import { EdgeTypes, EnvironmentId } from '@/portainer/environments/types';
import { useEnvironmentList } from '@/portainer/environments/queries/useEnvironmentList';
import { EdgeTypes, EnvironmentId } from '@/react/portainer/environments/types';
import { useEnvironmentList } from '@/react/portainer/environments/queries/useEnvironmentList';
import { useActiveSchedules } from '../queries/useActiveSchedules';

View file

@ -1,4 +1,4 @@
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { EdgeGroup } from '@/react/edge/edge-groups/types';
import { ScheduleType } from '../types';

View file

@ -1,4 +1,4 @@
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { EdgeUpdateSchedule } from '../types';

View file

@ -1,7 +1,7 @@
import { useQuery } from 'react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { EdgeUpdateSchedule, ScheduleType, StatusType } from '../types';

View file

@ -1,7 +1,7 @@
import { useQuery } from 'react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { queryKeys } from './query-keys';
import { buildUrl } from './urls';

View file

@ -1,4 +1,4 @@
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { UserId } from '@/portainer/users/types';
import { EdgeGroup } from '@/react/edge/edge-groups/types';

View file

@ -1,5 +1,8 @@
import { getPlatformType } from '@/portainer/environments/utils';
import { EnvironmentType, PlatformType } from '@/portainer/environments/types';
import { getPlatformType } from '@/react/portainer/environments/utils';
import {
EnvironmentType,
PlatformType,
} from '@/react/portainer/environments/types';
import Docker from './docker.svg?c';
import Azure from './azure.svg?c';

View file

@ -0,0 +1,65 @@
import { Environment, EnvironmentType, PlatformType } from '../types';
export function getPlatformType(envType: EnvironmentType) {
switch (envType) {
case EnvironmentType.KubernetesLocal:
case EnvironmentType.AgentOnKubernetes:
case EnvironmentType.EdgeAgentOnKubernetes:
return PlatformType.Kubernetes;
case EnvironmentType.Docker:
case EnvironmentType.AgentOnDocker:
case EnvironmentType.EdgeAgentOnDocker:
return PlatformType.Docker;
case EnvironmentType.Azure:
return PlatformType.Azure;
default:
throw new Error(`${envType} is not a supported environment type`);
}
}
export function isDockerEnvironment(envType: EnvironmentType) {
return getPlatformType(envType) === PlatformType.Docker;
}
export function isKubernetesEnvironment(envType: EnvironmentType) {
return getPlatformType(envType) === PlatformType.Kubernetes;
}
export function isAgentEnvironment(envType: EnvironmentType) {
return (
isEdgeEnvironment(envType) ||
[EnvironmentType.AgentOnDocker, EnvironmentType.AgentOnKubernetes].includes(
envType
)
);
}
export function isEdgeEnvironment(envType: EnvironmentType) {
return [
EnvironmentType.EdgeAgentOnDocker,
EnvironmentType.EdgeAgentOnKubernetes,
].includes(envType);
}
export function isUnassociatedEdgeEnvironment(env: Environment) {
return isEdgeEnvironment(env.Type) && !env.EdgeID;
}
export function getRoute(environment: Environment) {
if (isEdgeEnvironment(environment.Type) && !environment.EdgeID) {
return 'portainer.endpoints.endpoint';
}
const platform = getPlatformType(environment.Type);
switch (platform) {
case PlatformType.Azure:
return 'azure.dashboard';
case PlatformType.Docker:
return 'docker.dashboard';
case PlatformType.Kubernetes:
return 'kubernetes.dashboard';
default:
return '';
}
}

View file

@ -4,7 +4,10 @@ import _ from 'lodash';
import clsx from 'clsx';
import { notifyError } from '@/portainer/services/notifications';
import { Environment, EnvironmentId } from '@/portainer/environments/types';
import {
Environment,
EnvironmentId,
} from '@/react/portainer/environments/types';
import { useAnalytics } from '@/angulartics.matomo/analytics-services';
import { Stepper } from '@@/Stepper';

View file

@ -3,10 +3,10 @@ import { useReducer, useState } from 'react';
import { object, SchemaOf, string } from 'yup';
import { buildOption } from '@/portainer/components/BoxSelector';
import { useCreateAzureEnvironmentMutation } from '@/portainer/environments/queries/useCreateEnvironmentMutation';
import { useCreateAzureEnvironmentMutation } from '@/react/portainer/environments/queries/useCreateEnvironmentMutation';
import { notifySuccess } from '@/portainer/services/notifications';
import { Environment } from '@/portainer/environments/types';
import { EnvironmentMetadata } from '@/portainer/environments/environment.service/create';
import { Environment } from '@/react/portainer/environments/types';
import { EnvironmentMetadata } from '@/react/portainer/environments/environment.service/create';
import { LoadingButton } from '@@/buttons/LoadingButton';
import { Input } from '@@/form-components/Input';

View file

@ -1,13 +1,13 @@
import { Field, Form, Formik } from 'formik';
import { useReducer } from 'react';
import { useCreateRemoteEnvironmentMutation } from '@/portainer/environments/queries/useCreateEnvironmentMutation';
import { useCreateRemoteEnvironmentMutation } from '@/react/portainer/environments/queries/useCreateEnvironmentMutation';
import { Hardware } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/Hardware';
import { notifySuccess } from '@/portainer/services/notifications';
import {
Environment,
EnvironmentCreationTypes,
} from '@/portainer/environments/types';
} from '@/react/portainer/environments/types';
import { LoadingButton } from '@@/buttons/LoadingButton';
import { FormControl } from '@@/form-components/FormControl';

View file

@ -1,4 +1,4 @@
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { APIForm } from './APIForm';

View file

@ -1,6 +1,6 @@
import { useState } from 'react';
import { useAgentDetails } from '@/portainer/environments/queries/useAgentDetails';
import { useAgentDetails } from '@/react/portainer/environments/queries/useAgentDetails';
import { CopyButton } from '@@/buttons/CopyButton';
import { Code } from '@@/Code';

View file

@ -1,5 +1,5 @@
import { Gpu } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
import { EnvironmentMetadata } from '@/portainer/environments/environment.service/create';
import { EnvironmentMetadata } from '@/react/portainer/environments/environment.service/create';
export interface FormValues {
name: string;

View file

@ -1,4 +1,4 @@
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { AgentForm } from '../../shared/AgentForm/AgentForm';

View file

@ -1,6 +1,6 @@
import { useState } from 'react';
import { useAgentDetails } from '@/portainer/environments/queries/useAgentDetails';
import { useAgentDetails } from '@/react/portainer/environments/queries/useAgentDetails';
import { CopyButton } from '@@/buttons/CopyButton';
import { Code } from '@@/Code';

View file

@ -1,10 +1,10 @@
import { Field, Form, Formik, useFormikContext } from 'formik';
import { useReducer } from 'react';
import { useCreateLocalDockerEnvironmentMutation } from '@/portainer/environments/queries/useCreateEnvironmentMutation';
import { useCreateLocalDockerEnvironmentMutation } from '@/react/portainer/environments/queries/useCreateEnvironmentMutation';
import { Hardware } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/Hardware';
import { notifySuccess } from '@/portainer/services/notifications';
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { LoadingButton } from '@@/buttons/LoadingButton';
import { FormControl } from '@@/form-components/FormControl';

View file

@ -1,4 +1,4 @@
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { DeploymentScripts } from '../APITab/DeploymentScripts';

View file

@ -1,5 +1,5 @@
import { Gpu } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
import { EnvironmentMetadata } from '@/portainer/environments/environment.service/create';
import { EnvironmentMetadata } from '@/react/portainer/environments/environment.service/create';
export interface FormValues {
name: string;

View file

@ -1,6 +1,6 @@
import { useState } from 'react';
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { commandsTabs } from '@/react/edge/components/EdgeScriptForm/scripts';
import { BoxSelector, type BoxSelectorOption } from '@@/BoxSelector';

View file

@ -5,16 +5,16 @@ import {
endpointTypeName,
stripProtocol,
} from '@/portainer/filters/filters';
import { EnvironmentId } from '@/portainer/environments/types';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { EdgeIndicator } from '@/portainer/home/EnvironmentList/EnvironmentItem';
import {
isEdgeEnvironment,
isUnassociatedEdgeEnvironment,
} from '@/portainer/environments/utils';
} from '@/react/portainer/environments/utils';
import {
ENVIRONMENTS_POLLING_INTERVAL,
useEnvironmentList,
} from '@/portainer/environments/queries/useEnvironmentList';
} from '@/react/portainer/environments/queries/useEnvironmentList';
import { Widget, WidgetBody, WidgetTitle } from '@@/Widget';

View file

@ -1,4 +1,4 @@
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { AgentForm } from '../shared/AgentForm';

View file

@ -1,7 +1,7 @@
import { useState } from 'react';
import { getAgentShortVersion } from '@/portainer/views/endpoints/helpers';
import { useAgentDetails } from '@/portainer/environments/queries/useAgentDetails';
import { useAgentDetails } from '@/react/portainer/environments/queries/useAgentDetails';
import { CopyButton } from '@@/buttons/CopyButton';
import { Code } from '@@/Code';

View file

@ -3,7 +3,7 @@ import { useState } from 'react';
import {
Environment,
EnvironmentCreationTypes,
} from '@/portainer/environments/types';
} from '@/react/portainer/environments/types';
import { commandsTabs } from '@/react/edge/components/EdgeScriptForm/scripts';
import { FeatureId } from '@/portainer/feature-flags/enums';

View file

@ -1,10 +1,10 @@
import { Form, Formik } from 'formik';
import { useReducer } from 'react';
import { useCreateAgentEnvironmentMutation } from '@/portainer/environments/queries/useCreateEnvironmentMutation';
import { useCreateAgentEnvironmentMutation } from '@/react/portainer/environments/queries/useCreateEnvironmentMutation';
import { notifySuccess } from '@/portainer/services/notifications';
import { Environment } from '@/portainer/environments/types';
import { CreateAgentEnvironmentValues } from '@/portainer/environments/environment.service/create';
import { Environment } from '@/react/portainer/environments/types';
import { CreateAgentEnvironmentValues } from '@/react/portainer/environments/environment.service/create';
import { LoadingButton } from '@@/buttons/LoadingButton';
import { Icon } from '@@/Icon';

View file

@ -1,7 +1,7 @@
import { object, SchemaOf, string } from 'yup';
import { gpusListValidation } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
import { CreateAgentEnvironmentValues } from '@/portainer/environments/environment.service/create';
import { CreateAgentEnvironmentValues } from '@/react/portainer/environments/environment.service/create';
import { metadataValidation } from '../MetadataFieldset/validation';
import { nameValidation } from '../NameField';

View file

@ -1,7 +1,7 @@
import { Formik, Form } from 'formik';
import { Environment } from '@/portainer/environments/types';
import { useCreateEdgeAgentEnvironmentMutation } from '@/portainer/environments/queries/useCreateEnvironmentMutation';
import { Environment } from '@/react/portainer/environments/types';
import { useCreateEdgeAgentEnvironmentMutation } from '@/react/portainer/environments/queries/useCreateEnvironmentMutation';
import { baseHref } from '@/portainer/helpers/pathHelper';
import { EdgeCheckinIntervalField } from '@/edge/components/EdgeCheckInIntervalField';
import { useCreateEdgeDeviceParam } from '@/react/portainer/environments/wizard/hooks/useCreateEdgeDeviceParam';

View file

@ -1,5 +1,5 @@
import { Gpu } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
import { EnvironmentMetadata } from '@/portainer/environments/environment.service/create';
import { EnvironmentMetadata } from '@/react/portainer/environments/environment.service/create';
export interface FormValues {
name: string;

View file

@ -1,7 +1,7 @@
import { v4 as uuid } from 'uuid';
import { useReducer, useState } from 'react';
import { Environment } from '@/portainer/environments/types';
import { Environment } from '@/react/portainer/environments/types';
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
import { CommandTab } from '@/react/edge/components/EdgeScriptForm/scripts';
import { OS, EdgeInfo } from '@/react/edge/components/EdgeScriptForm/types';

View file

@ -1,6 +1,6 @@
import { object, number, array, SchemaOf } from 'yup';
import { EnvironmentMetadata } from '@/portainer/environments/environment.service/create';
import { EnvironmentMetadata } from '@/react/portainer/environments/environment.service/create';
export function metadataValidation(): SchemaOf<EnvironmentMetadata> {
return object({

View file

@ -2,7 +2,7 @@ import { Field, useField } from 'formik';
import { string } from 'yup';
import { debounce } from 'lodash';
import { getEnvironments } from '@/portainer/environments/environment.service';
import { getEnvironments } from '@/react/portainer/environments/environment.service';
import { FormControl } from '@@/form-components/FormControl';
import { Input } from '@@/form-components/Input';

View file

@ -1,4 +1,4 @@
import { EnvironmentCreationTypes } from '@/portainer/environments/types';
import { EnvironmentCreationTypes } from '@/react/portainer/environments/types';
import { BoxSelectorOption } from '@@/BoxSelector';

View file

@ -1,4 +1,4 @@
import { EnvironmentType } from '@/portainer/environments/types';
import { EnvironmentType } from '@/react/portainer/environments/types';
import { useAnalytics } from '@/angulartics.matomo/analytics-services';
import { PageHeader } from '@@/PageHeader';

View file

@ -1,12 +1,15 @@
import { useEffect, useState } from 'react';
import { useMutation } from 'react-query';
import { useEnvironmentList } from '@/portainer/environments/queries/useEnvironmentList';
import { Environment, EnvironmentType } from '@/portainer/environments/types';
import { useEnvironmentList } from '@/react/portainer/environments/queries/useEnvironmentList';
import {
Environment,
EnvironmentType,
} from '@/react/portainer/environments/types';
import {
createLocalDockerEnvironment,
createLocalKubernetesEnvironment,
} from '@/portainer/environments/environment.service/create';
} from '@/react/portainer/environments/environment.service/create';
export function useConnectLocalEnvironment(): {
status: 'error' | 'loading' | 'success';

View file

@ -1,7 +1,7 @@
import { useMutation } from 'react-query';
import { useEffect } from 'react';
import { generateKey } from '@/portainer/environments/environment.service/edge';
import { generateKey } from '@/react/portainer/environments/environment.service/edge';
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
import { commandsTabs } from '@/react/edge/components/EdgeScriptForm/scripts';