refactor: update presets UI to follow same rules as other pages.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
c9534bdf11
commit
35f38d7cee
8 changed files with 147 additions and 37 deletions
4
API.md
4
API.md
|
|
@ -1777,6 +1777,7 @@ Binary image data with appropriate headers
|
||||||
- `per_page` (optional): Items per page. Default: `config.default_pagination`.
|
- `per_page` (optional): Items per page. Default: `config.default_pagination`.
|
||||||
- `sort` (optional): Comma-separated sort fields. Accepted values: `id`, `name`, `priority`, `default`, `created_at`, `updated_at`. Default: `priority,name`.
|
- `sort` (optional): Comma-separated sort fields. Accepted values: `id`, `name`, `priority`, `default`, `created_at`, `updated_at`. Default: `priority,name`.
|
||||||
- `order` (optional): Comma-separated sort directions matching `sort`, or a single direction applied to every requested sort field. Accepted values: `asc`, `desc`. Default: `desc,asc`.
|
- `order` (optional): Comma-separated sort directions matching `sort`, or a single direction applied to every requested sort field. Accepted values: `asc`, `desc`. Default: `desc,asc`.
|
||||||
|
- `exclude_defaults` (optional): When `true`, excludes system presets from the results. Default: `false`.
|
||||||
|
|
||||||
**Response**:
|
**Response**:
|
||||||
```json
|
```json
|
||||||
|
|
@ -1806,10 +1807,9 @@ Binary image data with appropriate headers
|
||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
- `default: true` indicates this is a system default preset (cannot be modified or deleted)
|
- `default: true` indicates this is a system default preset (cannot be modified or deleted)
|
||||||
- Default ordering remains `priority desc, name asc`
|
|
||||||
|
|
||||||
**Error Responses**:
|
**Error Responses**:
|
||||||
- `400 Bad Request` - Invalid pagination or sorting query parameters
|
- `400 Bad Request` - Invalid data was provided.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,25 +180,32 @@ class PresetsRepository(metaclass=Singleton):
|
||||||
per_page: int,
|
per_page: int,
|
||||||
sort: str | None = None,
|
sort: str | None = None,
|
||||||
order: str | None = None,
|
order: str | None = None,
|
||||||
|
exclude_defaults: bool = False,
|
||||||
) -> tuple[list[PresetModel], int, int, int]:
|
) -> tuple[list[PresetModel], int, int, int]:
|
||||||
order_by = self._build_order_by(sort, order)
|
order_by = self._build_order_by(sort, order)
|
||||||
|
|
||||||
async with self.session() as session:
|
async with self.session() as session:
|
||||||
total: int = await self.count()
|
total: int = await self.count(exclude_defaults=exclude_defaults)
|
||||||
total_pages: int = (total + per_page - 1) // per_page if total > 0 else 1
|
total_pages: int = (total + per_page - 1) // per_page if total > 0 else 1
|
||||||
|
|
||||||
if page > total_pages and total > 0:
|
if page > total_pages and total > 0:
|
||||||
page = total_pages
|
page = total_pages
|
||||||
|
|
||||||
query: Select[tuple[PresetModel]] = (
|
query: Select[tuple[PresetModel]] = select(PresetModel)
|
||||||
select(PresetModel).order_by(*order_by).limit(per_page).offset((page - 1) * per_page)
|
if exclude_defaults:
|
||||||
)
|
query = query.where(PresetModel.default.is_(False))
|
||||||
|
|
||||||
|
query = query.order_by(*order_by).limit(per_page).offset((page - 1) * per_page)
|
||||||
result: Result[tuple[PresetModel]] = await session.execute(query)
|
result: Result[tuple[PresetModel]] = await session.execute(query)
|
||||||
return list(result.scalars().all()), total, page, total_pages
|
return list(result.scalars().all()), total, page, total_pages
|
||||||
|
|
||||||
async def count(self) -> int:
|
async def count(self, exclude_defaults: bool = False) -> int:
|
||||||
async with self.session() as session:
|
async with self.session() as session:
|
||||||
result: Result[tuple[int]] = await session.execute(select(func.count()).select_from(PresetModel))
|
query = select(func.count()).select_from(PresetModel)
|
||||||
|
if exclude_defaults:
|
||||||
|
query = query.where(PresetModel.default.is_(False))
|
||||||
|
|
||||||
|
result: Result[tuple[int]] = await session.execute(query)
|
||||||
return int(result.scalar_one())
|
return int(result.scalar_one())
|
||||||
|
|
||||||
async def get(self, identifier: int | str) -> PresetModel | None:
|
async def get(self, identifier: int | str) -> PresetModel | None:
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,11 @@ async def presets_list(request: Request, encoder: Encoder, repo: PresetsReposito
|
||||||
try:
|
try:
|
||||||
page, per_page = normalize_pagination(request)
|
page, per_page = normalize_pagination(request)
|
||||||
items, total, current_page, total_pages = await repo.list_paginated(
|
items, total, current_page, total_pages = await repo.list_paginated(
|
||||||
page,
|
page=page,
|
||||||
per_page,
|
per_page=per_page,
|
||||||
sort=request.query.get("sort"),
|
sort=request.query.get("sort"),
|
||||||
order=request.query.get("order"),
|
order=request.query.get("order"),
|
||||||
|
exclude_defaults=bool(request.query.get("exclude_defaults", False)),
|
||||||
)
|
)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
return web.json_response(data={"error": str(exc)}, status=web.HTTPBadRequest.status_code)
|
return web.json_response(data={"error": str(exc)}, status=web.HTTPBadRequest.status_code)
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,18 @@ class TestPresetsRepository:
|
||||||
|
|
||||||
assert [item.name for item in items] == ["gamma", "beta", "alpha"], "Should sort by requested field"
|
assert [item.name for item in items] == ["gamma", "beta", "alpha"], "Should sort by requested field"
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_list_paginated_excludes_defaults(self, repo):
|
||||||
|
await repo.create({"name": "System Default", "default": True, "priority": 10})
|
||||||
|
await repo.create({"name": "Custom Preset", "priority": 1})
|
||||||
|
|
||||||
|
items, total, page, total_pages = await repo.list_paginated(page=1, per_page=10, exclude_defaults=True)
|
||||||
|
|
||||||
|
assert [item.name for item in items] == ["custom_preset"], "Should exclude default presets"
|
||||||
|
assert total == 1, "Should count only custom presets"
|
||||||
|
assert page == 1, "Should keep current page when filtered results exist"
|
||||||
|
assert total_pages == 1, "Should compute pages from the filtered total"
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_list_paginated_supports_multiple_sort_fields(self, repo):
|
async def test_list_paginated_supports_multiple_sort_fields(self, repo):
|
||||||
await repo.create({"name": "Charlie", "priority": 2})
|
await repo.create({"name": "Charlie", "priority": 2})
|
||||||
|
|
@ -153,3 +165,17 @@ class TestPresetRoutes:
|
||||||
|
|
||||||
assert response.status == web.HTTPBadRequest.status_code, "Should reject unsupported sort direction"
|
assert response.status == web.HTTPBadRequest.status_code, "Should reject unsupported sort direction"
|
||||||
assert "order" in payload["error"], "Should explain invalid sort direction"
|
assert "order" in payload["error"], "Should explain invalid sort direction"
|
||||||
|
|
||||||
|
async def test_list_route_supports_excluding_defaults(self, repo):
|
||||||
|
await repo.create({"name": "System Default", "default": True, "priority": 10})
|
||||||
|
await repo.create({"name": "Custom Preset", "priority": 1})
|
||||||
|
|
||||||
|
request = MagicMock(spec=Request)
|
||||||
|
request.query = {"page": "1", "per_page": "10", "exclude_defaults": "true"}
|
||||||
|
|
||||||
|
response = await presets_list(request, Encoder(), repo)
|
||||||
|
payload = json.loads(response.text)
|
||||||
|
|
||||||
|
assert response.status == web.HTTPOk.status_code, "Should return 200 for valid default exclusion"
|
||||||
|
assert [item["name"] for item in payload["items"]] == ["custom_preset"], "Should exclude default presets"
|
||||||
|
assert payload["pagination"]["total"] == 1, "Should report filtered total"
|
||||||
|
|
|
||||||
|
|
@ -367,13 +367,12 @@ const props = defineProps<{
|
||||||
reference?: number | null;
|
reference?: number | null;
|
||||||
preset: Partial<Preset>;
|
preset: Partial<Preset>;
|
||||||
addInProgress?: boolean;
|
addInProgress?: boolean;
|
||||||
presets?: Preset[];
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const config = useYtpConfig();
|
const config = useYtpConfig();
|
||||||
const toast = useNotification();
|
const toast = useNotification();
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const { presets, findPreset, selectItems } = usePresetOptions(() => props.presets);
|
const { presets, findPreset, selectItems } = usePresetOptions();
|
||||||
|
|
||||||
const form = reactive<Preset>({
|
const form = reactive<Preset>({
|
||||||
name: '',
|
name: '',
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ const removePreset = (id: number) => {
|
||||||
const loadPresets = async (
|
const loadPresets = async (
|
||||||
page: number = 1,
|
page: number = 1,
|
||||||
perPage: number | undefined = undefined,
|
perPage: number | undefined = undefined,
|
||||||
|
options: { excludeDefaults?: boolean } = {},
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
|
|
@ -136,6 +137,10 @@ const loadPresets = async (
|
||||||
if (perPage !== undefined) {
|
if (perPage !== undefined) {
|
||||||
url += `&per_page=${perPage}`;
|
url += `&per_page=${perPage}`;
|
||||||
}
|
}
|
||||||
|
if (options.excludeDefaults) {
|
||||||
|
url += '&exclude_defaults=true';
|
||||||
|
}
|
||||||
|
|
||||||
const response = await request(url);
|
const response = await request(url);
|
||||||
await ensureSuccess(response);
|
await ensureSuccess(response);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<div class="flex min-w-0 flex-wrap items-center gap-2 xl:justify-end">
|
<div class="flex min-w-0 flex-wrap items-center gap-2 xl:justify-end">
|
||||||
<UButton
|
<UButton
|
||||||
v-if="presetsNoDefault.length > 0"
|
v-if="presets.length > 0"
|
||||||
color="neutral"
|
color="neutral"
|
||||||
:variant="showFilter ? 'soft' : 'outline'"
|
:variant="showFilter ? 'soft' : 'outline'"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -62,13 +62,13 @@
|
||||||
icon="i-lucide-refresh-cw"
|
icon="i-lucide-refresh-cw"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
@click="() => void presetsStore.loadPresets(1, 1000)"
|
@click="() => void loadContent(page)"
|
||||||
>
|
>
|
||||||
<span>Reload</span>
|
<span>Reload</span>
|
||||||
</UButton>
|
</UButton>
|
||||||
|
|
||||||
<UInput
|
<UInput
|
||||||
v-if="showFilter && presetsNoDefault.length > 0"
|
v-if="showFilter && presets.length > 0"
|
||||||
id="filter"
|
id="filter"
|
||||||
ref="filterInput"
|
ref="filterInput"
|
||||||
v-model="query"
|
v-model="query"
|
||||||
|
|
@ -112,6 +112,18 @@
|
||||||
</UButton>
|
</UButton>
|
||||||
</UDropdownMenu>
|
</UDropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<UPagination
|
||||||
|
v-if="paging?.total_pages > 1"
|
||||||
|
:page="paging.page"
|
||||||
|
:total="paging.total"
|
||||||
|
:items-per-page="paging.per_page"
|
||||||
|
:disabled="isLoading"
|
||||||
|
show-edges
|
||||||
|
:sibling-count="0"
|
||||||
|
@update:page="loadContent"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -416,6 +428,22 @@
|
||||||
description="There are no custom defined presets."
|
description="There are no custom defined presets."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="filteredPresets.length > 0 && !query && paging?.total_pages > 1"
|
||||||
|
class="flex justify-end"
|
||||||
|
>
|
||||||
|
<UPagination
|
||||||
|
:page="paging.page"
|
||||||
|
:total="paging.total"
|
||||||
|
:items-per-page="paging.per_page"
|
||||||
|
:disabled="isLoading"
|
||||||
|
show-edges
|
||||||
|
:sibling-count="0"
|
||||||
|
@update:page="loadContent"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<UAlert v-if="!query && presets.length > 0" color="info" variant="soft">
|
<UAlert v-if="!query && presets.length > 0" color="info" variant="soft">
|
||||||
<template #description>
|
<template #description>
|
||||||
<ul class="list-disc space-y-2 pl-5 text-sm text-default">
|
<ul class="list-disc space-y-2 pl-5 text-sm text-default">
|
||||||
|
|
@ -443,7 +471,6 @@
|
||||||
:addInProgress="editor.addInProgress.value"
|
:addInProgress="editor.addInProgress.value"
|
||||||
:reference="editor.reference.value"
|
:reference="editor.reference.value"
|
||||||
:preset="editor.preset.value"
|
:preset="editor.preset.value"
|
||||||
:presets="presets"
|
|
||||||
@cancel="() => void editor.requestClose()"
|
@cancel="() => void editor.requestClose()"
|
||||||
@dirty-change="(dirty) => (editor.dirty.value = dirty)"
|
@dirty-change="(dirty) => (editor.dirty.value = dirty)"
|
||||||
@submit="editor.submit"
|
@submit="editor.submit"
|
||||||
|
|
@ -470,6 +497,8 @@ const config = useYtpConfig();
|
||||||
const box = useConfirm();
|
const box = useConfirm();
|
||||||
const editor = usePresetEditor();
|
const editor = usePresetEditor();
|
||||||
const pageShell = requirePageShell('presets');
|
const pageShell = requirePageShell('presets');
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const { confirmDialog } = useDialog();
|
const { confirmDialog } = useDialog();
|
||||||
const { toggleExpand, expandClass } = useExpandableMeta();
|
const { toggleExpand, expandClass } = useExpandableMeta();
|
||||||
|
|
||||||
|
|
@ -481,21 +510,19 @@ const showFilter = ref(false);
|
||||||
const filterInput = ref<{ inputRef?: { value?: HTMLInputElement | null } } | null>(null);
|
const filterInput = ref<{ inputRef?: { value?: HTMLInputElement | null } } | null>(null);
|
||||||
const selectedIds = ref<number[]>([]);
|
const selectedIds = ref<number[]>([]);
|
||||||
const massDelete = ref(false);
|
const massDelete = ref(false);
|
||||||
|
const page = ref<number>(route.query.page ? parseInt(route.query.page as string, 10) : 1);
|
||||||
|
|
||||||
const presets = computed(() => presetsStore.presets.value as PresetWithUI[]);
|
const presets = computed(() => presetsStore.presets.value as PresetWithUI[]);
|
||||||
|
const paging = presetsStore.pagination;
|
||||||
const isLoading = presetsStore.isLoading;
|
const isLoading = presetsStore.isLoading;
|
||||||
|
|
||||||
const presetsNoDefault = computed(() => presets.value.filter((item) => !item.default));
|
|
||||||
|
|
||||||
const filteredPresets = computed<PresetWithUI[]>(() => {
|
const filteredPresets = computed<PresetWithUI[]>(() => {
|
||||||
const normalizedQuery = query.value?.toLowerCase();
|
const normalizedQuery = query.value?.toLowerCase();
|
||||||
if (!normalizedQuery) {
|
if (!normalizedQuery) {
|
||||||
return presetsNoDefault.value;
|
return presets.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return presetsNoDefault.value.filter((item) =>
|
return presets.value.filter((item) => deepIncludes(item, normalizedQuery, new WeakSet()));
|
||||||
deepIncludes(item, normalizedQuery, new WeakSet()),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectablePresetIds = computed(() =>
|
const selectablePresetIds = computed(() =>
|
||||||
|
|
@ -525,6 +552,19 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const syncPageQuery = async (pageNumber: number): Promise<void> => {
|
||||||
|
const totalPages = paging.value.total_pages;
|
||||||
|
const nextQuery = { ...route.query };
|
||||||
|
|
||||||
|
if (totalPages > 1) {
|
||||||
|
nextQuery.page = String(pageNumber);
|
||||||
|
} else {
|
||||||
|
delete nextQuery.page;
|
||||||
|
}
|
||||||
|
|
||||||
|
await router.replace({ query: nextQuery });
|
||||||
|
};
|
||||||
|
|
||||||
watch(showFilter, (value) => {
|
watch(showFilter, (value) => {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
query.value = '';
|
query.value = '';
|
||||||
|
|
@ -553,6 +593,13 @@ const toggleFilterPanel = async (): Promise<void> => {
|
||||||
filterInput.value?.inputRef?.value?.focus?.({ preventScroll: true });
|
filterInput.value?.inputRef?.value?.focus?.({ preventScroll: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadContent = async (pageNumber = 1): Promise<void> => {
|
||||||
|
page.value = pageNumber;
|
||||||
|
await presetsStore.loadPresets(pageNumber, undefined, { excludeDefaults: true });
|
||||||
|
await nextTick();
|
||||||
|
await syncPageQuery(pageNumber);
|
||||||
|
};
|
||||||
|
|
||||||
const toggleMasterSelection = (): void => {
|
const toggleMasterSelection = (): void => {
|
||||||
if (allSelected.value) {
|
if (allSelected.value) {
|
||||||
selectedIds.value = [];
|
selectedIds.value = [];
|
||||||
|
|
@ -596,15 +643,20 @@ const deleteSelected = async (): Promise<void> => {
|
||||||
|
|
||||||
massDelete.value = true;
|
massDelete.value = true;
|
||||||
|
|
||||||
for (const item of itemsToDelete) {
|
try {
|
||||||
if (!item.id) {
|
for (const item of itemsToDelete) {
|
||||||
continue;
|
if (!item.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await presetsStore.deletePreset(item.id);
|
||||||
}
|
}
|
||||||
await presetsStore.deletePreset(item.id);
|
} finally {
|
||||||
|
selectedIds.value = [];
|
||||||
|
massDelete.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedIds.value = [];
|
await loadContent(page.value);
|
||||||
massDelete.value = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteItem = async (item: Preset): Promise<void> => {
|
const deleteItem = async (item: Preset): Promise<void> => {
|
||||||
|
|
@ -640,5 +692,5 @@ const calcPath = (path?: string): string => {
|
||||||
return path ? location + '/' + sTrim(path, '/') : location;
|
return path ? location + '/' + sTrim(path, '/') : location;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => await presetsStore.loadPresets(1, 1000));
|
onMounted(async () => await loadContent(page.value));
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,26 @@ describe('usePresets', () => {
|
||||||
requestSpy.mockRestore()
|
requestSpy.mockRestore()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('requests custom presets without defaults when asked', async () => {
|
||||||
|
const requestSpy = spyOn(utils, 'request')
|
||||||
|
requestSpy.mockResolvedValueOnce(
|
||||||
|
createMockResponse({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
jsonData: {
|
||||||
|
items: [mockPreset],
|
||||||
|
pagination: mockPagination,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const presets = usePresets()
|
||||||
|
await presets.loadPresets(2, 25, { excludeDefaults: true })
|
||||||
|
|
||||||
|
expect(requestSpy).toHaveBeenCalledWith('/api/presets/?page=2&per_page=25&exclude_defaults=true')
|
||||||
|
requestSpy.mockRestore()
|
||||||
|
})
|
||||||
|
|
||||||
it('sorts presets by priority then name', async () => {
|
it('sorts presets by priority then name', async () => {
|
||||||
const items = [
|
const items = [
|
||||||
{ ...mockPreset, id: 1, name: 'B', priority: 2 },
|
{ ...mockPreset, id: 1, name: 'B', priority: 2 },
|
||||||
|
|
@ -127,12 +147,12 @@ describe('usePresets', () => {
|
||||||
await presets.loadPresets()
|
await presets.loadPresets()
|
||||||
|
|
||||||
const sorted = presets.presets.value
|
const sorted = presets.presets.value
|
||||||
expect(sorted[0].priority).toBe(2)
|
expect(sorted[0]!.priority).toBe(2)
|
||||||
expect(sorted[0].name).toBe('A')
|
expect(sorted[0]!.name).toBe('A')
|
||||||
expect(sorted[1].priority).toBe(2)
|
expect(sorted[1]!.priority).toBe(2)
|
||||||
expect(sorted[1].name).toBe('B')
|
expect(sorted[1]!.name).toBe('B')
|
||||||
expect(sorted[2].priority).toBe(1)
|
expect(sorted[2]!.priority).toBe(1)
|
||||||
expect(sorted[2].name).toBe('C')
|
expect(sorted[2]!.name).toBe('C')
|
||||||
requestSpy.mockRestore()
|
requestSpy.mockRestore()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -219,7 +239,7 @@ describe('usePresets', () => {
|
||||||
const presets = usePresets()
|
const presets = usePresets()
|
||||||
await presets.updatePreset(1, { ...mockPreset, default: true })
|
await presets.updatePreset(1, { ...mockPreset, default: true })
|
||||||
|
|
||||||
const requestBody = JSON.parse((requestSpy.mock.calls[0][1] as any).body)
|
const requestBody = JSON.parse((requestSpy.mock.calls[0]![1] as any).body)
|
||||||
expect(requestBody.id).toBeUndefined()
|
expect(requestBody.id).toBeUndefined()
|
||||||
expect(requestBody.default).toBe(false)
|
expect(requestBody.default).toBe(false)
|
||||||
requestSpy.mockRestore()
|
requestSpy.mockRestore()
|
||||||
|
|
@ -257,7 +277,7 @@ describe('usePresets', () => {
|
||||||
const presets = usePresets()
|
const presets = usePresets()
|
||||||
await presets.patchPreset(1, { id: 10, default: true })
|
await presets.patchPreset(1, { id: 10, default: true })
|
||||||
|
|
||||||
const requestBody = JSON.parse((requestSpy.mock.calls[0][1] as any).body)
|
const requestBody = JSON.parse((requestSpy.mock.calls[0]![1] as any).body)
|
||||||
expect(requestBody.id).toBeUndefined()
|
expect(requestBody.id).toBeUndefined()
|
||||||
expect(requestBody.default).toBe(false)
|
expect(requestBody.default).toBe(false)
|
||||||
requestSpy.mockRestore()
|
requestSpy.mockRestore()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue