Skip to content

Commit

Permalink
Enable target_id filter on the job list API v2
Browse files Browse the repository at this point in the history
  • Loading branch information
syucream committed Jul 21, 2024
1 parent 08cb8d9 commit c3d1a6d
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 10 deletions.
2 changes: 1 addition & 1 deletion apiclient/typescript-fetch/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dmm-com/airone-apiclient-typescript-fetch",
"version": "0.0.18",
"version": "0.0.19",
"description": "AirOne APIv2 client in TypeScript",
"main": "src/autogenerated/index.ts",
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export const topPath = () => basePath;
export const advancedSearchPath = () => basePath + "advanced_search";
export const advancedSearchResultPath = () =>
basePath + "advanced_search_result";
export const jobsPath = () => basePath + "jobs";
export const jobsPath = (targetId?: number) =>
basePath + "jobs" + (targetId ? `?target_id=${targetId}` : "");
export const aclPath = (objectId: number | string) =>
basePath + `acl/${objectId}`;
export const aclHistoryPath = (objectId: number | string) =>
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/components/common/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import AutorenewIcon from "@mui/icons-material/Autorenew";
import { Box, Divider, Tooltip, Typography } from "@mui/material";
import { styled } from "@mui/material/styles";
import React, { FC } from "react";
import { Link } from "react-router-dom";

import { jobsPath } from "Routes";

const Frame = styled(Box)({
width: "100%",
Expand Down Expand Up @@ -41,13 +44,15 @@ const ChildrenBox = styled(Box)({
interface Props {
title: string;
description?: string;
targetId?: number;
hasOngoingProcess?: boolean;
children?: React.ReactNode;
}

export const PageHeader: FC<Props> = ({
title,
description,
targetId,
hasOngoingProcess,
children,
}) => {
Expand All @@ -63,7 +68,9 @@ export const PageHeader: FC<Props> = ({
</Typography>
{hasOngoingProcess && (
<Tooltip title="未処理の変更があります。現在表示されているデータは最新でない可能性があります。">
<AutorenewIcon />
<Box component={Link} to={jobsPath(targetId)}>
<AutorenewIcon />
</Box>
</Tooltip>
)}
<ChildrenBox>{children}</ChildrenBox>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/pages/EntityEditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export const EntityEditPage: FC = () => {
entity?.value != null ? entity.value.name : "新規エンティティの作成"
}
description={entity?.value && "エンティテイティ詳細 / 編集"}
targetId={entity.value?.id}
hasOngoingProcess={entity?.value?.hasOngoingChanges}
>
<SubmitButton
Expand Down
1 change: 1 addition & 0 deletions frontend/src/pages/EntryListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const EntryListPage: FC<Props> = ({ canCreateEntry = true }) => {
<PageHeader
title={entity.value?.name ?? ""}
description="エントリ一覧"
targetId={entity.value?.id}
hasOngoingProcess={entity.value?.hasOngoingChanges}
>
<Box width="50px">
Expand Down
19 changes: 14 additions & 5 deletions frontend/src/pages/JobListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ReplayIcon from "@mui/icons-material/Replay";
import { Box, Button, Container, Typography } from "@mui/material";
import React, { FC } from "react";
import { Link } from "react-router-dom";
import React, { FC, useMemo } from "react";
import { Link, useLocation } from "react-router-dom";
import { useToggle } from "react-use";

import { useAsyncWithThrow } from "../hooks/useAsyncWithThrow";
Expand All @@ -17,13 +17,22 @@ import { aironeApiClient } from "repository/AironeApiClient";
import { JobList as ConstJobList } from "services/Constants";

export const JobListPage: FC = () => {
const [page, changePage] = usePage();
const location = useLocation();

const [page, changePage] = usePage();
const [refresh, toggleRefresh] = useToggle(false);

const { targetId } = useMemo(() => {
const params = new URLSearchParams(location.search);
const targetId = params.get("target_id");
return {
targetId: targetId ? Number(targetId) : undefined,
};
}, [location.search]);

const jobs = useAsyncWithThrow(async () => {
return await aironeApiClient.getJobs(page);
}, [page, refresh]);
return await aironeApiClient.getJobs(page, targetId);
}, [page, targetId, refresh]);

return (
<Box className="container-fluid">
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/repository/AironeApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -918,10 +918,14 @@ class AironeApiClient {
);
}

async getJobs(page = 1): Promise<PaginatedJobSerializersList> {
async getJobs(
page: number = 1,
targetId?: number
): Promise<PaginatedJobSerializersList> {
return await this.job.jobApiV2JobsList({
offset: (page - 1) * JobList.MAX_ROW_COUNT,
limit: JobList.MAX_ROW_COUNT,
targetId,
});
}

Expand Down
6 changes: 5 additions & 1 deletion job/api_v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def download(self, request: Request, *args, **kwargs) -> Response:
@extend_schema(
parameters=[
OpenApiParameter("created_after", OpenApiTypes.DATETIME, OpenApiParameter.QUERY),
OpenApiParameter("target_id", OpenApiTypes.INT, OpenApiParameter.QUERY),
],
)
class JobListAPI(viewsets.ModelViewSet):
Expand All @@ -82,7 +83,8 @@ class JobListAPI(viewsets.ModelViewSet):

def get_queryset(self) -> QuerySet:
user = self.request.user
created_after = self.request.query_params.get("created_after", None)
created_after: str | None = self.request.query_params.get("created_after", None)
target_id: str | None = self.request.query_params.get("target_id", None)

export_operations: list[JobOperation] = [
JobOperation.EXPORT_ENTRY,
Expand All @@ -107,6 +109,8 @@ def get_queryset(self) -> QuerySet:

if created_after:
query &= Q(created_at__gte=created_after)
if target_id:
query &= Q(target=target_id)

return Job.objects.filter(query).select_related("target").order_by("-created_at")

Expand Down
25 changes: 25 additions & 0 deletions job/tests/test_api_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,31 @@ def test_get_recent_job(self):
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.json()["count"], 0)

def test_get_jobs_with_target_id(self):
user = self.guest_login()

entity = Entity.objects.create(name="entity", created_user=user)
entry1 = Entry.objects.create(name="entry1", created_user=user, schema=entity)
entry2 = Entry.objects.create(name="entry2", created_user=user, schema=entity)

# create three jobs for entry1
[Job.new_create(user, entry1) for _ in range(0, _TEST_MAX_LIST_VIEW)]
self.assertEqual(Job.objects.filter(user=user).count(), _TEST_MAX_LIST_VIEW)
# create one job for entry2
Job.new_create(user, entry2)

# checks number of the returned objects are for entry1
resp = self.client.get(
f"/job/api/v2/jobs?limit={_TEST_MAX_LIST_VIEW + 100}&offset=0&target_id={entry1.id}"
)
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.json()["count"], _TEST_MAX_LIST_VIEW)

# checks number of the returned objects are for both entry1 and entry2
resp = self.client.get(f"/job/api/v2/jobs?limit={_TEST_MAX_LIST_VIEW + 100}&offset=0")
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.json()["count"], _TEST_MAX_LIST_VIEW + 1)

def test_get_job(self):
user = self.guest_login()

Expand Down

0 comments on commit c3d1a6d

Please sign in to comment.