diff --git a/app/angulartics.matomo/analytics-services.ts b/app/angulartics.matomo/analytics-services.ts
index c1202fd79..da543af66 100644
--- a/app/angulartics.matomo/analytics-services.ts
+++ b/app/angulartics.matomo/analytics-services.ts
@@ -1,6 +1,6 @@
import _ from 'lodash';
-import { usePublicSettings } from '@/portainer/settings/queries';
+import { usePublicSettings } from '@/react/portainer/settings/queries';
const categories = [
'docker',
diff --git a/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesView.tsx b/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesView.tsx
index d30e464c7..ff2e0a5d9 100644
--- a/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesView.tsx
+++ b/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesView.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
-import { useSettings } from '@/portainer/settings/queries';
+import { useSettings } from '@/react/portainer/settings/queries';
import { useGroups } from '@/portainer/environment-groups/queries';
import { PageHeader } from '@@/PageHeader';
diff --git a/app/edge/components/EdgeAsyncIntervalsForm.tsx b/app/edge/components/EdgeAsyncIntervalsForm.tsx
new file mode 100644
index 000000000..f36ccd9ec
--- /dev/null
+++ b/app/edge/components/EdgeAsyncIntervalsForm.tsx
@@ -0,0 +1,163 @@
+import { number, object, SchemaOf } from 'yup';
+
+import { r2a } from '@/react-tools/react2angular';
+
+import { FormControl } from '@@/form-components/FormControl';
+import { Select } from '@@/form-components/Input';
+
+import { Options, useIntervalOptions } from './useIntervalOptions';
+
+export const EDGE_ASYNC_INTERVAL_USE_DEFAULT = -1;
+
+export interface EdgeAsyncIntervalsValues {
+ PingInterval: number;
+ SnapshotInterval: number;
+ CommandInterval: number;
+}
+
+export const options: Options = [
+ { label: 'Use default interval', value: -1, isDefault: true },
+ {
+ value: 0,
+ label: 'disabled',
+ },
+ {
+ value: 60,
+ label: '1 minute',
+ },
+ {
+ value: 60 * 60,
+ label: '1 hour',
+ },
+ {
+ value: 24 * 60 * 60,
+ label: '1 day',
+ },
+ {
+ value: 7 * 24 * 60 * 60,
+ label: '1 week',
+ },
+];
+
+const defaultFieldSettings = {
+ ping: {
+ label: 'Ping interval',
+ tooltip:
+ 'Interval used by this Edge agent to check in with the Portainer instance',
+ },
+ snapshot: {
+ label: 'Snapshot interval',
+ tooltip: 'Interval used by this Edge agent to snapshot the agent state',
+ },
+ command: {
+ label: 'Command interval',
+ tooltip:
+ 'Interval used by this Edge agent to fetch commands from the Portainer instance',
+ },
+};
+
+interface Props {
+ values: EdgeAsyncIntervalsValues;
+ isDefaultHidden?: boolean;
+ readonly?: boolean;
+ fieldSettings?: typeof defaultFieldSettings;
+ onChange(value: EdgeAsyncIntervalsValues): void;
+}
+
+export function EdgeAsyncIntervalsForm({
+ onChange,
+ values,
+ isDefaultHidden = false,
+ readonly = false,
+ fieldSettings = defaultFieldSettings,
+}: Props) {
+ const pingIntervalOptions = useIntervalOptions(
+ 'Edge.PingInterval',
+ options,
+ isDefaultHidden
+ );
+
+ const snapshotIntervalOptions = useIntervalOptions(
+ 'Edge.SnapshotInterval',
+ options,
+ isDefaultHidden
+ );
+
+ const commandIntervalOptions = useIntervalOptions(
+ 'Edge.CommandInterval',
+ options,
+ isDefaultHidden
+ );
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+
+ function handleChange(e: React.ChangeEvent) {
+ onChange({ ...values, [e.target.name]: parseInt(e.target.value, 10) });
+ }
+}
+
+const intervals = options.map((option) => option.value);
+
+export function edgeAsyncIntervalsValidation(): SchemaOf {
+ return object({
+ PingInterval: number().required('This field is required.').oneOf(intervals),
+ SnapshotInterval: number()
+ .required('This field is required.')
+ .oneOf(intervals),
+ CommandInterval: number()
+ .required('This field is required.')
+ .oneOf(intervals),
+ });
+}
+
+export const EdgeAsyncIntervalsFormAngular = r2a(EdgeAsyncIntervalsForm, [
+ 'values',
+ 'onChange',
+ 'isDefaultHidden',
+ 'readonly',
+ 'fieldSettings',
+]);
diff --git a/app/edge/components/EdgeCheckInIntervalField.tsx b/app/edge/components/EdgeCheckInIntervalField.tsx
index 43f133dcf..f8b6e85ff 100644
--- a/app/edge/components/EdgeCheckInIntervalField.tsx
+++ b/app/edge/components/EdgeCheckInIntervalField.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
-import { useSettings } from '@/portainer/settings/queries';
import { r2a } from '@/react-tools/react2angular';
+import { useSettings } from '@/react/portainer/settings/queries';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { FormControl } from '@@/form-components/FormControl';
diff --git a/app/edge/components/useIntervalOptions.ts b/app/edge/components/useIntervalOptions.ts
new file mode 100644
index 000000000..8d2a9dc5e
--- /dev/null
+++ b/app/edge/components/useIntervalOptions.ts
@@ -0,0 +1,67 @@
+import _ from 'lodash';
+import { useState, useEffect } from 'react';
+
+import { useSettings } from '@/react/portainer/settings/queries';
+
+type Option = {
+ label: string;
+ value: number;
+};
+
+type DefaultOption = Option & { isDefault: true };
+
+export type Options = [DefaultOption, ...Option[]];
+
+export function useIntervalOptions(
+ fieldName:
+ | 'Edge.PingInterval'
+ | 'Edge.SnapshotInterval'
+ | 'Edge.CommandInterval'
+ | 'EdgeAgentCheckinInterval',
+ initialOptions: Options,
+ isDefaultHidden: boolean
+) {
+ const [{ value: defaultValue }] = initialOptions;
+ const [options, setOptions] = useState