Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simple filters for collections #5575

Merged
merged 89 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
bbaa891
Add missing pagination in some endpoints
zhiltsov-max Jan 9, 2023
9542c8d
Update SDK
zhiltsov-max Jan 9, 2023
c498fa5
Update tests
zhiltsov-max Jan 9, 2023
fbcc345
Update changelog
zhiltsov-max Jan 9, 2023
26473e8
Fix formatting
zhiltsov-max Jan 9, 2023
c20991a
Fix changelog
zhiltsov-max Jan 9, 2023
fb2516c
t
zhiltsov-max Jan 10, 2023
d3c4ca7
Merge branch 'zm/add-missing-pagination' into zm/redirect-duplicated-…
zhiltsov-max Jan 10, 2023
3dcf328
Merge branch 'develop' into zm/improve-some-endpoints
nmanovic Jan 10, 2023
3e507bf
Added fetchAll aggregator
bsekachev Jan 11, 2023
c65ac32
Add simple redirects
zhiltsov-max Jan 10, 2023
895aa16
Merge branch 'develop' into zm/improve-some-endpoints
zhiltsov-max Jan 11, 2023
3ca2026
Update test assets
zhiltsov-max Jan 11, 2023
e73cbf6
Merge remote-tracking branch 'origin/zm/improve-some-endpoints' into …
zhiltsov-max Jan 11, 2023
ca7c732
Update UI tests
zhiltsov-max Jan 11, 2023
97bfb9f
t
zhiltsov-max Jan 11, 2023
6d314f6
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 11, 2023
4f6f365
Merge branch 'zm/improve-some-endpoints' into zm/redirect-duplicated-…
zhiltsov-max Jan 11, 2023
af23b06
Implement simple filters support
zhiltsov-max Jan 11, 2023
6689ca2
Simplify implementation
zhiltsov-max Jan 11, 2023
44944e7
Update filtering fields in views
zhiltsov-max Jan 12, 2023
3f0f5d1
Remove extra fields from schema
zhiltsov-max Jan 12, 2023
afba94c
Fix prefetch use
zhiltsov-max Jan 13, 2023
ecbb364
Change string filter to inclusion
zhiltsov-max Jan 13, 2023
7ebab92
Update search fields and add tests
zhiltsov-max Jan 17, 2023
c322136
Refactor some code
zhiltsov-max Jan 17, 2023
92e6a69
Update webhook filters
zhiltsov-max Jan 17, 2023
0815eca
Polish some code
zhiltsov-max Jan 17, 2023
23eabd3
Fix schema errors
zhiltsov-max Jan 17, 2023
fbc52cc
Remove extra parameters from endpoints
zhiltsov-max Jan 17, 2023
0e235b4
Fix redirects and restore extra parameters
zhiltsov-max Jan 18, 2023
49e4b61
Restore permission check behavior
zhiltsov-max Jan 18, 2023
f645f40
Update issue tests
zhiltsov-max Jan 18, 2023
b19e581
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 18, 2023
b58f121
Fix linter problems
zhiltsov-max Jan 18, 2023
0bec884
Update license headers
zhiltsov-max Jan 18, 2023
ecf8dcb
Fix linter warning
zhiltsov-max Jan 18, 2023
ee31c85
Update changelog
zhiltsov-max Jan 18, 2023
f72024d
Fix issue tests
zhiltsov-max Jan 19, 2023
2a24b80
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 19, 2023
073037d
Refactor some code
zhiltsov-max Jan 19, 2023
7fd4e56
Fix merge
zhiltsov-max Jan 19, 2023
f12884e
Fix linter
zhiltsov-max Jan 19, 2023
056e8cc
Implement filters using JsonFilter
zhiltsov-max Jan 20, 2023
403b547
Remove extra import
zhiltsov-max Jan 20, 2023
a2792f2
Fix check
zhiltsov-max Jan 20, 2023
9009179
Fix type description
zhiltsov-max Jan 20, 2023
6b343cf
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 20, 2023
4b79078
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 23, 2023
b014016
Merge remote-tracking branch 'origin/zm/redirect-duplicated-endpoints…
zhiltsov-max Jan 23, 2023
e3aa275
Fix api tests
zhiltsov-max Jan 23, 2023
71f5b20
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 23, 2023
b59e6ea
Revert switching to json filter
zhiltsov-max Jan 23, 2023
03325cb
Fix tests
zhiltsov-max Jan 23, 2023
43795a0
Fix license headers
zhiltsov-max Jan 26, 2023
101a8de
Implement extra fields in serializers, update test data
zhiltsov-max Jan 26, 2023
2484bf9
Refactored previews & projects
bsekachev Jan 27, 2023
31686a7
Fetching jobs workarounded
bsekachev Jan 27, 2023
bf7e420
Fixed code
bsekachev Jan 27, 2023
db797c4
Fixed issue comments
bsekachev Jan 27, 2023
1b806e0
update some tests
zhiltsov-max Jan 27, 2023
94516c3
Fixed comments
bsekachev Jan 27, 2023
ab7e92c
Merge branch 'zm/redirect-duplicated-endpoints' of github.com:opencv/…
bsekachev Jan 27, 2023
9eb136f
Fixed page size
bsekachev Jan 27, 2023
81508b0
Reworked fetching issue comments
bsekachev Jan 27, 2023
f69d708
Simplified sorting
bsekachev Jan 27, 2023
afdf454
Fix tests
zhiltsov-max Jan 30, 2023
fd2311d
Merge remote-tracking branch 'origin/zm/redirect-duplicated-endpoints…
zhiltsov-max Jan 30, 2023
3ba32f3
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 30, 2023
cfcfec5
Fix merge
zhiltsov-max Jan 30, 2023
b489edc
Fix linter issues
zhiltsov-max Jan 30, 2023
2539dc4
Fix test
zhiltsov-max Jan 30, 2023
f7c1cdc
Fix pytorch adapter
zhiltsov-max Jan 30, 2023
c7c6cf7
Update changelog
zhiltsov-max Jan 30, 2023
9efe98d
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Jan 30, 2023
e49b578
Fix test
zhiltsov-max Jan 31, 2023
65d0c0d
Merge remote-tracking branch 'origin/zm/redirect-duplicated-endpoints…
zhiltsov-max Jan 31, 2023
327fc9f
Fix ui problem with jobs
zhiltsov-max Jan 31, 2023
a379b2b
Fix some tests
zhiltsov-max Feb 1, 2023
dfea00d
Fixed jest tests
klakhov Feb 1, 2023
8448c98
fixed getJobs method
klakhov Feb 1, 2023
cfae321
Fixed remaining tests
klakhov Feb 1, 2023
27c5e16
progress count by segments, removed jobs fetching
klakhov Feb 1, 2023
7920f29
added waiting for task load
klakhov Feb 1, 2023
c5d0032
Add new fields to the server schema
zhiltsov-max Feb 1, 2023
48a8810
Merge branch 'develop' into zm/redirect-duplicated-endpoints
zhiltsov-max Feb 1, 2023
24d469a
Merge branch 'develop' into zm/redirect-duplicated-endpoints
nmanovic Feb 1, 2023
00961b4
Merge branch 'develop' into zm/redirect-duplicated-endpoints
nmanovic Feb 2, 2023
7ad2c5e
added additinal checks for opening task job
klakhov Feb 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- YOLO v7 serverless feature added using ONNX backend (<https://github.com/opencv/cvat/pull/5552>)
- Cypress test for social account authentication (<https://github.com/opencv/cvat/pull/5444>)
- Dummy github and google authentication servers (<https://github.com/opencv/cvat/pull/5444>)
- \[Server API\] Simple filters for object collection endpoints
(<https://github.com/opencv/cvat/pull/5575>)

### Changed
- The Docker Compose files now use the Compose Specification version
Expand All @@ -31,18 +33,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
The corresponding arguments are keyword-only now.
(<https://github.com/opencv/cvat/pull/5502>)
- \[Server API\] Added missing pagination or pagination parameters in
`/project/{id}/tasks`, `/tasks/{id}/jobs`, `/jobs/{id}/issues`,
`/jobs/{id}/commits`, `/issues/{id}/comments`, `/organizations`
`/jobs/{id}/commits`, `/organizations`
(<https://github.com/opencv/cvat/pull/5557>)
- Windows Installation Instructions adjusted to work around <https://github.com/nuclio/nuclio/issues/1821>
- The contour detection function for semantic segmentation (<https://github.com/opencv/cvat/pull/4665>)
- Delete newline character when generating a webhook signature (<https://github.com/opencv/cvat/pull/5622>)
- DL models UI (<https://github.com/opencv/cvat/pull/5635>)

### Deprecated
- TDB
- TBD

### Removed
- \[Server API\] Endpoints with collections are removed in favor of their full variants
`/project/{id}/tasks`, `/tasks/{id}/jobs`, `/jobs/{id}/issues`, `/issues/{id}/comments`.
Corresponding fields are added or changed to provide a link to the child collection
in `/projects/{id}`, `/tasks/{id}`, `/jobs/{id}`, `/issues/{id}`
(<https://github.com/opencv/cvat/pull/5575>)
- Limit on the maximum number of manifest files that can be added for cloud storage (<https://github.com/opencv/cvat/pull/5660>)

### Fixed
Expand All @@ -53,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix the type of the credentials parameter of make_client from the Python SDK
- Reduced number of noisy information on ortho views for 3D canvas (<https://github.com/opencv/cvat/pull/5608>)
- Clean up disk space after a project is removed (<https://github.com/opencv/cvat/pull/5632>)
- \[Server API\] Various errors in the generated schema (<https://github.com/opencv/cvat/pull/5575>)
- SiamMask and TransT serverless functions (<https://github.com/opencv/cvat/pull/5658>)

### Security
Expand Down
53 changes: 26 additions & 27 deletions cvat-core/src/api-implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {

import User from './user';
import { AnnotationFormats } from './annotation-formats';
import { ArgumentError } from './exceptions';
import { Task, Job } from './session';
import Project from './project';
import CloudStorage from './cloud-storage';
Expand Down Expand Up @@ -167,8 +166,8 @@ export default function implementAPI(cvat) {
return users;
};

cvat.jobs.get.implementation = async (filter) => {
checkFilter(filter, {
cvat.jobs.get.implementation = async (query) => {
checkFilter(query, {
page: isInteger,
filter: isString,
sort: isString,
Expand All @@ -177,30 +176,24 @@ export default function implementAPI(cvat) {
jobID: isInteger,
});

if ('taskID' in filter && 'jobID' in filter) {
throw new ArgumentError('Filter fields "taskID" and "jobID" are not permitted to be used at the same time');
}

if ('taskID' in filter) {
const [task] = await serverProxy.tasks.get({ id: filter.taskID });
if (task) {
return new Task(task).jobs;
checkExclusiveFields(query, ['jobID', 'taskID', 'filter', 'search'], ['page', 'sort']);
if ('jobID' in query) {
const job = await serverProxy.jobs.get({ id: query.jobID });
if (job) {
return [new Job(job)];
}

return [];
}

if ('jobID' in filter) {
const job = await serverProxy.jobs.get({ id: filter.jobID });
if (job) {
return [new Job(job)];
}
if ('taskID' in query) {
query.filter = JSON.stringify({ and: [{ '==': [{ var: 'task_id' }, query.taskID] }] });
}

const searchParams = {};
for (const key of Object.keys(filter)) {
for (const key of Object.keys(query)) {
if (['page', 'sort', 'search', 'filter'].includes(key)) {
searchParams[key] = filter[key];
searchParams[key] = query[key];
}
}

Expand Down Expand Up @@ -229,8 +222,7 @@ export default function implementAPI(cvat) {
}
}

let tasksData = null;
if (filter.projectId) {
if ('projectId' in filter) {
if (searchParams.filter) {
const parsed = JSON.parse(searchParams.filter);
searchParams.filter = JSON.stringify({ and: [parsed, { '==': [{ var: 'project_id' }, filter.projectId] }] });
Expand All @@ -239,8 +231,19 @@ export default function implementAPI(cvat) {
}
}

tasksData = await serverProxy.tasks.get(searchParams);
const tasks = tasksData.map((task) => new Task(task));
const tasksData = await serverProxy.tasks.get(searchParams);
const tasks = await Promise.all(tasksData.map(async (taskItem) => {
// Temporary workaround for UI
// Fixme: too much requests on tasks page
let jobs = { results: [] };
if ('id' in filter) {
jobs = await serverProxy.jobs.get({
filter: JSON.stringify({ and: [{ '==': [{ var: 'task_id' }, taskItem.id] }] }),
}, true);
}
return new Task({ ...taskItem, jobs: jobs.results });
}));

tasks.count = tasksData.count;
return tasks;
};
Expand All @@ -263,11 +266,7 @@ export default function implementAPI(cvat) {
}

const projectsData = await serverProxy.projects.get(searchParams);
const projects = projectsData.map((project) => {
project.task_ids = project.tasks;
return project;
}).map((project) => new Project(project));

const projects = projectsData.map((project) => new Project(project));
projects.count = projectsData.count;

return projects;
Expand Down
16 changes: 3 additions & 13 deletions cvat-core/src/cloud-storage.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Copyright (C) 2021-2022 Intel Corporation
// Copyright (C) 2022 CVAT.ai Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import { isBrowser, isNode } from 'browser-or-node';
import PluginRegistry from './plugins';
import serverProxy from './server-proxy';
import { ArgumentError } from './exceptions';
import { CloudStorageCredentialsType, CloudStorageProviderType, CloudStorageStatus } from './enums';
import User from './user';
import { decodePreview } from './frames';

function validateNotEmptyString(value: string): void {
if (typeof value !== 'string') {
Expand Down Expand Up @@ -362,17 +362,7 @@ Object.defineProperties(CloudStorage.prototype.getPreview, {
return new Promise((resolve, reject) => {
serverProxy.cloudStorages
.getPreview(this.id)
.then((result) => {
if (isNode) {
resolve(global.Buffer.from(result, 'binary').toString('base64'));
} else if (isBrowser) {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(result);
}
})
.then((result) => decodePreview(result))
.catch((error) => {
reject(error);
});
Expand Down
8 changes: 4 additions & 4 deletions cvat-core/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ export function checkExclusiveFields(obj, exclusive, ignore): void {
exclusive: [],
other: [],
};
for (const field in Object.keys(obj)) {
if (!(field in ignore)) {
if (field in exclusive) {
if (fields.other.length) {
for (const field in obj) {
if (!(ignore.includes(field))) {
if (exclusive.includes(field)) {
if (fields.other.length || fields.exclusive.length) {
throw new ArgumentError(`Do not use the filter field "${field}" with others`);
}
fields.exclusive.push(field);
Expand Down
30 changes: 12 additions & 18 deletions cvat-core/src/frames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,26 +618,20 @@ export async function getContextImage(jobID, frame) {
return frameDataCache[jobID].frameBuffer.getContextImage(frame);
}

export async function getPreview(taskID = null, jobID = null) {
export function decodePreview(preview: Blob): Promise<string> {
return new Promise((resolve, reject) => {
// Just go to server and get preview (no any cache)
serverProxy.frames
.getPreview(taskID, jobID)
.then((result) => {
if (isNode) {
// eslint-disable-next-line no-undef
resolve(global.Buffer.from(result, 'binary').toString('base64'));
} else if (isBrowser) {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(result);
}
})
.catch((error) => {
if (isNode) {
resolve(global.Buffer.from(preview, 'binary').toString('base64'));
} else if (isBrowser) {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result as string);
};
reader.onerror = (error) => {
reject(error);
});
};
reader.readAsDataURL(preview);
}
});
}

Expand Down
55 changes: 27 additions & 28 deletions cvat-core/src/issue.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
// Copyright (C) 2020-2022 Intel Corporation
// Copyright (C) 2022 CVAT.ai Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import quickhull from 'quickhull';

import { Job } from 'session';
import PluginRegistry from './plugins';
import Comment, { RawCommentData } from './comment';
import User from './user';
import { ArgumentError } from './exceptions';
import serverProxy from './server-proxy';

interface RawIssueData {
job: number;
position: number[];
frame: number;
id?: number;
job?: any;
position?: number[];
comments?: any;
frame?: number;
comments?: RawCommentData[];
owner?: any;
resolved?: boolean;
created_date?: string;
}

export default class Issue {
public readonly id: number;
public readonly job: Job;
public readonly comments: Comment[];
public readonly id?: number;
public readonly job: number;
public readonly frame: number;
public readonly owner: User;
public readonly resolved: boolean;
public readonly createdDate: string;
public position: number[];
public readonly owner?: User;
public readonly comments: Comment[];
public readonly resolved?: boolean;
public readonly createdDate?: string;
public position?: number[];
private readonly __internal: RawIssueData & { comments: Comment[] };

constructor(initialData: RawIssueData) {
const data: RawIssueData = {
const data: RawIssueData & { comments: Comment[] } = {
id: undefined,
job: undefined,
position: undefined,
comments: [],
frame: undefined,
created_date: undefined,
owner: undefined,
resolved: undefined,
comments: undefined,
};

for (const property in data) {
Expand All @@ -53,14 +53,16 @@ export default class Issue {

if (data.owner && !(data.owner instanceof User)) data.owner = new User(data.owner);

if (data.comments) {
data.comments = data.comments.map((comment) => new Comment(comment));
}

if (typeof data.created_date === 'undefined') {
data.created_date = new Date().toISOString();
}

if (Array.isArray(initialData.comments)) {
data.comments = initialData.comments.map((comment: RawCommentData): Comment => new Comment(comment));
} else {
data.comments = [];
}

Object.defineProperties(
this,
Object.freeze({
Expand All @@ -80,7 +82,7 @@ export default class Issue {
get: () => data.job,
},
comments: {
get: () => [...data.comments],
get: () => data.comments,
},
frame: {
get: () => data.frame,
Expand Down Expand Up @@ -144,19 +146,15 @@ export default class Issue {
}

public serialize(): RawIssueData {
const { comments } = this;
const data: RawIssueData = {
job: this.job,
position: this.position,
frame: this.frame,
comments: comments.map((comment) => comment.serialize()),
};

if (typeof this.id === 'number') {
data.id = this.id;
}
if (typeof this.job === 'number') {
data.job = this.job;
}
if (typeof this.createdDate === 'string') {
data.created_date = this.createdDate;
}
Expand All @@ -175,23 +173,24 @@ Object.defineProperties(Issue.prototype.comment, {
implementation: {
writable: false,
enumerable: false,
value: async function implementation(data: RawCommentData) {
value: async function implementation(this: Issue, data: RawCommentData) {
if (typeof data !== 'object' || data === null) {
throw new ArgumentError(`The argument "data" must be an object. Got "${data}"`);
}
if (typeof data.message !== 'string' || data.message.length < 1) {
throw new ArgumentError(`Comment message must be a not empty string. Got "${data.message}"`);
}

const internalData = Object.getOwnPropertyDescriptor(this, '__internal').get();
const comment = new Comment(data);
if (typeof this.id === 'number') {
const serialized = comment.serialize();
serialized.issue = this.id;
const response = await serverProxy.comments.create(serialized);
const savedComment = new Comment(response);
this.__internal.comments.push(savedComment);
internalData.comments.push(savedComment);
} else {
this.__internal.comments.push(comment);
internalData.comments.push(comment);
}
},
},
Expand Down
Loading