mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 05:45:22 +02:00
refactor(edge/groups): migrate view to react [EE-2219] (#11758)
Some checks failed
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:s390x platform:linux version:]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled
Some checks failed
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:s390x platform:linux version:]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled
This commit is contained in:
parent
b7cde35c3d
commit
9c70a43ac3
39 changed files with 579 additions and 386 deletions
|
@ -1,16 +1,21 @@
|
|||
import { EdgeTypes, EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
import { FormError } from '@@/form-components/FormError';
|
||||
import { ArrayError } from '@@/form-components/InputList/InputList';
|
||||
|
||||
import { EdgeGroupAssociationTable } from './EdgeGroupAssociationTable';
|
||||
|
||||
export function AssociatedEdgeEnvironmentsSelector({
|
||||
onChange,
|
||||
value,
|
||||
error,
|
||||
}: {
|
||||
onChange: (
|
||||
value: EnvironmentId[],
|
||||
meta: { type: 'add' | 'remove'; value: EnvironmentId }
|
||||
) => void;
|
||||
value: EnvironmentId[];
|
||||
error?: ArrayError<Array<EnvironmentId>>;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
|
@ -20,6 +25,14 @@ export function AssociatedEdgeEnvironmentsSelector({
|
|||
environment entry to move it from one table to the other.
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="col-sm-12">
|
||||
<FormError>
|
||||
{typeof error === 'string' ? error : error.join(', ')}
|
||||
</FormError>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="col-sm-12 mt-4">
|
||||
<div className="flex">
|
||||
<div className="w-1/2">
|
||||
|
|
|
@ -2,15 +2,15 @@ import { createColumnHelper } from '@tanstack/react-table';
|
|||
import { truncate } from 'lodash';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { useTags } from '@/portainer/tags/queries';
|
||||
import { useGroups } from '@/react/portainer/environments/environment-groups/queries';
|
||||
import { EnvironmentsQueryParams } from '@/react/portainer/environments/environment.service';
|
||||
import { useEnvironmentList } from '@/react/portainer/environments/queries';
|
||||
import { Environment } from '@/react/portainer/environments/types';
|
||||
import { useGroups } from '@/react/portainer/environments/environment-groups/queries';
|
||||
import { useTags } from '@/portainer/tags/queries';
|
||||
import { EnvironmentsQueryParams } from '@/react/portainer/environments/environment.service';
|
||||
import { AutomationTestingProps } from '@/types';
|
||||
|
||||
import { useTableStateWithoutStorage } from '@@/datatables/useTableState';
|
||||
import { Datatable, TableRow } from '@@/datatables';
|
||||
import { useTableStateWithoutStorage } from '@@/datatables/useTableState';
|
||||
|
||||
type DecoratedEnvironment = Environment & {
|
||||
Tags: string[];
|
||||
|
@ -41,12 +41,12 @@ const columns = [
|
|||
export function EdgeGroupAssociationTable({
|
||||
title,
|
||||
query,
|
||||
onClickRow,
|
||||
onClickRow = () => {},
|
||||
'data-cy': dataCy,
|
||||
}: {
|
||||
title: string;
|
||||
query: EnvironmentsQueryParams;
|
||||
onClickRow: (env: Environment) => void;
|
||||
onClickRow?: (env: Environment) => void;
|
||||
} & AutomationTestingProps) {
|
||||
const tableState = useTableStateWithoutStorage('Name');
|
||||
const [page, setPage] = useState(0);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
import { useCreateGroupMutation } from '@/react/edge/edge-groups/queries/useCreateEdgeGroupMutation';
|
||||
import { useCreateEdgeGroupMutation } from '@/react/edge/edge-groups/queries/useCreateEdgeGroupMutation';
|
||||
import { useEdgeGroups } from '@/react/edge/edge-groups/queries/useEdgeGroups';
|
||||
|
||||
import { CreatableSelector } from './CreatableSelector';
|
||||
|
||||
export function EdgeGroupsSelector() {
|
||||
const createMutation = useCreateGroupMutation();
|
||||
const createMutation = useCreateEdgeGroupMutation();
|
||||
|
||||
const edgeGroupsQuery = useEdgeGroups({
|
||||
select: (edgeGroups) =>
|
||||
|
|
55
app/react/edge/edge-groups/CreateView/CreateView.tsx
Normal file
55
app/react/edge/edge-groups/CreateView/CreateView.tsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { useRouter } from '@uirouter/react';
|
||||
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
import { Widget } from '@@/Widget';
|
||||
|
||||
import { useCreateEdgeGroupMutation } from '../queries/useCreateEdgeGroupMutation';
|
||||
import { EdgeGroupForm } from '../components/EdgeGroupForm/EdgeGroupForm';
|
||||
|
||||
export function CreateView() {
|
||||
const mutation = useCreateEdgeGroupMutation();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
title="Create edge group"
|
||||
breadcrumbs={[
|
||||
{ label: 'Edge groups', link: 'edge.groups' },
|
||||
'Add edge group',
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<Widget>
|
||||
<Widget.Body>
|
||||
<EdgeGroupForm
|
||||
onSubmit={({ environmentIds, ...values }) => {
|
||||
mutation.mutate(
|
||||
{
|
||||
endpoints: environmentIds,
|
||||
...values,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
notifySuccess(
|
||||
'Success',
|
||||
'Edge group successfully created'
|
||||
);
|
||||
router.stateService.go('^');
|
||||
},
|
||||
}
|
||||
);
|
||||
}}
|
||||
isLoading={mutation.isLoading}
|
||||
/>
|
||||
</Widget.Body>
|
||||
</Widget>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
72
app/react/edge/edge-groups/ItemView/ItemView.tsx
Normal file
72
app/react/edge/edge-groups/ItemView/ItemView.tsx
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { useCurrentStateAndParams, useRouter } from '@uirouter/react';
|
||||
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
import { Widget } from '@@/Widget';
|
||||
import { Redirect } from '@@/Redirect';
|
||||
|
||||
import { useUpdateEdgeGroupMutation } from '../queries/useUpdateEdgeGroupMutation';
|
||||
import { EdgeGroupForm } from '../components/EdgeGroupForm/EdgeGroupForm';
|
||||
import { useEdgeGroup } from '../queries/useEdgeGroup';
|
||||
|
||||
export function ItemView() {
|
||||
const {
|
||||
params: { groupId: id },
|
||||
} = useCurrentStateAndParams();
|
||||
const groupQuery = useEdgeGroup(id);
|
||||
const mutation = useUpdateEdgeGroupMutation();
|
||||
const router = useRouter();
|
||||
|
||||
if (groupQuery.isError) {
|
||||
return <Redirect to="edge.groups" />;
|
||||
}
|
||||
|
||||
if (!groupQuery.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const group = groupQuery.data;
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
title="Edit edge group"
|
||||
breadcrumbs={[
|
||||
{ label: 'Edge groups', link: 'edge.groups' },
|
||||
group.Name,
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<Widget>
|
||||
<Widget.Body>
|
||||
<EdgeGroupForm
|
||||
group={group}
|
||||
onSubmit={({ environmentIds, ...values }) => {
|
||||
mutation.mutate(
|
||||
{
|
||||
id,
|
||||
endpoints: environmentIds,
|
||||
...values,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
notifySuccess(
|
||||
'Success',
|
||||
'Edge group successfully updated'
|
||||
);
|
||||
router.stateService.go('^');
|
||||
},
|
||||
}
|
||||
);
|
||||
}}
|
||||
isLoading={mutation.isLoading}
|
||||
/>
|
||||
</Widget.Body>
|
||||
</Widget>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import { useFormikContext } from 'formik';
|
||||
|
||||
import { EdgeGroupAssociationTable } from '@/react/edge/components/EdgeGroupAssociationTable';
|
||||
import { EdgeTypes } from '@/react/portainer/environments/types';
|
||||
|
||||
import { BoxSelector } from '@@/BoxSelector';
|
||||
import { TagSelector } from '@@/TagSelector';
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
|
||||
import { tagOptions } from './tag-options';
|
||||
import { FormValues } from './types';
|
||||
|
||||
export function DynamicGroupFieldset() {
|
||||
const { values, setFieldValue, errors } = useFormikContext<FormValues>();
|
||||
return (
|
||||
<>
|
||||
<FormSection title="Tags">
|
||||
<BoxSelector
|
||||
slim
|
||||
value={values.partialMatch}
|
||||
onChange={(partialMatch) =>
|
||||
setFieldValue('partialMatch', partialMatch)
|
||||
}
|
||||
options={tagOptions}
|
||||
radioName="partialMatch"
|
||||
/>
|
||||
<TagSelector
|
||||
value={values.tagIds}
|
||||
onChange={(tagIds) => setFieldValue('tagIds', tagIds)}
|
||||
errors={errors.tagIds}
|
||||
/>
|
||||
</FormSection>
|
||||
|
||||
<EdgeGroupAssociationTable
|
||||
data-cy="edgeGroupCreate-associatedEnvironmentsTable"
|
||||
title="Associated environments by tags"
|
||||
query={{
|
||||
types: EdgeTypes,
|
||||
tagIds: values.tagIds,
|
||||
tagsPartialMatch: values.partialMatch,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
import { Form, Formik, useFormikContext } from 'formik';
|
||||
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
import { BoxSelector } from '@@/BoxSelector';
|
||||
import { FormActions } from '@@/form-components/FormActions';
|
||||
|
||||
import { EdgeGroup } from '../../types';
|
||||
|
||||
import { groupTypeOptions } from './group-type-options';
|
||||
import { FormValues } from './types';
|
||||
import { useValidation } from './useValidation';
|
||||
import { DynamicGroupFieldset } from './DynamicGroupFieldset';
|
||||
import { StaticGroupFieldset } from './StaticGroupFieldset';
|
||||
import { NameField } from './NameField';
|
||||
|
||||
export function EdgeGroupForm({
|
||||
onSubmit,
|
||||
isLoading,
|
||||
group,
|
||||
}: {
|
||||
onSubmit: (values: FormValues) => void;
|
||||
isLoading: boolean;
|
||||
group?: EdgeGroup;
|
||||
}) {
|
||||
const validation = useValidation({ id: group?.Id });
|
||||
return (
|
||||
<Formik
|
||||
validationSchema={validation}
|
||||
validateOnMount
|
||||
initialValues={
|
||||
group
|
||||
? {
|
||||
dynamic: group.Dynamic,
|
||||
environmentIds: group.Endpoints,
|
||||
name: group.Name,
|
||||
partialMatch: group.PartialMatch,
|
||||
tagIds: group.TagIds,
|
||||
}
|
||||
: {
|
||||
name: '',
|
||||
dynamic: false,
|
||||
environmentIds: [],
|
||||
partialMatch: false,
|
||||
tagIds: [],
|
||||
}
|
||||
}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<InnerForm isLoading={isLoading} isCreate={!group} />
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
||||
function InnerForm({
|
||||
isLoading,
|
||||
isCreate,
|
||||
}: {
|
||||
isLoading: boolean;
|
||||
isCreate: boolean;
|
||||
}) {
|
||||
const { values, setFieldValue, isValid, errors } =
|
||||
useFormikContext<FormValues>();
|
||||
|
||||
return (
|
||||
<Form className="form-horizontal">
|
||||
<NameField errors={errors.name} />
|
||||
|
||||
<FormSection title="Group type">
|
||||
<BoxSelector
|
||||
slim
|
||||
value={values.dynamic}
|
||||
onChange={(dynamic) => setFieldValue('dynamic', dynamic)}
|
||||
options={groupTypeOptions}
|
||||
radioName="groupTypeDynamic"
|
||||
/>
|
||||
</FormSection>
|
||||
|
||||
{values.dynamic ? <DynamicGroupFieldset /> : <StaticGroupFieldset />}
|
||||
|
||||
<FormActions
|
||||
submitLabel={isCreate ? 'Add edge group' : 'Save edge group'}
|
||||
isLoading={isLoading}
|
||||
isValid={isValid}
|
||||
data-cy="edgeGroupCreate-addGroupButton"
|
||||
loadingText="In progress..."
|
||||
errors={errors}
|
||||
/>
|
||||
</Form>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import { Field, FormikErrors } from 'formik';
|
||||
import { string } from 'yup';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
|
||||
import { useEdgeGroups } from '../../queries/useEdgeGroups';
|
||||
import { EdgeGroup } from '../../types';
|
||||
|
||||
export function NameField({ errors }: { errors?: FormikErrors<string> }) {
|
||||
return (
|
||||
<FormControl label="Name" required errors={errors} inputId="group_name">
|
||||
<Field
|
||||
as={Input}
|
||||
name="name"
|
||||
placeholder="e.g. mygroup"
|
||||
data-cy="edgeGroupCreate-groupNameInput"
|
||||
id="group_name"
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
|
||||
export function useNameValidation(id?: EdgeGroup['Id']) {
|
||||
const edgeGroupsQuery = useEdgeGroups();
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
string()
|
||||
.required('Name is required')
|
||||
.test({
|
||||
name: 'is-unique',
|
||||
test: (value) =>
|
||||
!edgeGroupsQuery.data?.find(
|
||||
(group) => group.Name === value && group.Id !== id
|
||||
),
|
||||
message: 'Name must be unique',
|
||||
}),
|
||||
[edgeGroupsQuery.data, id]
|
||||
);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import { useFormikContext } from 'formik';
|
||||
|
||||
import { AssociatedEdgeEnvironmentsSelector } from '@/react/edge/components/AssociatedEdgeEnvironmentsSelector';
|
||||
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
import { confirmDestructive } from '@@/modals/confirm';
|
||||
import { buildConfirmButton } from '@@/modals/utils';
|
||||
|
||||
import { FormValues } from './types';
|
||||
|
||||
export function StaticGroupFieldset({ isEdit }: { isEdit?: boolean }) {
|
||||
const { values, setFieldValue, errors } = useFormikContext<FormValues>();
|
||||
|
||||
return (
|
||||
<FormSection title="Associated environments">
|
||||
<div className="form-group">
|
||||
<AssociatedEdgeEnvironmentsSelector
|
||||
value={values.environmentIds}
|
||||
error={errors.environmentIds}
|
||||
onChange={async (environmentIds, meta) => {
|
||||
if (meta.type === 'remove' && isEdit) {
|
||||
const confirmed = await confirmDestructive({
|
||||
title: 'Confirm action',
|
||||
message:
|
||||
'Removing the environment from this group will remove its corresponding edge stacks',
|
||||
confirmButton: buildConfirmButton('Confirm'),
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setFieldValue('environmentIds', environmentIds);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { TagId } from '@/portainer/tags/types';
|
||||
|
||||
export interface FormValues {
|
||||
name: string;
|
||||
dynamic: boolean;
|
||||
environmentIds: EnvironmentId[];
|
||||
partialMatch: boolean;
|
||||
tagIds: TagId[];
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { SchemaOf, array, boolean, number, object } from 'yup';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { EdgeGroup } from '../../types';
|
||||
|
||||
import { FormValues } from './types';
|
||||
import { useNameValidation } from './NameField';
|
||||
|
||||
export function useValidation({
|
||||
id,
|
||||
}: { id?: EdgeGroup['Id'] } = {}): SchemaOf<FormValues> {
|
||||
const nameValidation = useNameValidation(id);
|
||||
return useMemo(
|
||||
() =>
|
||||
object({
|
||||
name: nameValidation,
|
||||
dynamic: boolean().default(false),
|
||||
environmentIds: array(number().required()),
|
||||
partialMatch: boolean().default(false),
|
||||
tagIds: array(number().required()).when('dynamic', {
|
||||
is: true,
|
||||
then: (schema) => schema.min(1, 'Tags are required'),
|
||||
}),
|
||||
}),
|
||||
[nameValidation]
|
||||
);
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export const queryKeys = {
|
||||
base: () => ['edge', 'groups'] as const,
|
||||
item: (id: number) => [...queryKeys.base(), id] as const,
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ export async function createEdgeGroup(requestPayload: CreateGroupPayload) {
|
|||
}
|
||||
}
|
||||
|
||||
export function useCreateGroupMutation() {
|
||||
export function useCreateEdgeGroupMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
|
|
47
app/react/edge/edge-groups/queries/useEdgeGroup.ts
Normal file
47
app/react/edge/edge-groups/queries/useEdgeGroup.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import {
|
||||
EnvironmentId,
|
||||
EnvironmentType,
|
||||
} from '@/react/portainer/environments/types';
|
||||
import { withError } from '@/react-tools/react-query';
|
||||
|
||||
import { EdgeGroup } from '../types';
|
||||
|
||||
import { queryKeys } from './query-keys';
|
||||
import { buildUrl } from './build-url';
|
||||
|
||||
export interface EdgeGroupListItemResponse extends EdgeGroup {
|
||||
EndpointTypes: Array<EnvironmentType>;
|
||||
HasEdgeStack?: boolean;
|
||||
HasEdgeJob?: boolean;
|
||||
HasEdgeConfig?: boolean;
|
||||
TrustedEndpoints: Array<EnvironmentId>;
|
||||
}
|
||||
|
||||
async function getEdgeGroup(id: EdgeGroup['Id']) {
|
||||
try {
|
||||
const { data } = await axios.get<EdgeGroup>(buildUrl({ id }));
|
||||
return data;
|
||||
} catch (err) {
|
||||
throw parseAxiosError(err as Error, 'Failed fetching edge groups');
|
||||
}
|
||||
}
|
||||
|
||||
export function useEdgeGroup<T = EdgeGroup>(
|
||||
id?: EdgeGroup['Id'],
|
||||
{
|
||||
select,
|
||||
}: {
|
||||
select?: (groups: EdgeGroup) => T;
|
||||
} = {}
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: queryKeys.item(id!),
|
||||
queryFn: () => getEdgeGroup(id!),
|
||||
select,
|
||||
enabled: !!id,
|
||||
...withError('Failed fetching edge group'),
|
||||
});
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { TagId } from '@/portainer/tags/types';
|
||||
import {
|
||||
mutationOptions,
|
||||
withError,
|
||||
withInvalidate,
|
||||
} from '@/react-tools/react-query';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
import { EdgeGroup } from '../types';
|
||||
|
||||
import { buildUrl } from './build-url';
|
||||
import { queryKeys } from './query-keys';
|
||||
|
||||
interface UpdateGroupPayload {
|
||||
id: EdgeGroup['Id'];
|
||||
name: string;
|
||||
dynamic: boolean;
|
||||
tagIds?: TagId[];
|
||||
endpoints?: EnvironmentId[];
|
||||
partialMatch?: boolean;
|
||||
}
|
||||
|
||||
export async function updateEdgeGroup({
|
||||
id,
|
||||
...requestPayload
|
||||
}: UpdateGroupPayload) {
|
||||
try {
|
||||
const { data: group } = await axios.put<EdgeGroup>(
|
||||
buildUrl({ id }),
|
||||
requestPayload
|
||||
);
|
||||
return group;
|
||||
} catch (e) {
|
||||
throw parseAxiosError(e as Error, 'Failed to update Edge group');
|
||||
}
|
||||
}
|
||||
|
||||
export function useUpdateEdgeGroupMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
updateEdgeGroup,
|
||||
mutationOptions(
|
||||
withError('Failed to update Edge group'),
|
||||
withInvalidate(queryClient, [queryKeys.base()])
|
||||
)
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue