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

User interface with react and antd #755

Merged
merged 38 commits into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6ef145b
CVAT-UI: Second try
bsekachev Sep 24, 2019
7ce8038
Login page, router
bsekachev Sep 26, 2019
36338b2
Registration
bsekachev Sep 26, 2019
df50516
Changed text
bsekachev Sep 26, 2019
2b68a43
Added auto complete
bsekachev Sep 26, 2019
57b540f
Minor fixes
bsekachev Sep 27, 2019
13e0e44
Merge branch 'develop' into bs/cvat_ui
bsekachev Sep 27, 2019
50b1762
Added logout actions
bsekachev Sep 30, 2019
054f081
Added logout reducers
bsekachev Sep 30, 2019
64f19af
Added header
bsekachev Sep 30, 2019
452d230
Improved header
bsekachev Sep 30, 2019
3a5f9cc
Added empty-tasks
bsekachev Oct 1, 2019
9a08429
Tasks page initialized
bsekachev Oct 2, 2019
8f6815c
Dinamic resolution
bsekachev Oct 2, 2019
c575a2c
Dinamic resolution
bsekachev Oct 2, 2019
32ff5a1
Added preview
bsekachev Oct 3, 2019
f73a0a8
Adjusted task item
bsekachev Oct 3, 2019
c323cfc
Added menu
bsekachev Oct 3, 2019
7cba9e0
Improved error handling
bsekachev Oct 3, 2019
d40bb09
Adjusted progress color
bsekachev Oct 3, 2019
ee30f2f
Some eslint fixes
bsekachev Oct 4, 2019
ff0e3e8
Task search and pagination
bsekachev Oct 4, 2019
a653314
Merge branch 'develop' into bs/cvat_ui
bsekachev Oct 4, 2019
2ff5e2e
Pagination & filter works together
bsekachev Oct 4, 2019
af173b3
Core entrypoint
bsekachev Oct 4, 2019
f61b97f
Configurable host
bsekachev Oct 4, 2019
f5dd6c3
Prebuilt cvat-core
bsekachev Oct 4, 2019
b0e72a2
Couple of fixes
bsekachev Oct 4, 2019
c7ad2f8
Added icons
bsekachev Oct 4, 2019
b690df4
Merge branch 'develop' into bs/cvat_ui
bsekachev Oct 14, 2019
ddfe50b
Fixed preview tests
bsekachev Oct 14, 2019
fadf494
Owner/assignee name instead of id
bsekachev Oct 14, 2019
c7051fd
Task previews in redux state
bsekachev Oct 14, 2019
86d1eb1
Some class components -> functional components
bsekachev Oct 14, 2019
0e6eed5
Code refactoring
bsekachev Oct 14, 2019
40fd26f
Code refactoring
bsekachev Oct 14, 2019
21b1b48
Separated validation patterns
bsekachev Oct 14, 2019
9e64aaf
Frozen scikit-image version 0.15
bsekachev Oct 14, 2019
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
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"directory": "./cvat-canvas",
"changeProcessCWD": true
},
{
"directory": "./cvat-ui",
"changeProcessCWD": true
},
{
"directory": ".",
"changeProcessCWD": true
Expand Down
8,581 changes: 8,581 additions & 0 deletions cvat-canvas/package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions cvat-core/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist
docs
node_modules
reports

1 change: 1 addition & 0 deletions cvat-core/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@
"func-names": [0],
"valid-typeof": [0],
"no-console": [0], // this rule deprecates console.log, console.warn etc. because "it is not good in production code"
"max-classes-per-file": [0],
},
};
4 changes: 2 additions & 2 deletions cvat-core/src/annotation-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@
handler_file: initialData.handler_file,
};

data.dumpers = initialData.dumpers.map(el => new Dumper(el));
data.loaders = initialData.loaders.map(el => new Loader(el));
data.dumpers = initialData.dumpers.map((el) => new Dumper(el));
data.loaders = initialData.loaders.map((el) => new Loader(el));

// Now all fields are readonly
Object.defineProperties(this, {
Expand Down
22 changes: 11 additions & 11 deletions cvat-core/src/annotations-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,19 @@

export() {
const data = {
tracks: this.tracks.filter(track => !track.removed)
.map(track => track.toJSON()),
tracks: this.tracks.filter((track) => !track.removed)
.map((track) => track.toJSON()),
shapes: Object.values(this.shapes)
.reduce((accumulator, value) => {
accumulator.push(...value);
return accumulator;
}, []).filter(shape => !shape.removed)
.map(shape => shape.toJSON()),
}, []).filter((shape) => !shape.removed)
.map((shape) => shape.toJSON()),
tags: Object.values(this.tags).reduce((accumulator, value) => {
accumulator.push(...value);
return accumulator;
}, []).filter(tag => !tag.removed)
.map(tag => tag.toJSON()),
}, []).filter((tag) => !tag.removed)
.map((tag) => tag.toJSON()),
};

return data;
Expand All @@ -200,7 +200,7 @@
const shapes = this.shapes[frame] || [];
const tags = this.tags[frame] || [];

const objects = tracks.concat(shapes).concat(tags).filter(object => !object.removed);
const objects = tracks.concat(shapes).concat(tags).filter((object) => !object.removed);
// filtering here

const objectStates = [];
Expand Down Expand Up @@ -370,7 +370,7 @@

const clientID = ++this.count;
const track = {
frame: Math.min.apply(null, Object.keys(keyframes).map(frame => +frame)),
frame: Math.min.apply(null, Object.keys(keyframes).map((frame) => +frame)),
shapes: Object.values(keyframes),
group: 0,
label_id: label.id,
Expand Down Expand Up @@ -577,7 +577,7 @@

if (objectType === 'track') {
const keyframes = Object.keys(object.shapes)
.sort((a, b) => +a - +b).map(el => +el);
.sort((a, b) => +a - +b).map((el) => +el);

let prevKeyframe = keyframes[0];
let visible = false;
Expand Down Expand Up @@ -699,13 +699,13 @@
} else if (state.objectType === 'track') {
constructed.tracks.push({
attributes: attributes
.filter(attr => !labelAttributes[attr.spec_id].mutable),
.filter((attr) => !labelAttributes[attr.spec_id].mutable),
frame: state.frame,
group: 0,
label_id: state.label.id,
shapes: [{
attributes: attributes
.filter(attr => labelAttributes[attr.spec_id].mutable),
.filter((attr) => labelAttributes[attr.spec_id].mutable),
frame: state.frame,
occluded: state.occluded || false,
outside: false,
Expand Down
2 changes: 1 addition & 1 deletion cvat-core/src/annotations-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@
lock: this.lock,
zOrder: this.zOrder,
points: [...this.points],
attributes: Object.assign({}, this.attributes),
attributes: { ...this.attributes },
label: this.label,
group: this.group,
color: this.color,
Expand Down
16 changes: 12 additions & 4 deletions cvat-core/src/api-implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

cvat.server.formats.implementation = async () => {
const result = await serverProxy.server.formats();
return result.map(el => new AnnotationFormat(el));
return result.map((el) => new AnnotationFormat(el));
};

cvat.server.register.implementation = async (username, firstName, lastName,
Expand Down Expand Up @@ -82,7 +82,7 @@
users = await serverProxy.users.getUsers();
}

users = users.map(user => new User(user));
users = users.map((user) => new User(user));
return users;
};

Expand Down Expand Up @@ -116,8 +116,11 @@

// If task was found by its id, then create task instance and get Job instance from it
if (tasks !== null && tasks.length) {
tasks[0].owner = await serverProxy.users.getUsers(tasks[0].owner);
tasks[0].assignee = await serverProxy.users.getUsers(tasks[0].assignee);
const task = new Task(tasks[0]);
return filter.jobID ? task.jobs.filter(job => job.id === filter.jobID) : task.jobs;
return filter.jobID ? task.jobs
.filter((job) => job.id === filter.jobID) : task.jobs;
}

return [];
Expand Down Expand Up @@ -158,8 +161,13 @@
}
}

const users = await serverProxy.users.getUsers();
const tasksData = await serverProxy.tasks.getTasks(searchParams.toString());
const tasks = tasksData.map(task => new Task(task));
const tasks = tasksData.map((task) => {
[task.owner] = users.filter((user) => user.id === task.owner);
[task.assignee] = users.filter((user) => user.id === task.assignee);
return new Task(task);
});
tasks.count = tasksData.count;

return tasks;
Expand Down
21 changes: 21 additions & 0 deletions cvat-core/src/frames.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,26 @@
});
};

async function getPreview(taskID) {
return new Promise(async (resolve, reject) => {
try {
// Just go to server and get preview (no any cache)
const result = await serverProxy.frames.getPreview(taskID);
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);
}
} catch (error) {
reject(error);
}
});
}

async function getFrame(taskID, mode, frame) {
if (!(taskID in frameDataCache)) {
frameDataCache[taskID] = {};
Expand Down Expand Up @@ -140,5 +160,6 @@
module.exports = {
FrameData,
getFrame,
getPreview,
};
})();
36 changes: 32 additions & 4 deletions cvat-core/src/server-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,20 @@
}
}

async function getUsers() {
async function getUsers(id = null) {
const { backendAPI } = config;

let response = null;
try {
response = await Axios.get(`${backendAPI}/users`, {
proxy: config.proxy,
});
if (id === null) {
response = await Axios.get(`${backendAPI}/users`, {
proxy: config.proxy,
});
} else {
response = await Axios.get(`${backendAPI}/users/${id}`, {
proxy: config.proxy,
});
}
} catch (errorData) {
throw generateError(errorData, 'Could not get users from the server');
}
Expand All @@ -372,6 +378,27 @@
return response.data;
}

async function getPreview(tid) {
const { backendAPI } = config;

let response = null;
try {
// TODO: change 0 frame to preview
response = await Axios.get(`${backendAPI}/tasks/${tid}/frames/0`, {
proxy: config.proxy,
responseType: 'blob',
});
} catch (errorData) {
const code = errorData.response ? errorData.response.status : errorData.code;
throw new ServerError(
`Could not get preview frame for the task ${tid} from the server`,
code,
);
}

return response.data;
}

async function getData(tid, frame) {
const { backendAPI } = config;

Expand Down Expand Up @@ -567,6 +594,7 @@
value: Object.freeze({
getData,
getMeta,
getPreview,
}),
writable: false,
},
Expand Down
42 changes: 35 additions & 7 deletions cvat-core/src/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
(() => {
const PluginRegistry = require('./plugins');
const serverProxy = require('./server-proxy');
const { getFrame } = require('./frames');
const { getFrame, getPreview } = require('./frames');
const { ArgumentError } = require('./exceptions');
const { TaskStatus } = require('./enums');
const { Label } = require('./labels');
Expand Down Expand Up @@ -109,6 +109,11 @@
.apiWrapper.call(this, prototype.frames.get, frame);
return result;
},
async preview() {
const result = await PluginRegistry
.apiWrapper.call(this, prototype.frames.preview);
return result;
},
},
writable: true,
}),
Expand Down Expand Up @@ -380,6 +385,17 @@
* @throws {module:API.cvat.exceptions.ServerError}
* @throws {module:API.cvat.exceptions.ArgumentError}
*/
/**
* Get the first frame of a task for preview
* @method preview
* @memberof Session.frames
* @returns {string} - jpeg encoded image
* @instance
* @async
* @throws {module:API.cvat.exceptions.PluginError}
* @throws {module:API.cvat.exceptions.ServerError}
* @throws {module:API.cvat.exceptions.ArgumentError}
*/

/**
* Namespace is used for an interaction with logs
Expand Down Expand Up @@ -619,6 +635,7 @@

this.frames = {
get: Object.getPrototypeOf(this).frames.get.bind(this),
preview: Object.getPrototypeOf(this).frames.preview.bind(this),
};
}

Expand Down Expand Up @@ -780,9 +797,9 @@
get: () => data.mode,
},
/**
* Identificator of a user who has created the task
* Instance of a user who has created the task
* @name owner
* @type {integer}
* @type {module:API.cvat.classes.User}
* @memberof module:API.cvat.classes.Task
* @readonly
* @instance
Expand All @@ -791,9 +808,9 @@
get: () => data.owner,
},
/**
* Identificator of a user who is responsible for the task
* Instance of a user who is responsible for the task
* @name assignee
* @type {integer}
* @type {module:API.cvat.classes.User}
* @memberof module:API.cvat.classes.Task
* @instance
* @throws {module:API.cvat.exceptions.ArgumentError}
Expand Down Expand Up @@ -1122,6 +1139,7 @@

this.frames = {
get: Object.getPrototypeOf(this).frames.get.bind(this),
preview: Object.getPrototypeOf(this).frames.preview.bind(this),
};
}

Expand Down Expand Up @@ -1218,6 +1236,11 @@
return frameData;
};

Job.prototype.frames.preview.implementation = async function () {
const frameData = await getPreview(this.task.id);
return frameData;
};

// TODO: Check filter for annotations
Job.prototype.annotations.get.implementation = async function (frame, filter) {
if (frame < this.startFrame || frame > this.stopFrame) {
Expand Down Expand Up @@ -1293,7 +1316,7 @@
name: this.name,
bug_tracker: this.bugTracker,
z_order: this.zOrder,
labels: [...this.labels.map(el => el.toJSON())],
labels: [...this.labels.map((el) => el.toJSON())],
};

await serverProxy.tasks.saveTask(this.id, taskData);
Expand All @@ -1302,7 +1325,7 @@

const taskData = {
name: this.name,
labels: this.labels.map(el => el.toJSON()),
labels: this.labels.map((el) => el.toJSON()),
image_quality: this.imageQuality,
z_order: Boolean(this.zOrder),
};
Expand Down Expand Up @@ -1358,6 +1381,11 @@
return result;
};

Task.prototype.frames.preview.implementation = async function () {
const frameData = await getPreview(this.id);
return frameData;
};

// TODO: Check filter for annotations
Task.prototype.annotations.get.implementation = async function (frame, filter) {
if (!Number.isInteger(frame) || frame < 0) {
Expand Down
14 changes: 14 additions & 0 deletions cvat-core/tests/api/frames.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,17 @@ describe('Feature: get frame data', () => {
expect(typeof (frameData)).toBe('string');
});
});

describe('Feature: get frame preview', () => {
test('get frame preview for a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const frame = await task.frames.preview();
expect(typeof (frame)).toBe('string');
});

test('get frame preview for a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const frame = await job.frames.preview();
expect(typeof (frame)).toBe('string');
});
});
Loading