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

feat(system): path to upgrade standalone to BE [EE-4071] (#8095)

This commit is contained in:
Chaim Lev-Ari 2022-12-11 08:58:22 +02:00 committed by GitHub
parent 756ac034ec
commit 5cbf52377d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
73 changed files with 1374 additions and 421 deletions

View file

@ -11,7 +11,7 @@ test('when user is using more nodes then allowed he should see message', async (
rest.get('/api/licenses/info', (req, res, ctx) =>
res(ctx.json({ nodes: allowed, type: LicenseType.Subscription }))
),
rest.get('/api/status/nodes', (req, res, ctx) =>
rest.get('/api/system/nodes', (req, res, ctx) =>
res(ctx.json({ nodes: used }))
)
);
@ -32,7 +32,7 @@ test("when user is using less nodes then allowed he shouldn't see message", asyn
rest.get('/api/licenses/info', (req, res, ctx) =>
res(ctx.json({ nodes: allowed, type: LicenseType.Subscription }))
),
rest.get('/api/status/nodes', (req, res, ctx) =>
rest.get('/api/system/nodes', (req, res, ctx) =>
res(ctx.json({ nodes: used }))
)
);

View file

@ -1,13 +1,11 @@
import { useQuery } from 'react-query';
import { error as notifyError } from '@/portainer/services/notifications';
import { LicenseType } from '@/portainer/license-management/types';
import { useLicenseInfo } from '@/portainer/license-management/use-license.service';
import { getNodesCount } from '@/portainer/services/api/status.service';
import { TextTip } from '@@/Tip/TextTip';
import { InformationPanel } from '@@/InformationPanel';
import { useNodesCount } from '../system/useNodesCount';
export function LicenseNodePanel() {
const nodesValid = useNodesValid();
@ -26,7 +24,7 @@ export function LicenseNodePanel() {
}
function useNodesValid() {
const { isLoading: isLoadingNodes, nodesCount } = useNodesCounts();
const { isLoading: isLoadingNodes, data: nodesCount = 0 } = useNodesCount();
const { isLoading: isLoadingLicense, info } = useLicenseInfo();
if (
@ -40,17 +38,3 @@ function useNodesValid() {
return nodesCount <= info.nodes;
}
function useNodesCounts() {
const { isLoading, data } = useQuery(
['status', 'nodes'],
() => getNodesCount(),
{
onError(error) {
notifyError('Failure', error as Error, 'Failed to get nodes count');
},
}
);
return { nodesCount: data || 0, isLoading };
}

View file

@ -1,10 +1,10 @@
import { useStatus } from '@/portainer/services/api/status.service';
import { useSettings } from '@/react/portainer/settings/queries';
import { useSystemStatus } from '@/react/portainer/system/useSystemStatus';
export function useAgentDetails() {
const settingsQuery = useSettings();
const versionQuery = useStatus((status) => status.Version);
const versionQuery = useSystemStatus({ select: (status) => status.Version });
if (!versionQuery.isSuccess || !settingsQuery.isSuccess) {
return null;

View file

@ -2,9 +2,7 @@ import { useRouter } from '@uirouter/react';
import { usePublicSettings } from '@/react/portainer/settings/queries';
export enum FeatureFlag {
BEUpgrade = 'beUpgrade',
}
export enum FeatureFlag {}
export function useFeatureFlag(
flag: FeatureFlag,

View file

@ -0,0 +1,22 @@
import { ComponentType } from 'react';
export function withEdition<T>(
WrappedComponent: ComponentType<T>,
edition: 'BE' | 'CE'
): ComponentType<T> {
// Try to create a nice displayName for React Dev Tools.
const displayName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
function WrapperComponent(props: T) {
if (process.env.PORTAINER_EDITION !== edition) {
return null;
}
return <WrappedComponent {...props} />;
}
WrapperComponent.displayName = `with${edition}Edition(${displayName})`;
return WrapperComponent;
}

View file

@ -0,0 +1,26 @@
import { ComponentType } from 'react';
import { FeatureFlag, useFeatureFlag } from './useRedirectFeatureFlag';
export function withFeatureFlag<T>(
WrappedComponent: ComponentType<T>,
flag: FeatureFlag
): ComponentType<T> {
// Try to create a nice displayName for React Dev Tools.
const displayName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
function WrapperComponent(props: T) {
const featureFlagQuery = useFeatureFlag(flag);
if (!featureFlagQuery.data) {
return null;
}
return <WrappedComponent {...props} />;
}
WrapperComponent.displayName = `with${flag}FeatureFlag(${displayName})`;
return WrapperComponent;
}

View file

@ -1,5 +1,5 @@
export function buildUrl(action?: string) {
let url = '/status';
let url = '/system';
if (action) {
url += `/${action}`;

View file

@ -0,0 +1,3 @@
export const queryKeys = {
base: () => ['system'] as const,
};

View file

@ -4,6 +4,9 @@ import axios, { parseAxiosError } from '@/portainer/services/axios';
import { withError } from '@/react-tools/react-query';
import { buildUrl } from './build-url';
import { queryKeys } from './query-keys';
export const queryKey = [...queryKeys.base(), 'nodes'] as const;
export interface NodesCountResponse {
nodes: number;
@ -19,7 +22,7 @@ async function getNodesCount() {
}
export function useNodesCount() {
return useQuery(['status', 'nodes'], getNodesCount, {
return useQuery(queryKey, getNodesCount, {
...withError('Unable to retrieve nodes count'),
});
}

View file

@ -4,9 +4,19 @@ import axios, { parseAxiosError } from '@/portainer/services/axios';
import { withError } from '@/react-tools/react-query';
import { buildUrl } from './build-url';
import { queryKeys } from './query-keys';
export const queryKey = [...queryKeys.base(), 'info'] as const;
export type ContainerPlatform =
| 'Docker Standalone'
| 'Docker Swarm'
| 'Kubernetes'
| 'Podman'
| 'Nomad';
export interface SystemInfoResponse {
platform: string;
platform: ContainerPlatform;
agents: number;
edgeAgents: number;
edgeDevices: number;
@ -14,7 +24,7 @@ export interface SystemInfoResponse {
async function getSystemInfo() {
try {
const { data } = await axios.get<SystemInfoResponse>(buildUrl('system'));
const { data } = await axios.get<SystemInfoResponse>(buildUrl('info'));
return data;
} catch (error) {
throw parseAxiosError(error as Error);
@ -22,7 +32,7 @@ async function getSystemInfo() {
}
export function useSystemInfo() {
return useQuery(['status', 'system'], getSystemInfo, {
return useQuery(queryKey, getSystemInfo, {
...withError('Unable to retrieve system info'),
});
}

View file

@ -0,0 +1,46 @@
import { useQuery } from 'react-query';
import { RetryValue } from 'react-query/types/core/retryer';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { buildUrl } from './build-url';
import { queryKeys } from './query-keys';
export const queryKey = [...queryKeys.base(), 'status'] as const;
export interface StatusResponse {
Edition: string;
Version: string;
InstanceID: string;
}
export async function getSystemStatus() {
try {
const { data } = await axios.get<StatusResponse>(buildUrl('status'));
data.Edition = 'Community Edition';
return data;
} catch (error) {
throw parseAxiosError(error as Error);
}
}
export function useSystemStatus<T = StatusResponse>({
select,
enabled,
retry,
onSuccess,
}: {
select?: (status: StatusResponse) => T;
enabled?: boolean;
retry?: RetryValue<unknown>;
onSuccess?: (data: T) => void;
} = {}) {
return useQuery(queryKey, () => getSystemStatus(), {
select,
enabled,
retry,
onSuccess,
});
}

View file

@ -0,0 +1,38 @@
import { useQuery } from 'react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { buildUrl } from './build-url';
import { queryKeys } from './query-keys';
export const queryKey = [...queryKeys.base(), 'version'] as const;
export interface VersionResponse {
// Whether portainer has an update available
UpdateAvailable: boolean;
// The latest version available
LatestVersion: string;
ServerVersion: string;
DatabaseVersion: string;
Build: {
BuildNumber: string;
ImageTag: string;
NodejsVersion: string;
YarnVersion: string;
WebpackVersion: string;
GoVersion: string;
};
}
export async function getSystemVersion() {
try {
const { data } = await axios.get<VersionResponse>(buildUrl('version'));
return data;
} catch (error) {
throw parseAxiosError(error as Error);
}
}
export function useSystemVersion() {
return useQuery(queryKey, () => getSystemVersion());
}

View file

@ -0,0 +1,20 @@
import { useMutation } from 'react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { withError } from '@/react-tools/react-query';
import { buildUrl } from './build-url';
export function useUpgradeEditionMutation() {
return useMutation(upgradeEdition, {
...withError('Unable to upgrade edition'),
});
}
async function upgradeEdition({ license }: { license: string }) {
try {
await axios.post(buildUrl('upgrade'), { license });
} catch (error) {
throw parseAxiosError(error as Error);
}
}