refactor(edge): move edge codebase to react (#7781)

pull/8086/head
Chaim Lev-Ari 2022-11-21 09:51:55 +02:00 committed by GitHub
parent 75f40fe485
commit 1e4c4e2616
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 254 additions and 187 deletions

View File

@ -1 +0,0 @@
export { EdgeDevicesView } from './EdgeDevicesView';

View File

@ -1,17 +1,11 @@
import angular from 'angular';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { r2a } from '@/react-tools/react2angular';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { withUIRouter } from '@/react-tools/withUIRouter';
import edgeStackModule from './views/edge-stacks';
import { componentsModule } from './components';
import { WaitingRoomView } from './EdgeDevices/WaitingRoomView';
import { reactModule } from './react';
angular
.module('portainer.edge', [edgeStackModule, componentsModule, reactModule])
.component('waitingRoomView', r2a(withUIRouter(withReactQuery(withCurrentUser(WaitingRoomView))), []))
.module('portainer.edge', [edgeStackModule, reactModule])
.config(function config($stateRegistryProvider) {
const edge = {
name: 'edge',

View File

@ -1,114 +0,0 @@
import { useEffect, useState } from 'react';
import { r2a } from '@/react-tools/react2angular';
import { useSettings } from '@/react/portainer/settings/queries';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { FormControl, Size } from '@@/form-components/FormControl';
import { Select } from '@@/form-components/Input';
interface Props {
value: number;
onChange(value: number): void;
isDefaultHidden?: boolean;
label?: string;
tooltip?: string;
readonly?: boolean;
size?: Size;
}
export const checkinIntervalOptions = [
{ label: 'Use default interval', value: 0 },
{
label: '5 seconds',
value: 5,
},
{
label: '10 seconds',
value: 10,
},
{
label: '30 seconds',
value: 30,
},
{ label: '5 minutes', value: 300 },
{ label: '1 hour', value: 3600 },
{ label: '1 day', value: 86400 },
];
export function EdgeCheckinIntervalField({
value,
readonly,
onChange,
isDefaultHidden = false,
label = 'Poll frequency',
tooltip = 'Interval used by this Edge agent to check in with the Portainer instance. Affects Edge environment management and Edge compute features.',
size = 'small',
}: Props) {
const options = useOptions(isDefaultHidden);
return (
<FormControl
inputId="edge_checkin"
label={label}
tooltip={tooltip}
size={size}
>
<Select
value={value}
onChange={(e) => {
onChange(parseInt(e.currentTarget.value, 10));
}}
options={options}
disabled={readonly}
/>
</FormControl>
);
}
export const EdgeCheckinIntervalFieldAngular = r2a(
withReactQuery(EdgeCheckinIntervalField),
[
'value',
'onChange',
'isDefaultHidden',
'tooltip',
'label',
'readonly',
'size',
]
);
function useOptions(isDefaultHidden: boolean) {
const [options, setOptions] = useState(checkinIntervalOptions);
const settingsQuery = useSettings(
(settings) => settings.EdgeAgentCheckinInterval
);
useEffect(() => {
if (isDefaultHidden) {
setOptions(checkinIntervalOptions.filter((option) => option.value !== 0));
}
if (!isDefaultHidden && typeof settingsQuery.data !== 'undefined') {
setOptions((options) => {
let label = `${settingsQuery.data} seconds`;
const option = options.find((o) => o.value === settingsQuery.data);
if (option) {
label = option.label;
}
return [
{
value: 0,
label: `Use default interval (${label})`,
},
...options.slice(1),
];
});
}
}, [settingsQuery.data, setOptions, isDefaultHidden]);
return options;
}

View File

@ -1,19 +0,0 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { EdgeCheckinIntervalFieldAngular } from './EdgeCheckInIntervalField';
export const componentsModule = angular
.module('app.edge.components', [])
.component(
'edgeScriptForm',
r2a(withReactQuery(EdgeScriptForm), [
'edgeInfo',
'commands',
'isNomadTokenVisible',
])
)
.component('edgeCheckinIntervalField', EdgeCheckinIntervalFieldAngular).name;

View File

@ -1,11 +1,46 @@
import angular from 'angular';
import { EdgeGroupsSelector } from '@/react/edge/components/EdgeGroupsSelector';
import { EdgeGroupsSelector } from '@/react/edge/edge-stacks/components/EdgeGroupsSelector';
import { r2a } from '@/react-tools/react2angular';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
import { EdgeAsyncIntervalsForm } from '@/react/edge/components/EdgeAsyncIntervalsForm';
export const componentsModule = angular
.module('portainer.edge.react.components', [])
.component(
'edgeGroupsSelector',
r2a(EdgeGroupsSelector, ['items', 'onChange', 'value'])
)
.component(
'edgeScriptForm',
r2a(withReactQuery(EdgeScriptForm), [
'edgeInfo',
'commands',
'isNomadTokenVisible',
'hideAsyncMode',
])
)
.component(
'edgeCheckinIntervalField',
r2a(withReactQuery(EdgeCheckinIntervalField), [
'value',
'onChange',
'isDefaultHidden',
'tooltip',
'label',
'readonly',
'size',
])
)
.component(
'edgeAsyncIntervalsForm',
r2a(withReactQuery(EdgeAsyncIntervalsForm), [
'values',
'onChange',
'isDefaultHidden',
'readonly',
'fieldSettings',
])
).name;

View File

@ -1,14 +1,19 @@
import angular from 'angular';
import { EdgeDevicesView } from '@/edge/EdgeDevices/EdgeDevicesView';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { r2a } from '@/react-tools/react2angular';
import { ListView } from '@/react/edge/edge-devices/ListView';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { WaitingRoomView } from '@/react/edge/edge-devices/WaitingRoomView';
export const viewsModule = angular
.module('portainer.edge.react.views', [])
.component(
'waitingRoomView',
r2a(withUIRouter(withReactQuery(withCurrentUser(WaitingRoomView))), [])
)
.component(
'edgeDevicesView',
r2a(withUIRouter(withReactQuery(withCurrentUser(EdgeDevicesView))), [])
r2a(withUIRouter(withReactQuery(withCurrentUser(ListView))), [])
).name;

View File

View File

@ -1,7 +1,5 @@
import { number, object, SchemaOf } from 'yup';
import { r2a } from '@/react-tools/react2angular';
import { FormControl } from '@@/form-components/FormControl';
import { Select } from '@@/form-components/Input';
@ -153,11 +151,3 @@ export function edgeAsyncIntervalsValidation(): SchemaOf<EdgeAsyncIntervalsValue
.oneOf(intervals),
});
}
export const EdgeAsyncIntervalsFormAngular = r2a(EdgeAsyncIntervalsForm, [
'values',
'onChange',
'isDefaultHidden',
'readonly',
'fieldSettings',
]);

View File

@ -0,0 +1,67 @@
import { FormControl, Size } from '@@/form-components/FormControl';
import { Select } from '@@/form-components/Input';
import { Options, useIntervalOptions } from './useIntervalOptions';
interface Props {
value: number;
onChange(value: number): void;
isDefaultHidden?: boolean;
label?: string;
tooltip?: string;
readonly?: boolean;
size?: Size;
}
export const checkinIntervalOptions: Options = [
{ label: 'Use default interval', value: 0, isDefault: true },
{
label: '5 seconds',
value: 5,
},
{
label: '10 seconds',
value: 10,
},
{
label: '30 seconds',
value: 30,
},
{ label: '5 minutes', value: 300 },
{ label: '1 hour', value: 3600 },
{ label: '1 day', value: 86400 },
];
export function EdgeCheckinIntervalField({
value,
readonly,
onChange,
isDefaultHidden = false,
label = 'Poll frequency',
tooltip = 'Interval used by this Edge agent to check in with the Portainer instance. Affects Edge environment management and Edge compute features.',
size = 'small',
}: Props) {
const options = useIntervalOptions(
'EdgeAgentCheckinInterval',
checkinIntervalOptions,
isDefaultHidden
);
return (
<FormControl
inputId="edge_checkin"
label={label}
tooltip={tooltip}
size={size}
>
<Select
value={value}
onChange={(e) => {
onChange(parseInt(e.currentTarget.value, 10));
}}
options={options}
disabled={readonly}
/>
</FormControl>
);
}

View File

@ -14,18 +14,21 @@ const edgePropertiesFormInitialValues: ScriptFormValues = {
platform: 'k8s' as Platform,
nomadToken: '',
authEnabled: true,
tlsEnabled: false,
};
interface Props {
edgeInfo: EdgeInfo;
commands: CommandTab[] | Partial<Record<OS, CommandTab[]>>;
isNomadTokenVisible?: boolean;
hideAsyncMode?: boolean;
}
export function EdgeScriptForm({
edgeInfo,
commands,
isNomadTokenVisible,
hideAsyncMode,
}: Props) {
const showOsSelector = !(commands instanceof Array);
@ -60,6 +63,7 @@ export function EdgeScriptForm({
onPlatformChange={(platform) =>
setFieldValue('platform', platform)
}
hideAsyncMode={hideAsyncMode}
/>
</div>
</>

View File

@ -6,6 +6,17 @@ export function validationSchema(isNomadTokenVisible?: boolean) {
return object().shape({
allowSelfSignedCertificates: boolean(),
envVars: string(),
...(isNomadTokenVisible ? nomadTokenValidation() : {}),
...nomadValidation(isNomadTokenVisible),
});
}
function nomadValidation(isNomadTokenVisible?: boolean) {
if (!isNomadTokenVisible) {
return {};
}
return {
tlsEnabled: boolean().default(false),
...nomadTokenValidation(),
};
}

View File

@ -1,4 +1,4 @@
import { Field, useFormikContext } from 'formik';
import { useFormikContext, Field } from 'formik';
import { FormControl } from '@@/form-components/FormControl';
import { Input } from '@@/form-components/Input';
@ -47,7 +47,22 @@ export function EdgeScriptSettingsFieldset({
</>
)}
{isNomadTokenVisible && <NomadTokenField />}
{isNomadTokenVisible && (
<>
<NomadTokenField />
<div className="form-group">
<div className="col-sm-12">
<SwitchField
label="TLS"
labelClass="col-sm-3 col-lg-2"
checked={values.tlsEnabled}
onChange={(checked) => setFieldValue('tlsEnabled', checked)}
/>
</div>
</div>
</>
)}
<FormControl
label="Environment variables"

View File

@ -16,6 +16,7 @@ interface Props {
commands: CommandTab[];
platform?: Platform;
onPlatformChange?(platform: Platform): void;
hideAsyncMode?: boolean;
}
export function ScriptTabs({
@ -24,6 +25,7 @@ export function ScriptTabs({
edgeId,
commands,
platform,
hideAsyncMode = false,
onPlatformChange = () => {},
}: Props) {
const agentDetails = useAgentDetails();
@ -38,10 +40,17 @@ export function ScriptTabs({
return null;
}
const { agentSecret, agentVersion } = agentDetails;
const { agentSecret, agentVersion, useEdgeAsyncMode } = agentDetails;
const options = commands.map((c) => {
const cmd = c.command(agentVersion, edgeKey, values, edgeId, agentSecret);
const cmd = c.command(
agentVersion,
edgeKey,
values,
!hideAsyncMode && useEdgeAsyncMode,
edgeId,
agentSecret
);
return {
id: c.id,

View File

@ -8,6 +8,7 @@ type CommandGenerator = (
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) => string;
@ -34,6 +35,11 @@ export const commandsTabs: Record<string, CommandTab> = {
label: 'Docker Standalone',
command: buildLinuxStandaloneCommand,
},
nomadLinux: {
id: 'nomad',
label: 'Nomad',
command: buildLinuxNomadCommand,
},
swarmWindows: {
id: 'swarm',
label: 'Docker Swarm',
@ -58,6 +64,7 @@ export function buildLinuxStandaloneCommand(
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) {
@ -69,7 +76,8 @@ export function buildLinuxStandaloneCommand(
edgeKey,
allowSelfSignedCertificates,
!edgeIdGenerator ? edgeId : undefined,
agentSecret
agentSecret,
useAsyncMode
)
);
@ -92,6 +100,7 @@ export function buildWindowsStandaloneCommand(
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) {
@ -103,7 +112,8 @@ export function buildWindowsStandaloneCommand(
edgeKey,
allowSelfSignedCertificates,
edgeIdGenerator ? '$Env:PORTAINER_EDGE_ID' : edgeId,
agentSecret
agentSecret,
useAsyncMode
)
);
@ -127,6 +137,7 @@ export function buildLinuxSwarmCommand(
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) {
@ -137,7 +148,8 @@ export function buildLinuxSwarmCommand(
edgeKey,
allowSelfSignedCertificates,
!edgeIdGenerator ? edgeId : undefined,
agentSecret
agentSecret,
useAsyncMode
),
'AGENT_CLUSTER_ADDR=tasks.portainer_edge_agent',
]);
@ -167,6 +179,7 @@ export function buildWindowsSwarmCommand(
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) {
@ -177,7 +190,8 @@ export function buildWindowsSwarmCommand(
edgeKey,
allowSelfSignedCertificates,
edgeIdGenerator ? '$Env:PORTAINER_EDGE_ID' : edgeId,
agentSecret
agentSecret,
useAsyncMode
),
'AGENT_CLUSTER_ADDR=tasks.portainer_edge_agent',
]);
@ -208,13 +222,17 @@ export function buildLinuxKubernetesCommand(
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) {
const { allowSelfSignedCertificates, edgeIdGenerator, envVars } = properties;
const agentShortVersion = getAgentShortVersion(agentVersion);
const envVarsTrimmed = envVars.trim();
let envVarsTrimmed = envVars.trim();
if (useAsyncMode) {
envVarsTrimmed += `EDGE_ASYNC=1`;
}
const idEnvVar = edgeIdGenerator
? `PORTAINER_EDGE_ID=$(${edgeIdGenerator}) \n\n`
: '';
@ -224,11 +242,43 @@ export function buildLinuxKubernetesCommand(
return `${idEnvVar}curl https://downloads.portainer.io/ee${agentShortVersion}/portainer-edge-agent-setup.sh | bash -s -- "${edgeIdVar}" "${edgeKey}" "${selfSigned}" "${agentSecret}" "${envVarsTrimmed}"`;
}
export function buildLinuxNomadCommand(
agentVersion: string,
edgeKey: string,
properties: ScriptFormValues,
useAsyncMode: boolean,
edgeId?: string,
agentSecret?: string
) {
const {
allowSelfSignedCertificates,
edgeIdGenerator,
envVars,
nomadToken = '',
tlsEnabled,
} = properties;
const agentShortVersion = getAgentShortVersion(agentVersion);
let envVarsTrimmed = envVars.trim();
if (useAsyncMode) {
envVarsTrimmed += `EDGE_ASYNC=1`;
}
const selfSigned = allowSelfSignedCertificates ? '1' : '0';
const idEnvVar = edgeIdGenerator
? `PORTAINER_EDGE_ID=$(${edgeIdGenerator}) \n\n`
: '';
const edgeIdVar = !edgeIdGenerator && edgeId ? edgeId : '$PORTAINER_EDGE_ID';
return `${idEnvVar}curl https://downloads.portainer.io/ee${agentShortVersion}/portainer-edge-agent-nomad-setup.sh | bash -s -- "${nomadToken}" "${edgeIdVar}" "${edgeKey}" "${selfSigned}" "${envVarsTrimmed}" "${agentSecret}" "${tlsEnabled}"`;
}
function buildDefaultEnvVars(
edgeKey: string,
allowSelfSignedCerts: boolean,
edgeId = '$PORTAINER_EDGE_ID',
agentSecret = ''
agentSecret = '',
useAsyncMode = false
) {
return _.compact([
'EDGE=1',
@ -236,5 +286,6 @@ function buildDefaultEnvVars(
`EDGE_KEY=${edgeKey}`,
`EDGE_INSECURE_POLL=${allowSelfSignedCerts ? 1 : 0}`,
agentSecret ? `AGENT_SECRET=${agentSecret}` : ``,
useAsyncMode ? 'EDGE_ASYNC=1' : '',
]);
}

View File

@ -4,6 +4,7 @@ export type OS = 'win' | 'linux';
export interface ScriptFormValues {
nomadToken: string;
authEnabled: boolean;
tlsEnabled: boolean;
allowSelfSignedCertificates: boolean;
envVars: string;

View File

@ -1,14 +1,14 @@
import { usePagination, useTable } from 'react-table';
import { Device } from '@/portainer/hostmanagement/open-amt/model';
import { useAMTDevices } from '@/edge/EdgeDevices/EdgeDevicesView/AMTDevicesDatatable/useAMTDevices';
import { RowProvider } from '@/edge/EdgeDevices/EdgeDevicesView/AMTDevicesDatatable/columns/RowContext';
import { EnvironmentId } from '@/react/portainer/environments/types';
import PortainerError from '@/portainer/error';
import { InnerDatatable } from '@@/datatables/InnerDatatable';
import { Table, TableContainer, TableHeaderRow, TableRow } from '@@/datatables';
import { useAMTDevices } from './useAMTDevices';
import { RowProvider } from './columns/RowContext';
import { useColumns } from './columns';
export interface AMTDevicesTableProps {

View File

@ -0,0 +1 @@
export { AMTDevicesDatatable } from './AMTDevicesDatatable';

View File

@ -3,7 +3,6 @@ import { useRowSelectColumn } from '@lineup-lite/hooks';
import _ from 'lodash';
import { Environment } from '@/react/portainer/environments/types';
import { AMTDevicesDatatable } from '@/edge/EdgeDevices/EdgeDevicesView/AMTDevicesDatatable/AMTDevicesDatatable';
import { EnvironmentGroup } from '@/react/portainer/environments/environment-groups/types';
import { PaginationControls } from '@@/PaginationControls';
@ -26,6 +25,7 @@ import { TableFooter } from '@@/datatables/TableFooter';
import { SelectedRowsCount } from '@@/datatables/SelectedRowsCount';
import { TextTip } from '@@/Tip/TextTip';
import { AMTDevicesDatatable } from './AMTDevicesDatatable';
import { EdgeDevicesDatatableActions } from './EdgeDevicesDatatableActions';
import { EdgeDevicesDatatableSettings } from './EdgeDevicesDatatableSettings';
import { RowProvider } from './columns/RowContext';

View File

@ -5,7 +5,7 @@ import { useRouter, useSref } from '@uirouter/react';
import { Environment } from '@/react/portainer/environments/types';
import { snapshotEndpoint } from '@/react/portainer/environments/environment.service';
import * as notifications from '@/portainer/services/notifications';
import { getRoute } from '@/react/portainer/environments/utils';
import { getDashboardRoute } from '@/react/portainer/environments/utils';
import { ActionsMenu } from '@@/datatables/ActionsMenu';
@ -27,19 +27,33 @@ export function ActionsCell({
}: CellProps<Environment>) {
const router = useRouter();
const environmentRoute = getRoute(environment);
const environmentRoute = getDashboardRoute(environment);
const browseLinkProps = useSref(environmentRoute, {
id: environment.Id,
endpointId: environment.Id,
});
const snapshotLinkProps = useSref('edge.browse.dashboard', {
environmentId: environment.Id,
});
const showRefreshSnapshot = false; // remove and show MenuItem when feature is available
return (
<ActionsMenu>
<MenuLink href={browseLinkProps.href} onClick={browseLinkProps.onClick}>
Browse
</MenuLink>
{environment.Edge.AsyncMode ? (
<MenuLink
className="!text-inherit hover:!no-underline"
href={snapshotLinkProps.href}
onClick={snapshotLinkProps.onClick}
>
Browse Snapshot
</MenuLink>
) : (
<MenuLink href={browseLinkProps.href} onClick={browseLinkProps.onClick}>
Browse
</MenuLink>
)}
{showRefreshSnapshot && (
<MenuItem hidden onSelect={() => handleRefreshSnapshotClick()}>
Refresh Snapshot

View File

@ -8,7 +8,7 @@ import { ViewLoading } from '@@/ViewLoading';
import { EdgeDevicesDatatableContainer } from './EdgeDevicesDatatable/EdgeDevicesDatatableContainer';
export function EdgeDevicesView() {
export function ListView() {
const [loadingMessage, setLoadingMessage] = useState('');
const settingsQuery = useSettings();

View File

@ -0,0 +1 @@
export { ListView } from './ListView';

View File

@ -1,8 +1,8 @@
import _ from 'lodash';
import { Select } from '@@/form-components/ReactSelect';
import { EdgeGroup } from '@/react/edge/edge-groups/types';
import { EdgeGroup } from '../edge-groups/types';
import { Select } from '@@/form-components/ReactSelect';
type SingleValue = EdgeGroup['Id'];

View File

@ -2,7 +2,7 @@ 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 settingsQuery = useSettings();
const versionQuery = useStatus((status) => status.Version);
@ -11,7 +11,10 @@ export function useAgentDetails() {
}
const agentVersion = versionQuery.data;
const agentSecret = settingsQuery.data;
return { agentVersion, agentSecret };
return {
agentVersion,
agentSecret: settingsQuery.data.AgentSecret,
useEdgeAsyncMode: settingsQuery.data.Edge.AsyncMode,
};
}

View File

@ -55,7 +55,7 @@ export function isUnassociatedEdgeEnvironment(env: Environment) {
return isEdgeEnvironment(env.Type) && !env.EdgeID;
}
export function getRoute(environment: Environment) {
export function getDashboardRoute(environment: Environment) {
if (isEdgeEnvironment(environment.Type) && !environment.EdgeID) {
return 'portainer.endpoints.endpoint';
}

View File

@ -3,7 +3,7 @@ import { Formik, Form } from 'formik';
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 { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
import { useCreateEdgeDeviceParam } from '@/react/portainer/environments/wizard/hooks/useCreateEdgeDeviceParam';
import { FormSection } from '@@/form-components/FormSection';

View File

@ -1,8 +1,8 @@
import { Form, Formik } from 'formik';
import { useReducer } from 'react';
import { EdgeCheckinIntervalField } from '@/edge/components/EdgeCheckInIntervalField';
import { EdgeAsyncIntervalsForm } from '@/edge/components/EdgeAsyncIntervalsForm';
import { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
import { EdgeAsyncIntervalsForm } from '@/react/edge/components/EdgeAsyncIntervalsForm';
import { notifySuccess } from '@/portainer/services/notifications';
import { FormControl } from '@@/form-components/FormControl';

View File

@ -1,6 +1,6 @@
import { boolean, number, object, SchemaOf } from 'yup';
import { options as asyncIntervalOptions } from '@/edge/components/EdgeAsyncIntervalsForm';
import { options as asyncIntervalOptions } from '@/react/edge/components/EdgeAsyncIntervalsForm';
import { FormValues } from './types';

View File

@ -1,6 +1,6 @@
import { Formik, Form } from 'formik';
import { EdgeCheckinIntervalField } from '@/edge/components/EdgeCheckInIntervalField';
import { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
import { Switch } from '@@/form-components/SwitchField/Switch';
import { FormControl } from '@@/form-components/FormControl';