Skip to content

Commit cf58b95

Browse files
authored
Merge pull request #497 from opendatalab/release
Update package version
2 parents 901ad02 + ee42b16 commit cf58b95

File tree

21 files changed

+224
-151
lines changed

21 files changed

+224
-151
lines changed

.releaserc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
[
1515
"@semantic-release/github",
1616
{
17-
"successComment": false
17+
"successComment": false,
18+
"failTitle": false
1819
}
1920
],
2021
[

apps/frontend/.releaserc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"@semantic-release/github",
2020
{
2121
"assets": [{ "path": "./*.zip", "label": "labelu-frontend-${nextRelease.version}.zip" }],
22-
"successComment": false
22+
"successComment": false,
23+
"failTitle": false
2324
}
2425
],
2526
[

apps/frontend/package.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
22
"name": "@labelu/frontend",
3-
"version": "5.1.0",
3+
"version": "5.2.1",
44
"private": true,
55
"dependencies": {
66
"@ant-design/icons": "^4.6.2",
7-
"@labelu/audio-annotator-react": "1.5.0",
8-
"@labelu/components-react": "1.4.1",
7+
"@labelu/audio-annotator-react": "1.5.2",
8+
"@labelu/components-react": "1.4.2",
99
"@labelu/image": "1.1.0",
1010
"@labelu/formatter": "1.0.2",
11-
"@labelu/image-annotator-react": "2.1.0",
11+
"@labelu/image-annotator-react": "2.1.1",
1212
"@labelu/interface": "1.3.1",
13-
"@labelu/video-annotator-react": "1.3.4-alpha.3",
14-
"@labelu/video-react": "1.3.1",
13+
"@labelu/video-annotator-react": "1.3.4",
14+
"@labelu/video-react": "1.3.3",
1515
"@tanstack/react-query": "^5.0.0",
1616
"antd": "5.10.1",
1717
"axios": "^1.3.4",

apps/frontend/src/hooks/useScrollFetch.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function useScrollFetch<T extends any[] | undefined>(
2323
service: (isReset: boolean) => Promise<T>,
2424
container?: HTMLDivElement | (() => HTMLDivElement | null) | undefined,
2525
options?: Option<T>,
26-
): [T, boolean, Dispatch<SetStateAction<T>>] {
26+
): [T, boolean, Dispatch<SetStateAction<T>>, () => Promise<unknown>] {
2727
const { threshold, afterFetching, isEnd, watch } = {
2828
threshold: 0,
2929
...options,
@@ -122,5 +122,5 @@ export function useScrollFetch<T extends any[] | undefined>(
122122
};
123123
}, [container, handleOnScroll]);
124124

125-
return [data, isLoading, setData];
125+
return [data, isLoading, setData, wrappedService];
126126
}

apps/frontend/src/initialize.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ declare global {
1818
IS_ONLINE: boolean;
1919

2020
AnalyzeWiz: typeof AnalyzeWiz;
21+
22+
__backend: {
23+
version: string;
24+
build_time: string;
25+
name: 'labelu';
26+
commit: string;
27+
};
28+
__frontend: {
29+
version: string;
30+
deps: Record<string, string>;
31+
};
2132
}
2233
}
2334

apps/frontend/src/loaders/task.loader.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { sampleKey, taskKey } from '@/api/queryKeyFactories';
44
import { getTaskList, getTask } from '@/api/services/task';
55
import queryClient from '@/api/queryClient';
66
import { getSamples } from '@/api/services/samples';
7-
import type { SampleListResponse, TaskResponseWithStatics } from '@/api/types';
7+
import type { ListByApiV1TasksTaskIdSamplesGetParams, SampleListResponse, TaskResponseWithStatics } from '@/api/types';
88
import type { ToolsConfigState } from '@/types/toolConfig';
99
import { preAnnotationKey } from '@/api/queryKeyFactories/preAnnotation';
1010
import { getPreAnnotations } from '@/api/services/preAnnotations';
@@ -55,7 +55,12 @@ export async function taskLoader({ params, request }: LoaderFunctionArgs) {
5555
const queryParams = {
5656
task_id: +params.taskId,
5757
...Object.fromEntries(searchParams.entries()),
58-
};
58+
} as ListByApiV1TasksTaskIdSamplesGetParams;
59+
60+
// task page
61+
if (params.taskId && !params.sampleId && !queryParams.pageSize) {
62+
queryParams.pageSize = 10;
63+
}
5964

6065
const sampleQueryKey = sampleKey.list(queryParams);
6166

@@ -67,6 +72,8 @@ export async function taskLoader({ params, request }: LoaderFunctionArgs) {
6772
if (searchParams.get('isNew') !== 'true') {
6873
const preAnnotationQueryKey = preAnnotationKey.list({ task_id: +params.taskId });
6974

75+
delete queryParams.sort;
76+
7077
result.preAnnotations = await queryClient.fetchQuery({
7178
queryKey: preAnnotationQueryKey,
7279
queryFn: () => getPreAnnotations(queryParams),

apps/frontend/src/pages/tasks.[id].samples.[id]/components/annotationRightCorner/index.tsx

+106-76
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ import { message } from '@/StaticAnt';
1818
import AnnotationContext from '../../annotation.context';
1919

2020
interface AnnotationRightCornerProps {
21-
isLastSample: boolean;
22-
isFirstSample: boolean;
2321
// 用于标注预览
2422
noSave?: boolean;
23+
24+
fetchNext?: () => void;
25+
26+
totalSize: number;
2527
}
2628

2729
export const SAMPLE_CHANGED = 'sampleChanged';
@@ -56,7 +58,7 @@ export interface AnnotationLoaderData {
5658
samples: SampleListResponse;
5759
}
5860

59-
const AnnotationRightCorner = ({ isLastSample, isFirstSample, noSave }: AnnotationRightCornerProps) => {
61+
const AnnotationRightCorner = ({ noSave, fetchNext, totalSize }: AnnotationRightCornerProps) => {
6062
const isFetching = useIsFetching();
6163
const isMutating = useIsMutating();
6264
const isGlobalLoading = isFetching > 0 || isMutating > 0;
@@ -67,10 +69,20 @@ const AnnotationRightCorner = ({ isLastSample, isFirstSample, noSave }: Annotati
6769
const sampleId = routeParams.sampleId;
6870
const { samples, setSamples, task } = useContext(AnnotationContext);
6971
const sampleIndex = _.findIndex(samples, (sample: SampleResponse) => sample.id === +sampleId!);
72+
const isLastSample = _.findIndex(samples, { id: +sampleId! }) === samples.length - 1;
73+
const isFirstSample = _.findIndex(samples, { id: +sampleId! }) === 0;
7074
const currentSample = samples[sampleIndex];
7175
const isSampleSkipped = currentSample?.state === SampleState.SKIPPED;
7276
const [searchParams] = useSearchParams();
7377

78+
// 第一次进入就是40的倍数时,获取下一页数据
79+
useEffect(() => {
80+
if (isLastSample && samples.length < totalSize) {
81+
// TODO: fetchNext 调用两次
82+
fetchNext?.();
83+
}
84+
}, [fetchNext, isLastSample, samples.length, totalSize]);
85+
7486
const navigateWithSearch = useCallback(
7587
(to: string) => {
7688
const searchStr = searchParams.toString();
@@ -84,78 +96,6 @@ const AnnotationRightCorner = ({ isLastSample, isFirstSample, noSave }: Annotati
8496
[navigate, searchParams],
8597
);
8698

87-
const handleCancelSkipSample = async () => {
88-
if (noSave) {
89-
return;
90-
}
91-
92-
await updateSampleState(
93-
{
94-
task_id: +taskId!,
95-
sample_id: +sampleId!,
96-
},
97-
{
98-
...currentSample,
99-
state: SampleState.NEW,
100-
},
101-
);
102-
103-
setSamples(
104-
samples.map((sample: SampleResponse) =>
105-
sample.id === +sampleId! ? { ...sample, state: SampleState.NEW } : sample,
106-
),
107-
);
108-
};
109-
110-
const handleSkipSample = async () => {
111-
if (noSave) {
112-
return;
113-
}
114-
115-
await updateSampleState(
116-
{
117-
task_id: +taskId!,
118-
sample_id: +sampleId!,
119-
},
120-
{
121-
...currentSample,
122-
state: SampleState.SKIPPED,
123-
},
124-
);
125-
126-
setSamples(
127-
samples.map((sample: SampleResponse) =>
128-
sample.id === +sampleId! ? { ...sample, state: SampleState.SKIPPED } : sample,
129-
),
130-
);
131-
// 切换到下一个文件
132-
if (!isLastSample) {
133-
navigateWithSearch(`/tasks/${taskId}/samples/${_.get(samples, `[${sampleIndex + 1}].id`)}`);
134-
} else {
135-
navigateWithSearch(`/tasks/${taskId}/samples/finished`);
136-
}
137-
};
138-
139-
useHotkeys(
140-
'ctrl+space, meta+space',
141-
() => {
142-
if (noSave) {
143-
return;
144-
}
145-
146-
if (currentSample.state === SampleState.SKIPPED) {
147-
handleCancelSkipSample();
148-
} else {
149-
handleSkipSample();
150-
}
151-
},
152-
{
153-
keyup: true,
154-
keydown: false,
155-
},
156-
[handleSkipSample, handleCancelSkipSample, currentSample],
157-
);
158-
15999
const saveCurrentSample = useCallback(async () => {
160100
if (currentSample?.state === SampleState.SKIPPED || noSave || !task?.media_type) {
161101
return;
@@ -301,7 +241,66 @@ const AnnotationRightCorner = ({ isLastSample, isFirstSample, noSave }: Annotati
301241
setTimeout(revalidator.revalidate);
302242
}, [saveCurrentSample, navigateWithSearch, taskId, revalidator.revalidate]);
303243

244+
const handleCancelSkipSample = async () => {
245+
if (noSave) {
246+
return;
247+
}
248+
249+
await updateSampleState(
250+
{
251+
task_id: +taskId!,
252+
sample_id: +sampleId!,
253+
},
254+
{
255+
...currentSample,
256+
state: SampleState.NEW,
257+
},
258+
);
259+
260+
setSamples(
261+
samples.map((sample: SampleResponse) =>
262+
sample.id === +sampleId! ? { ...sample, state: SampleState.NEW } : sample,
263+
),
264+
);
265+
};
266+
267+
const handleSkipSample = async () => {
268+
if (noSave) {
269+
return;
270+
}
271+
272+
await updateSampleState(
273+
{
274+
task_id: +taskId!,
275+
sample_id: +sampleId!,
276+
},
277+
{
278+
...currentSample,
279+
state: SampleState.SKIPPED,
280+
},
281+
);
282+
283+
setSamples(
284+
samples.map((sample: SampleResponse) =>
285+
sample.id === +sampleId! ? { ...sample, state: SampleState.SKIPPED } : sample,
286+
),
287+
);
288+
289+
await saveCurrentSample();
290+
// 切换到下一个文件
291+
if (!isLastSample) {
292+
navigateWithSearch(`/tasks/${taskId}/samples/${_.get(samples, `[${sampleIndex + 1}].id`)}`);
293+
} else {
294+
navigateWithSearch(`/tasks/${taskId}/samples/finished`);
295+
}
296+
};
297+
304298
const handleNextSample = useCallback(() => {
299+
// 到达分页边界,触发加载下一页
300+
if (sampleIndex === samples.length - 2 && samples.length < totalSize) {
301+
fetchNext?.();
302+
}
303+
305304
if (noSave) {
306305
navigateWithSearch(`/tasks/${taskId}/samples/${_.get(samples, `[${sampleIndex + 1}].id`)}`);
307306

@@ -315,7 +314,18 @@ const AnnotationRightCorner = ({ isLastSample, isFirstSample, noSave }: Annotati
315314
navigateWithSearch(`/tasks/${taskId}/samples/${_.get(samples, `[${sampleIndex + 1}].id`)}`);
316315
});
317316
}
318-
}, [noSave, isLastSample, navigateWithSearch, taskId, samples, sampleIndex, handleComplete, saveCurrentSample]);
317+
}, [
318+
sampleIndex,
319+
samples,
320+
totalSize,
321+
noSave,
322+
isLastSample,
323+
fetchNext,
324+
navigateWithSearch,
325+
taskId,
326+
handleComplete,
327+
saveCurrentSample,
328+
]);
319329

320330
const handlePrevSample = useCallback(async () => {
321331
if (sampleIndex === 0) {
@@ -344,6 +354,26 @@ const AnnotationRightCorner = ({ isLastSample, isFirstSample, noSave }: Annotati
344354
500,
345355
);
346356

357+
useHotkeys(
358+
'ctrl+space, meta+space',
359+
() => {
360+
if (noSave) {
361+
return;
362+
}
363+
364+
if (currentSample.state === SampleState.SKIPPED) {
365+
handleCancelSkipSample();
366+
} else {
367+
handleSkipSample();
368+
}
369+
},
370+
{
371+
keyup: true,
372+
keydown: false,
373+
},
374+
[handleSkipSample, handleCancelSkipSample, currentSample],
375+
);
376+
347377
useEffect(() => {
348378
document.addEventListener('keydown', onKeyDown);
349379

apps/frontend/src/pages/tasks.[id].samples.[id]/components/sliderCard/index.tsx

+12-10
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,18 @@ const SliderCard = ({ type, cardInfo, index, onClick }: SliderCardProps) => {
5555

5656
if (type === MediaType.VIDEO) {
5757
return (
58-
<VideoCard
59-
src={url!}
60-
title={inner_id}
61-
active={id === sampleId}
62-
onClick={() => handleOnClick(cardInfo)}
63-
showPlayIcon
64-
showDuration
65-
completed={state === 'DONE'}
66-
skipped={state === 'SKIPPED'}
67-
/>
58+
<div style={{ paddingLeft: '1rem', paddingRight: '1rem' }}>
59+
<VideoCard
60+
src={url!}
61+
title={inner_id}
62+
active={id === sampleId}
63+
onClick={() => handleOnClick(cardInfo)}
64+
showPlayIcon
65+
showDuration
66+
completed={state === 'DONE'}
67+
skipped={state === 'SKIPPED'}
68+
/>
69+
</div>
6870
);
6971
}
7072

0 commit comments

Comments
 (0)