mirror of
https://github.com/portainer/portainer.git
synced 2025-07-25 08:19:40 +02:00
chore(fdo): remove FDO code EE-7235 (#11981)
This commit is contained in:
parent
1a3db327c7
commit
19fa40286a
57 changed files with 3 additions and 2609 deletions
|
@ -15,7 +15,6 @@ import { EnvironmentStatus } from '../types';
|
|||
|
||||
import { columns } from './columns';
|
||||
import { EnvironmentListItem } from './types';
|
||||
import { ImportFdoDeviceButton } from './ImportFdoDeviceButton';
|
||||
|
||||
const tableKey = 'environments';
|
||||
const settingsStore = createPersistedStore(tableKey, 'Name');
|
||||
|
@ -83,8 +82,6 @@ export function EnvironmentsDatatable({
|
|||
Remove
|
||||
</Button>
|
||||
|
||||
<ImportFdoDeviceButton />
|
||||
|
||||
{isBE && (
|
||||
<AddButton
|
||||
color="secondary"
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import { AddButton } from '@@/buttons';
|
||||
|
||||
import { useSettings } from '../../settings/queries';
|
||||
import {
|
||||
FeatureFlag,
|
||||
useFeatureFlag,
|
||||
} from '../../feature-flags/useFeatureFlag';
|
||||
|
||||
export function ImportFdoDeviceButton() {
|
||||
const flagEnabledQuery = useFeatureFlag(FeatureFlag.FDO);
|
||||
|
||||
const isFDOEnabledQuery = useSettings(
|
||||
(settings) => settings.fdoConfiguration.enabled,
|
||||
flagEnabledQuery.data
|
||||
);
|
||||
|
||||
if (!isFDOEnabledQuery.data || !flagEnabledQuery.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ml-[5px]">
|
||||
<AddButton
|
||||
color="secondary"
|
||||
to="portainer.endpoints.importDevice"
|
||||
data-cy="import-fdo-device-button"
|
||||
>
|
||||
Import FDO device
|
||||
</AddButton>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
import { usePublicSettings } from '../settings/queries';
|
||||
|
||||
export enum FeatureFlag {
|
||||
FDO = 'fdo',
|
||||
}
|
||||
export enum FeatureFlag {}
|
||||
|
||||
export function useFeatureFlag(
|
||||
flag: FeatureFlag,
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import { List } from 'lucide-react';
|
||||
|
||||
import { Datatable } from '@@/datatables';
|
||||
import { createPersistedStore } from '@@/datatables/types';
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
|
||||
import { columns } from './columns';
|
||||
import { FDOProfilesDatatableActions } from './FDOProfilesDatatableActions';
|
||||
import { useFDOProfiles } from './useFDOProfiles';
|
||||
|
||||
const storageKey = 'fdoProfiles';
|
||||
|
||||
const settingsStore = createPersistedStore(storageKey, 'name');
|
||||
|
||||
export interface FDOProfilesDatatableProps {
|
||||
isFDOEnabled: boolean;
|
||||
}
|
||||
|
||||
export function FDOProfilesDatatable({
|
||||
isFDOEnabled,
|
||||
}: FDOProfilesDatatableProps) {
|
||||
const tableState = useTableState(settingsStore, storageKey);
|
||||
|
||||
const { isLoading, profiles } = useFDOProfiles();
|
||||
|
||||
return (
|
||||
<Datatable
|
||||
columns={columns}
|
||||
dataset={profiles}
|
||||
settingsManager={tableState}
|
||||
title="Device Profiles"
|
||||
titleIcon={List}
|
||||
disableSelect={!isFDOEnabled}
|
||||
getRowId={(row) => row.id.toString()}
|
||||
isLoading={isLoading}
|
||||
renderTableActions={(selectedItems) => (
|
||||
<FDOProfilesDatatableActions
|
||||
isFDOEnabled={isFDOEnabled}
|
||||
selectedItems={selectedItems}
|
||||
/>
|
||||
)}
|
||||
data-cy="fdo-profiles-datatable"
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useRouter } from '@uirouter/react';
|
||||
import { PlusCircle } from 'lucide-react';
|
||||
|
||||
import { Profile } from '@/portainer/hostmanagement/fdo/model';
|
||||
import * as notifications from '@/portainer/services/notifications';
|
||||
import {
|
||||
deleteProfile,
|
||||
duplicateProfile,
|
||||
} from '@/portainer/hostmanagement/fdo/fdo.service';
|
||||
|
||||
import { confirm } from '@@/modals/confirm';
|
||||
import { Link } from '@@/Link';
|
||||
import { Button } from '@@/buttons';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
interface Props {
|
||||
isFDOEnabled: boolean;
|
||||
selectedItems: Profile[];
|
||||
}
|
||||
|
||||
export function FDOProfilesDatatableActions({
|
||||
isFDOEnabled,
|
||||
selectedItems,
|
||||
}: Props) {
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link
|
||||
to="portainer.endpoints.profile"
|
||||
className="space-left"
|
||||
data-cy="fdo-add-profile-link"
|
||||
>
|
||||
<Button
|
||||
disabled={!isFDOEnabled}
|
||||
icon={PlusCircle}
|
||||
data-cy="fdo-add-profile-button"
|
||||
>
|
||||
Add Profile
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Button
|
||||
disabled={!isFDOEnabled || selectedItems.length !== 1}
|
||||
data-cy="fdo-duplicate-profile-button"
|
||||
onClick={() => onDuplicateProfileClick()}
|
||||
icon={PlusCircle}
|
||||
>
|
||||
Duplicate
|
||||
</Button>
|
||||
|
||||
<DeleteButton
|
||||
disabled={!isFDOEnabled || selectedItems.length === 0}
|
||||
onConfirmed={() => onDeleteProfileClick()}
|
||||
confirmMessage="This action will delete the selected profile(s). Continue?"
|
||||
data-cy="fdo-remove-profile-button"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
async function onDuplicateProfileClick() {
|
||||
const confirmed = await confirm({
|
||||
title: 'Are you sure ?',
|
||||
message: 'This action will duplicate the selected profile. Continue?',
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const profile = selectedItems[0];
|
||||
const newProfile = await duplicateProfile(profile.id);
|
||||
notifications.success('Profile successfully duplicated', profile.name);
|
||||
router.stateService.go('portainer.endpoints.profile.edit', {
|
||||
id: newProfile.id,
|
||||
});
|
||||
} catch (err) {
|
||||
notifications.error(
|
||||
'Failure',
|
||||
err as Error,
|
||||
'Unable to duplicate profile'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function onDeleteProfileClick() {
|
||||
await Promise.all(
|
||||
selectedItems.map(async (profile) => {
|
||||
try {
|
||||
await deleteProfile(profile.id);
|
||||
|
||||
notifications.success('Profile successfully removed', profile.name);
|
||||
} catch (err) {
|
||||
notifications.error(
|
||||
'Failure',
|
||||
err as Error,
|
||||
'Unable to remove profile'
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
await queryClient.invalidateQueries(['fdo_profiles']);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import { isoDateFromTimestamp } from '@/portainer/filters/filters';
|
||||
|
||||
import { columnHelper } from './helper';
|
||||
|
||||
export const created = columnHelper.accessor('dateCreated', {
|
||||
header: 'Created',
|
||||
id: 'created',
|
||||
cell: ({ getValue }) => {
|
||||
const value = getValue();
|
||||
return isoDateFromTimestamp(value);
|
||||
},
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
|
||||
import { Profile } from '@/portainer/hostmanagement/fdo/model';
|
||||
|
||||
export const columnHelper = createColumnHelper<Profile>();
|
|
@ -1,14 +0,0 @@
|
|||
import { Profile } from '@/portainer/hostmanagement/fdo/model';
|
||||
|
||||
import { buildNameColumn } from '@@/datatables/buildNameColumn';
|
||||
|
||||
import { created } from './created';
|
||||
|
||||
export const columns = [
|
||||
buildNameColumn<Profile>(
|
||||
'name',
|
||||
'portainer.endpoints.profile.edit',
|
||||
'fdo-profiles-name'
|
||||
),
|
||||
created,
|
||||
];
|
|
@ -1 +0,0 @@
|
|||
export { FDOProfilesDatatable } from './FDOProfilesDatatable';
|
|
@ -1,30 +0,0 @@
|
|||
import { useEffect, useMemo } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import PortainerError from '@/portainer/error';
|
||||
import * as notifications from '@/portainer/services/notifications';
|
||||
import { getProfiles } from '@/portainer/hostmanagement/fdo/fdo.service';
|
||||
|
||||
export function useFDOProfiles() {
|
||||
const { isLoading, data, isError, error } = useQuery(['fdo_profiles'], () =>
|
||||
getProfiles()
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isError) {
|
||||
notifications.error(
|
||||
'Failure',
|
||||
error as Error,
|
||||
'Failed retrieving FDO profiles'
|
||||
);
|
||||
}
|
||||
}, [isError, error]);
|
||||
|
||||
const profiles = useMemo(() => data || [], [data]);
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
profiles,
|
||||
error: isError ? (error as PortainerError) : undefined,
|
||||
};
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
.fdo-table {
|
||||
margin-top: 3em;
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { Formik, Field, Form } from 'formik';
|
||||
import { FlaskConical, Laptop } from 'lucide-react';
|
||||
|
||||
import { FDOConfiguration } from '@/portainer/hostmanagement/fdo/model';
|
||||
import {
|
||||
FeatureFlag,
|
||||
useFeatureFlag,
|
||||
} from '@/react/portainer/feature-flags/useFeatureFlag';
|
||||
|
||||
import { Switch } from '@@/form-components/SwitchField/Switch';
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { FormSectionTitle } from '@@/form-components/FormSectionTitle';
|
||||
import { Widget, WidgetBody, WidgetTitle } from '@@/Widget';
|
||||
import { LoadingButton } from '@@/buttons/LoadingButton';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
|
||||
import { FDOProfilesDatatable } from '../FDOProfilesDatatable';
|
||||
|
||||
import styles from './SettingsFDO.module.css';
|
||||
import { validationSchema } from './SettingsFDO.validation';
|
||||
|
||||
export interface Settings {
|
||||
fdoConfiguration: FDOConfiguration;
|
||||
EnableEdgeComputeFeatures: boolean;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
settings: Settings;
|
||||
onSubmit(values: FDOConfiguration): void;
|
||||
}
|
||||
|
||||
export function SettingsFDO({ settings, onSubmit }: Props) {
|
||||
const flagEnabledQuery = useFeatureFlag(FeatureFlag.FDO);
|
||||
|
||||
if (!flagEnabledQuery.data) {
|
||||
return (
|
||||
<Widget>
|
||||
<Widget.Body>
|
||||
<TextTip color="blue" icon={FlaskConical}>
|
||||
Since FDO is still an experimental feature that requires additional
|
||||
infrastructure, it has been temporarily hidden in the UI.
|
||||
</TextTip>
|
||||
</Widget.Body>
|
||||
</Widget>
|
||||
);
|
||||
}
|
||||
|
||||
return <SettingsFDOForm settings={settings} onSubmit={onSubmit} />;
|
||||
}
|
||||
|
||||
export function SettingsFDOForm({ settings, onSubmit }: Props) {
|
||||
const fdoConfiguration = settings ? settings.fdoConfiguration : null;
|
||||
const initialFDOEnabled = fdoConfiguration ? fdoConfiguration.enabled : false;
|
||||
|
||||
const [isFDOEnabled, setIsFDOEnabled] = useState(initialFDOEnabled);
|
||||
useEffect(() => {
|
||||
setIsFDOEnabled(settings?.fdoConfiguration?.enabled);
|
||||
}, [settings]);
|
||||
|
||||
const initialValues = {
|
||||
enabled: initialFDOEnabled,
|
||||
ownerURL: fdoConfiguration ? fdoConfiguration.ownerURL : '',
|
||||
ownerUsername: fdoConfiguration ? fdoConfiguration.ownerUsername : '',
|
||||
ownerPassword: fdoConfiguration ? fdoConfiguration.ownerPassword : '',
|
||||
};
|
||||
|
||||
const edgeComputeFeaturesEnabled = settings
|
||||
? settings.EnableEdgeComputeFeatures
|
||||
: false;
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<Widget>
|
||||
<WidgetTitle icon={Laptop} title="FDO" />
|
||||
<WidgetBody>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={onSubmit}
|
||||
enableReinitialize
|
||||
validationSchema={() => validationSchema()}
|
||||
validateOnChange
|
||||
validateOnMount
|
||||
>
|
||||
{({
|
||||
values,
|
||||
errors,
|
||||
handleSubmit,
|
||||
setFieldValue,
|
||||
isSubmitting,
|
||||
isValid,
|
||||
dirty,
|
||||
}) => (
|
||||
<Form className="form-horizontal" onSubmit={handleSubmit}>
|
||||
<FormControl
|
||||
inputId="edge_enableFDO"
|
||||
label="Enable FDO Management Service"
|
||||
size="small"
|
||||
errors={errors.enabled}
|
||||
>
|
||||
<Switch
|
||||
id="edge_enableFDO"
|
||||
data-cy="edge-enableFDO-switch"
|
||||
name="edge_enableFDO"
|
||||
className="space-right"
|
||||
disabled={!edgeComputeFeaturesEnabled}
|
||||
checked={edgeComputeFeaturesEnabled && values.enabled}
|
||||
onChange={(e) => onChangedEnabled(e, setFieldValue)}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<TextTip color="blue" className="mb-2">
|
||||
When enabled, this will allow Portainer to interact with FDO
|
||||
Services.
|
||||
</TextTip>
|
||||
|
||||
{edgeComputeFeaturesEnabled && values.enabled && (
|
||||
<>
|
||||
<hr />
|
||||
|
||||
<FormControl
|
||||
inputId="owner_url"
|
||||
label="Owner Service Server"
|
||||
errors={errors.ownerURL}
|
||||
>
|
||||
<Field
|
||||
as={Input}
|
||||
name="ownerURL"
|
||||
id="owner_url"
|
||||
placeholder="http://127.0.0.1:8042"
|
||||
value={values.ownerURL}
|
||||
data-cy="fdo-serverInput"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl
|
||||
inputId="owner_username"
|
||||
label="Owner Service Username"
|
||||
errors={errors.ownerUsername}
|
||||
>
|
||||
<Field
|
||||
as={Input}
|
||||
name="ownerUsername"
|
||||
id="owner_username"
|
||||
placeholder="username"
|
||||
value={values.ownerUsername}
|
||||
data-cy="fdo-usernameInput"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl
|
||||
inputId="owner_password"
|
||||
label="Owner Service Password"
|
||||
errors={errors.ownerPassword}
|
||||
>
|
||||
<Field
|
||||
as={Input}
|
||||
type="password"
|
||||
name="ownerPassword"
|
||||
id="owner_password"
|
||||
placeholder="password"
|
||||
value={values.ownerPassword}
|
||||
data-cy="fdo-passwordInput"
|
||||
/>
|
||||
</FormControl>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="form-group mt-5">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
disabled={!isValid || !dirty}
|
||||
data-cy="settings-fdoButton"
|
||||
isLoading={isSubmitting}
|
||||
loadingText="Saving settings..."
|
||||
>
|
||||
Save settings
|
||||
</LoadingButton>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
|
||||
{edgeComputeFeaturesEnabled && isFDOEnabled && (
|
||||
<div className={styles.fdoTable}>
|
||||
<FormSectionTitle>Device Profiles</FormSectionTitle>
|
||||
<TextTip color="blue" className="mb-2">
|
||||
Add, Edit and Manage the list of device profiles available
|
||||
during FDO device setup
|
||||
</TextTip>
|
||||
<FDOProfilesDatatable isFDOEnabled={initialFDOEnabled} />
|
||||
</div>
|
||||
)}
|
||||
</WidgetBody>
|
||||
</Widget>
|
||||
</div>
|
||||
);
|
||||
|
||||
async function onChangedEnabled(
|
||||
e: boolean,
|
||||
setFieldValue: (
|
||||
field: string,
|
||||
value: unknown,
|
||||
shouldValidate?: boolean
|
||||
) => void
|
||||
) {
|
||||
setIsFDOEnabled(e);
|
||||
setFieldValue('enabled', e);
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import { object, string } from 'yup';
|
||||
|
||||
export function validationSchema() {
|
||||
return object().shape({
|
||||
ownerURL: string().when('enabled', {
|
||||
is: true,
|
||||
then: string().required('Field is required'),
|
||||
}),
|
||||
ownerUsername: string().when('enabled', {
|
||||
is: true,
|
||||
then: string().required('Field is required'),
|
||||
}),
|
||||
ownerPassword: string().when('enabled', {
|
||||
is: true,
|
||||
then: string().required('Field is required'),
|
||||
}),
|
||||
});
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export { SettingsFDO } from './SettingsFDO';
|
|
@ -253,7 +253,7 @@ export function SettingsOpenAMT({ settings, onSubmit }: Props) {
|
|||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
disabled={!isValid || !dirty}
|
||||
data-cy="settings-fdoButton"
|
||||
data-cy="settings-OpenAMTButton"
|
||||
isLoading={isSubmitting}
|
||||
loadingText="Saving settings..."
|
||||
>
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
import { TeamId } from '@/react/portainer/users/teams/types';
|
||||
|
||||
export interface FDOConfiguration {
|
||||
enabled: boolean;
|
||||
ownerURL: string;
|
||||
ownerUsername: string;
|
||||
ownerPassword: string;
|
||||
}
|
||||
|
||||
export interface TLSConfiguration {
|
||||
TLS: boolean;
|
||||
TLSSkipVerify: boolean;
|
||||
|
@ -119,7 +112,6 @@ export interface Settings {
|
|||
LDAPSettings: LDAPSettings;
|
||||
OAuthSettings: OAuthSettings;
|
||||
openAMTConfiguration: OpenAMTConfiguration;
|
||||
fdoConfiguration: FDOConfiguration;
|
||||
FeatureFlagSettings: { [key: Feature]: boolean };
|
||||
SnapshotInterval: string;
|
||||
TemplatesURL: string;
|
||||
|
@ -201,8 +193,6 @@ export interface PublicSettingsResponse {
|
|||
KubeconfigExpiry: string;
|
||||
/** Whether team sync is enabled */
|
||||
TeamSync: boolean;
|
||||
/** Whether FDO is enabled */
|
||||
IsFDOEnabled: boolean;
|
||||
/** Whether AMT is enabled */
|
||||
IsAMTEnabled: boolean;
|
||||
/** Whether to hide default registry (only on BE) */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue