Release 0.6.0 (#1238)
* Release 0.5 (#705) * Changed version number (0, 5, 'final', 0). * Updated changelog file. * fixed default attribute values for tracked shapes (#703) * typo ? Should not this be cvat_redis -> redis ? * Fixed labels regex for non-latin characters (#708) * Update README.md * Update README.md * Don't save shapes with keyframe==False * Selecting non images leads to 400 error (#734) * Fix HTTP 400 error if together with vision data the user submit non-vision data (e.g. text files) * Ignore SVG images because Pillow doesn't work with them. * Fix the problem with duplicated frames in case of "share" (#735) * Fix the problem with duplicated frames in case of "share". * Fix a case when the code works incorrectly /a/b/c /a/b/c0 Previously only /a/b/c will be in output but should be both. * added method docs to Auto Annotation inference.py (#725) * remove deprecated method call `from_ir` (#726) * New command line tool for working with tasks (#732) * Adding new command line tool for performing common task related operations (create, list, delete, etc.) * Replaced @exception decorator with try/except in main() * Replaced optional --name with positional name and removed default * Added license text to files * Added django units to cover future API changes * Refactored into submodules to better support tests * Fix an issue with permissions (observer can change annotations) (#745) * Fixed a problem with observer (check_object_permissions method was not called) * Added a test case to cover issue #712. * COCO Annotation IDs should begin with 1 (#748) Currently the annotation ID begins with 0 which is interpreted by cocoapi as a false detection. The array dtm saves the matches via the ground truth annotation ID. The variable dtm is initialized as an array of zeros.main636becdc73/PythonAPI/pycocotools/cocoeval.py (L269)636becdc73/PythonAPI/pycocotools/cocoeval.py (L295)636becdc73/PythonAPI/pycocotools/cocoeval.py (L375)* Slightly enhance command line interface feature (#746) * Slightly enhance command line interface feature. Added README.md, run tests using travis, run CLI tests from VS code. * Removed formatted string due to a limitation on our python version inside the container. * Add information about command line interface to the main page. * Projects (server only, REST API) (#754) * Initial version of projects * Added tests for Projects REST API. * Added information about projects into CHANGELOG * Updating string format for case missed in PR #746. (#757) * add robust JSON handeling for auto annotation runner (#758) * Basic user information (#761) * Fix https://github.com/opencv/cvat/issues/750 * Updated CHANGELOG * Added more tests for /api/v1/users* REST API. * Disable fix_segments_intersections for now (#751) * Disable fix_segments_intersections for now When the bounding boxes had intersections and were exported with the COCO JSON format they were often cut off. I commented out the line with the function fix_segments_intersections and replaced it with lines of that function. This helped with the bounding boxes and keeps the masks as they are created with CVAT. It is probably inconvenient for the user to get something fixed in the export without an active agreement of the user. Secondly letting a function automatically fix segments could result in a bad fix. * Use fix_segments_intersections only with z-order The fix_segments_intersections will only be used when the z-order flag is set. This is useful for bounding boxes or masks which don't need to be fixed. This fix was created according to Andrey Zhavoronkov's (@azhavoro) advice. * Added information about a fixed issue. (#765) * Add more information into questions section (#766) * User interface with react and antd (#755) * Login page, router * Registration * Tasks view * add in serializing check in auto annotation model runner (#770) * allow security segmentation models to be used in auto annotation (#759) * Integration with Zenodo (#779) * Updated CHANGELOG with information about Zenodo * Updated version of the project. * Fixed a case when a task's owner can be undefined. (#782) * Added `restart` tag to docker-compose for `cvat_ui` (#789) * User interface with React and antd (#785) * Dump & refactoring * Upload annotations, cvat-core from sources * Added download icon * Added icon * Update documentation to point to OpenVino component documentation (#752) * Change the version of OpenVINO compatibility (#797) * Change the version of OpenVINO compatibility * added mask RCNN script (#780) * added in yolo auto annotation sciprt (#794) * Annotation formats documentation (#719) * added handling of truncated and difficult attributes for pascal voc loader/dumper added descriptions of supported annotation formats * added YOLO example * made match_frame as Annotations method changed 'image/source_id' field TF feature from int64 to string (according to TF OD API dataset utlis) * updated README improved match_frame function * added unit tests for dump/load * added in semantic segmentation instructions to README (#804) * fix off by one error in mask rcnn (#801) * Fix Yolo: swap width, height; Change box coord order; parsing fix (#802) * Auto segmentation using Mask_RCNN (#767) * Update CHANGELOG.md * Bump pillow from 5.1.0 to 6.2.0 in /cvat/requirements (#808) Bumps [pillow](https://github.com/python-pillow/Pillow) from 5.1.0 to 6.2.0. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/5.1.0...6.2.0) Signed-off-by: dependabot[bot] <support@github.com> * Bump pillow from 5.3.0 to 6.2.0 in /utils/cli (#807) Bumps [pillow](https://github.com/python-pillow/Pillow) from 5.3.0 to 6.2.0. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/5.3.0...6.2.0) Signed-off-by: dependabot[bot] <support@github.com> * Bump eslint-utils from 1.4.0 to 1.4.3 in /cvat-canvas (#809) Bumps [eslint-utils](https://github.com/mysticatea/eslint-utils) from 1.4.0 to 1.4.3. - [Release notes](https://github.com/mysticatea/eslint-utils/releases) - [Commits](https://github.com/mysticatea/eslint-utils/compare/v1.4.0...v1.4.3) Signed-off-by: dependabot[bot] <support@github.com> * fix serialize bug when using AutoAnnotation runner (#810) * User interface with React and antd (#811) * Fixed links for analytics and help * Delete task functionality * Added navigation for create and open task * Added icon for help * Added easy plugin checker * Header dependes on installed plugins * Menu depends on installed plugins * Shared actions menu component, base layout for task page * Task page based (relations with redux, base layout) * Added attribute form * Finished label creator * Added jobs table * Added job assignee * Save updated labels on server * Added imports plugin, updated webpack * Editable bug tracker * Clean task update * Change assignee * Fix login problem (unathorized user cannot login). (#812) * Fix upload anno for COCO (#788) * COCO: load bbox as rectangle if segmentation field is empty * added unit test for coco format (case: object segment field is empty) * Add support for ip git repo urls (#827) * Add support for ip v4 git repo urls * Add tests for git urls * React & Antd UI: Create task (#840) * Separated component user selector * Change job assignee * Basic create task window * Bug fixes and refactoring * Create task connected with a server * Loading status for a button * Reset loading on error response * UI improvements * Github/feedback/share window * added in new interp files for pixel link v0004 (#852) * Add LabelMe format support (#844) * Add labelme export * Add LabelMe import * Add labelme format to readme * Updated CHANGELOG.md * Adding dump and load support for MOT CSV format. (#830) * Adding dump and load support for MOT CSV format. * Updated test cases to use correct track annotations for MOT format. * Removed behaviour of MOT loader which would duplicate the last track shape prior to setting outside=True. * Add dataset export facility (#813) * Add datumaro django application * Add cvat task datumaro bindings * Add REST api for task export * Add scheduler service * Updated CHANGELOG.md * Mit license for pixellink and changelog (#862) * React & Antd UI: Model manager (#856) * Supported git to create and sync * Updated antd * Updated icons * Improved header * Top bar for models & empty models list * Removed one extra reducer and actions * Removed one extra reducer and actions * Crossplatform css * Models reducers, some models actions, base for model list, imrovements * Models list, ability to delete models * Added ability to upload models * Improved form, reinit models after create * Removed some importants in css * Model running dialog window, a lot of fixes * Add a dataset export button for tasks (#834) * Add dataset export button for tasks in dashboard * Fix downloading, shrink list of export formats * Add strict export format check * Add strict export format check * Change REST api paths * Move formats declarations to server, * Coco converter updates (#864) * [Datumaro] Fix coco images export (#875) * Update test * Fix export * Support several image paths in coco extractor * [Datumaro] Disable lazy image caching by default (#876) * Disable lazy image caching by default * Deterministic cache test * Add displacing image cache * React & Antd UI: Export dataset, refactoring & fixes (#872) * Automatic label matching (by the same name) in model running window * Improved create task window * Improved upload model window * Fixed: error window showed twice * Updated CONTRIBUTING.md * Removed token before login, fixed dump submenu (adjustment), fixed case when empty models list displayed * Export as dataset, better error showing system * Removed extra requests, improved UI * Fixed a name of a format * Show inference progress * Fixed model loading after a model was uploaded * Fix redirect (#878) * Add cvat cli to datumaro project export (#870) * Configurable REST for UI, minor improvements (#880) * [Datumaro] Pip installation (#881) * Add version file * Remove unnecessary dependencies * Add lxml use motivation * Add pip setup script * Reduce opencv dependency * Fix cli command * Codacy * page_size parameter for all REST API methods (#884) * Added page_size parameter for all REST API methods which returns list of objects. Also it is possible to specify page_size=all to return all elements. * Updated changelog.md * VOC converter: Use depth from CVAT XML if available (#885) * Token auth for non-REST API apps (#889) * Token authorization for non REST API apps (e.g. git, tf annotation, tf segmentation) * set CORS_REPLACE_HTTPS_REFERER option to True (#895) * Fix some spelling (#897) * React & Antd: Dashboard migration (#892) * Removed old dashboard * Getting all users * Updated changelog * Reimplemented login decorator * Implicit host, scheme in docker-compose * Fixed issue with pagination * Implicit page size parameter for tasks * Fixed linkedin icon, added links to tasks in notifications * Configurable method for check plugin * Bump django from 2.2.4 to 2.2.8 in /cvat/requirements (#902) Bumps [django](https://github.com/django/django) from 2.2.4 to 2.2.8. - [Release notes](https://github.com/django/django/releases) - [Commits](https://github.com/django/django/compare/2.2.4...2.2.8) Signed-off-by: dependabot[bot] <support@github.com> * Az/fix meta requests (#903) * fixed processing of meta requests * Fixed some issues with dump (#904) * Changed method for downloading annotations * Initial commit * Initial commit * Updated download method for dataset * fixed eslint error * Restore session id (#905) * Restore session id when we use token authorization. * UI eslint fixes (#908) * Installed airbnb fullsettings * Fixed actions menu * Create model/task page * File manager, header * Labels editor * Login, register * Models page & model runner * Tasks page * Feedback and base app * Tasks page * Containers * Reducers * Fixed additional issues * Small pagination fix * implemented adas semantic segmentation * Copy JOB info to clibpard * Yolov3 interpretration script fix for 'Annotation failed' and changes to mapping.json (#896) (#912) * [Datumaro] Add YOLO converter (#906) * Add YOLO converter * Added yolo extractor * Added YOLO format test * Add YOLO export in UI * Added padding * Remove deprecated html attributes (#924) * Updated message * Improved some hints * Added 3rdparty library to clipboard * Updated doc * Added ability to copy labels without IDs * Removed extra lines * Updated contributing * Updated contributing * Task name displayed better * Improved tasks routing * Ability to show hidden task * Destroy messages before getting new tasks * Fixed eslint * Names of selected files when creating a new task * [Datumaro] Added tf detection api tfrecord import and export (#894) * Added tf detection api tfrecord import and export * Added export button in dashboard * Add tf to requirements * Extend test * Add tf dependency * Require images in tfrecord export * Add video task case handling * Maintain image order in CVAT export * Fix Task image id-path conversions * Update tfrecord tests * Extend image utilities * Update tfrecord format * Fix image loading bug * Add some logs * Add 'copy' option to project import command * Reduce default cache size * Improve UX with creating new shape by shortkey (#941) * Fixed command in CONTRIBUTING.md (#947) * Fixed command in CONTRIBUTING.md * Removed daemon, updated command * [Datumaro] COCO 'merge instance polygons' option (#938) * Add polygon merging option to coco converter * Add test, refactor coco, add support for cli args * Drop colormap application in datumaro format * Add cli support in voc converter * Add cli support in yolo converter * Add converter cli options in project cli * Add image data type conversion in image saving * [Datumaro] Fix voc colormap (#945) * Add polygon merging option to coco converter * Add test, refactor coco, add support for cli args * Drop colormap application in datumaro format * Add cli support in voc converter * Add cli support in yolo converter * Add converter cli options in project cli * Add image data type conversion in image saving * Add image data type conversion in image saving * Update mask support in voc * Replace null with quotes in coco export * Improve cli * Enable Datumaro intellisense in vs cde * Adjust fields in voc detection export * Return pylint to config (#951) * Update docker base images (#950) Don't fix minor/patch version to get security updates and bug fixes. * Fixed git plugin (#961) * Add upload annotation function to cli (#958) * add upload annotation function to cli * Update core.py Removing whitespace * React, Antd, Redux: Left sidebar and top for annotation page (#963) * Rebased from develop * Improved getting icons method * Added more icons * Left menu * Initial commit * Setup SVGO, added some buttons to top * Top bar progress * Top bar for annotation page * Updated styles * added in label visualization to auto annotation runner (#931) * Bump tensorflow from 1.13.1 to 1.15.0 in /utils/tfrecords (#967) Bumps [tensorflow](https://github.com/tensorflow/tensorflow) from 1.13.1 to 1.15.0. - [Release notes](https://github.com/tensorflow/tensorflow/releases) - [Changelog](https://github.com/tensorflow/tensorflow/blob/master/RELEASE.md) - [Commits](https://github.com/tensorflow/tensorflow/compare/v1.13.1...v1.15.0) Signed-off-by: dependabot[bot] <support@github.com> * Fixed number attribute (#972) * CSS Enhancement (#971) * Removed vendor/specific rules * Sass for CVAT, less for Antd, added autoprefixer and css polyfills * Removed extra line * Changed update state * [Datumaro] VOC labelmap support (#957) * Add import result checks and options to skip * Add label-specific attributes * Overwrite option for export * Add labelmap file support in voc * Add labelmap tests * Little refactoring * Bump tensorflow from 1.12.3 to 1.15.0 in /cvat/requirements (#968) * Bump tensorflow from 1.12.3 to 1.15.0 in /cvat/requirements Bumps [tensorflow](https://github.com/tensorflow/tensorflow) from 1.12.3 to 1.15.0. - [Release notes](https://github.com/tensorflow/tensorflow/releases) - [Changelog](https://github.com/tensorflow/tensorflow/blob/master/RELEASE.md) - [Commits](https://github.com/tensorflow/tensorflow/compare/v1.12.3...v1.15.0) Signed-off-by: dependabot[bot] <support@github.com> * Update pip because tensorflow 1.15 cannot not be found. * Fix a typo (pip -> pip3) * Replaced pip3 by python3 -m pip. * Change-submit-button-style (#976) * UI/UX improvement. Changed buttons type for create task / upload model * Added documentation for swagger page (#936) * Styles refactoring (#977) * Add polygon point count checks (#975) * User Guide update (#953) * Swagger documentation (#978) * Fix swagger problems (exceptions, /api/swagger.json, /api/docs/) * [Datumaro] CVAT format import (#974) * Add label-specific attributes * Add CVAT format import * Register CVAT format * Add little more logs * Little refactoring for tests * Cvat format checks * Add missing check * Refactor datumaro format * Little refactoring * Regularize dataset importer logic * Fix project import issue * Refactor coco extractor * Refactor tests * Codacy * Fix label for mask rcnn (#980) * UI Enhancements (#985) * Single import of basic styles * A little bit redesigned header * Specified min resolution 1280x768 * Getting a job instance * Improved handling when task doesn't exist * Adding dump for VOC instance mask. (#859) * Add mask instance dumper * Fix bug * Merge mask instance into mask * Merge the change into mask * Create MaskColorizer * Add dump method * Updating the Model Manager section of the CVAT User Guide (#991) * Added Code Climate, CodeBeat badges. (#995) * [Datumaro] Fix TFrecord converter constructor (#993) * Resolved performance bottleneck in merge function (#999) * Fixed issue: Unknown shape type found (#998) * Automatic bordering feature during drawing/editing (#997) * Change Modal submit button okType (#1001) * Fixed comparison of shapes (#1000) * Add test code for cli upload function (#986) * pass in model name and task id to run auto annotation script (#934) * fix dockerfile for PDF (#939) * Updating the Auto Annotation section of the CVAT User Guide (#996) * Updating the Task synchronization with a repository section of the CVAT User Guide (#1006) * Fix timezone bug (#1010) * [Datumaro] Fix project loading (#1013) * Fix occasional infinite loop in project loading * Fix project import source options saving * Fix project import .git dir placement * Make code aware of grayscale images * Added root folder for share functionality (#1005) * Improved feature: common borders (#1016) * Auto borders -> common borders, invisible when do not edit or draw, don't reset state * Reset sticker after clicking outside * Update AWS-Deployment-Guide.md (#1019) Fixed documentation typo for file extension * Correct link to #automatic-annotation in README (#1029) * AWS deployment guide updated #1009 (#1031) * Add info about auto segmentation to advanced topics of the installation guide (#1033) * correct path to eula.cfg (#1037) * Update README.md (#1040) * Removed patool package with GPL license (it is not used) (#1045) * Removed VIM package (it isn't necessary) (#1046) * Trim possible attribute values like attribute values setup by a user (#1044) * React UI: Player in annotation view & settings page (#1018) * Active player controls * Setup packages * Playing * Fold/unfold sidebar, minor issues * Improved cvat-canvas integration * Resolved some issues * Added cvat-canvas to Dockerfile.ui * Fit canvas method * Added annotation reducer * Added annotation actions * Added containers * Added components * cvat-canvas removed from dockerignore * Added settings page * Minor improvements * Container for canvas wrapper * Configurable grid * Rotation * fitCanvas added to readme * Aligned table * Changed CharField(64) -> CharField(4096) for attribute value (#1048) * [Datumaro] Add cvat format export (#1034) * Add cvat format export * Remove wrong items in test * [Datumaro] Instance polygon-mask conversions in COCO format (#1008) * Microoptimizations * Mask conversion functions * Add mask-polygon conversions * Add mask-polygon conversions in coco * Add mask-polygon conversions in coco * Update requirements * Option to disable crop * Fix cli parameter passing * Fix test * Fixes in COCO * [Datumaro] Dataset annotations filter (#1053) * Fix deprecation message * Update launcher interface * Add dataset entity, anno filter, remove filter from project config, update transform * Update project and source cli * Fix help message * Refactor tests * Added ability to match many model labels to one task labels (#1051) * Added ability to match many model labels to one task labels * Fixed grammar * React UI: Player updates (#1058) * Move, zoom integration * Moving, zooming, additional canvas handler * Activating & changing for objects * Improved colors * Saving annotations on the server * Fixed size * Refactoring * Added couple of notifications * Basic shape drawing * Cancel previous drawing * Refactoring * Minor draw improvings * Merge, group, split * Improved colors * Fixed: Uncaught TypeError: Cannot read property 'nodeValue' of undefined (#1068) * Add about CVAT (#1024) * Fix typos in xml_format.md (#1069) typo fixes * Update CONTRIBUTING.md (#1072) * align serializer max length of attribute value with the model (#1074) * Cleanup Dockerfiles for CVAT (#1060) * Replaced wget by curl * Moved CI stuff into Dockerfile.ci * Use docker-compose to run commnands inside docker (need environment variables) * Added patool again (to support different archive formats) * Roll back tensorflow version: 1.15 -> 1.13.1 Fixed https://github.com/opencv/cvat/issues/982 Fixed https://github.com/opencv/cvat/issues/1017 * datumaro install tensorflow 2.x now. It breaks automatic annotation using TF. * Follow redirects in curl (auto_segmentation) * Update method call (#1085) * React UI: Sidebar with objects and optimizations for annotation view (#1089) * Basic layout for objects panel * Objects header * A little name refactoring * Side panel base layout * Firefox specific exceptions * Some minor fixes * React & canvas optimizations * Icons refactoring * Little style refactoring * Some style fixes * Improved side panel with objects * Actual attribute values * Actual icons * Hidden > visible * hidden -> __internal * Fixed hidden in ui * Fixed some issues in canvas * Fixed list height * Color picker for labels * A bit fixed design * Actual header icons * Changing attributes and switchable buttons * Removed react memo (will reoptimize better) * Sorting methods, removed cache from cvat-core (a lot of bugs related with it) * Label switchers * Fixed bug with update timestamp for shapes * Annotation state refactoring * Removed old resetCache calls * Optimized top & left panels. Number of renders significantly decreased * Optimized some extra renders * Accelerated performance * Fixed two minor issues * Canvas improvements * Minor fixes * Removed extra code * resolving import error caused by pip 20.0 (#1094) * [Datumaro] CLI updates + better documentation (#1057) * Optimize mask conversions (#1097) * Update base.py (#1099) Modification necessary for using CVAT from remote machines when accessing with FQDNs See https://github.com/opencv/cvat/issues/1011#issue-542817055 and https://github.com/opencv/cvat/pull/1098 "I believe the reason for this is that sometimes if the port number is :80 and the URL is not in the LAN (:port), but instead it is a Fully Qualified Domain Name (:port), the port 80 is redundant (mydomain.com:80) and the errors arise." * fixed dump of interpolation points object && statistics calculation (#1108) * Add extreme clicking feature to draw box by 4 points (#1111) * Add extreme clicking feature to draw box by 4 points * Add documentation for extreme clicking * React UI: Annotation view enhancements (#1106) * Keyframes navigation * Synchronized objects on canvas and in side panel * Fixed minor bug with collapse * Fixed css property 'pointer-events' * Drawn appearance block * Removed extra force reflow * Finished appearance block, fixed couple bugs * Improved save() in cvat-core, changed approach to highlight shapes * Fixed exception in edit function, fixed filling for polylines and points, fixed wrong image navigation, remove and copy * Added lock * Some fixes with points * Minor appearance fixes * Fixed insert for points * Fixed unit tests * Fixed control * Fixed list size * Added propagate * Minor fix with attr saving * Some div changed to buttons * Locked some buttons for unimplemented functionalities * Statistics modal, changing a job status * Minor fix with shapes counting * Couple of fixes to improve visibility * Added fullscreen * SVG Canvas -> HTML Canvas frame (#1113) * SVG Frame -> HTML Canvas frame * React UI: Added annotation menus, added shape context menu, added some confirmations before dangerous actions (#1123) * Annotation menu, modified tasks menu * Removed extra styles * Context menu using side panel * Mousewheel on draw * Added more cursor icons * Do not check .svg & .scss by eslint * [Datumaro] Plugins and transforms (#1126) * Fix model run command * Rename annotation types, update class interfaces * Fix random cvat format test fails * Mask operations and dataset format fixes * Update tests, extract format testing functions * Add transform interface * Implement plugin system * Update tests with plugins * Fix logging * Add transfroms * Update cvat integration * Fix tensorflow installation (#1129) * Make tf dependency optional * Reduce opencv dependency * Import tf eagerly as it is a plugin * Do not install TF with Datumaro * Add plugin system documentation (#1131) * React UI: Improved mouse behaviour during draw/merge/edit/group/split (#1130) * Moving image with mouse during drawing, paste, group, split, merge * Babel plugin to dev deps * Move mouse during editing * Minor issues * [Datumaro] fixes (#1137) * Fix import command * Fix project name for spawned projects * Fix voc and coco converter parameters * Fix voc colormap color interpretation * Change order of image search for cvat extractor * fix CVAT image search paths * Bump django from 2.2.8 to 2.2.10 in /cvat/requirements (#1139) Bumps [django](https://github.com/django/django) from 2.2.8 to 2.2.10. - [Release notes](https://github.com/django/django/releases) - [Commits](https://github.com/django/django/compare/2.2.8...2.2.10) Signed-off-by: dependabot[bot] <support@github.com> * Add extreme clicking method in cvat-canvas and cvat-ui (#1127) * Add extreme clicking method in cvat-canvas and cvat-ui * Fix bugs and issues, update readme * Fix error after rebasing develop * updated CUDA to version 10 (#1138) * updated CUDA to version 10 * updated tensorflow * added comment about NVIDIA_REQUIRE_CUDA env varOF * React UI: Undo/redo (#1135) * Typed reducers (#1136) * Added typed actions/reducers * Added commands to check types / eslint issues * Added redux dev tools * Bump gitpython version (#1146) * Fix postgres startup. * React UI: Objects filtering & search (#1155) * Initial filter function * Updated method for filtering * Updated documentation * Added annotations filter file * Updated some comments * Added filter to UI * Implemented search alorithm * Removed extra code * Fixed typos * Added frame URL * Object URL * Removed extra encoding/decoding * Fixed dump for cases when special URL characters in task name (#1162) * Add offline subset remapping and bbox conversion (#1147) * Avoid tf deprecation warning (#1148) * [Datumaro] Pretty output folder names (#1149) * Generate output dir name from operation parameters * Fix failing command * Update changelog (#1165) * [Datumaro] Introduce image info (#1140) * Employ transforms and item wrapper * Add image class and tests * Add image info support to formats * Fix cli * Fix merge and voc converte * Update remote images extractor * Codacy * Remove item name, require path in Image * Merge images of dataset items * Update tests * Add image dir converter * Update Datumaro format * Update COCO format with image info * Update CVAT format with image info * Update TFrecord format with image info * Update VOC formar with image info * Update YOLO format with image info * Update dataset manager bindings with image info * Add image name to id transform * Fix coco export * More types in actions and reducers (#1166) * [Datumaro] Add masks to tfrecord format (#1156) * Employ transforms and item wrapper * Add image class and tests * Add image info support to formats * Fix cli * Fix merge and voc converte * Update remote images extractor * Codacy * Remove item name, require path in Image * Merge images of dataset items * Update tests * Add image dir converter * Update Datumaro format * Update COCO format with image info * Update CVAT format with image info * Update TFrecord format with image info * Update VOC formar with image info * Update YOLO format with image info * Update dataset manager bindings with image info * Add image name to id transform * Fix coco export * Add masks support for tfrecord * Refactor coco * Fix comparison * Remove dead code * Extract common code for instances * Replace YOLO format support in CVAT with Datumaro (#1151) * Employ transforms and item wrapper * Add image class and tests * Add image info support to formats * Fix cli * Fix merge and voc converte * Update remote images extractor * Codacy * Remove item name, require path in Image * Merge images of dataset items * Update tests * Add image dir converter * Update Datumaro format * Update COCO format with image info * Update CVAT format with image info * Update TFrecord format with image info * Update VOC formar with image info * Update YOLO format with image info * Update dataset manager bindings with image info * Add image name to id transform * Replace YOLO export and import in CVAT with Datumaro * Add editorconfig (#1142) * Add editorconfig * Update indent value * Cuboid annotation (#678) * Cuboid feature * migration files * Refactored cuboidShape Fixed a bug where coloring by label would not update cuboids properly Fixed a bug where the select points would not scale properly on initialization * Removed math.js dependency Implemented custom line intersection function * new cvat formatting with labelled points * Added MIT License to js files that were missing it * Added simple constraints to the cuboids * reverted commit for settings for vscode to hide local path * fixed locking for cuboids * fixed cuboid View when locked * fixed occlusion view for cuboids * Allow cuboid points to be outside the frame dimensions. Signed-off-by: Tritin Truong <truongtritin98@gmail.com> * Added stricter constraints on cuboid edges. * Slightly stricter restrictions for edge case * Cleaned up unused imports * removed dashed lines on cuboids * Moved projection lines to settings tab * Fixed Cuboid shape buffer \ * Fix migrations (two 022 migrations after merge with the develop branch). * Fix compatibility issues with auto segmentation. * Grab points and update control scheme * Greatly improved control scheme, fixed shape merging Fixed Cuboid upload * Fixed slight visual bug when dragging faces * Some optimizations * Hiding the grab point on creation Small refactoring * Fixed some cases where cuboid breaks * Fixed upload for videos * Removed perspective effects * Made left back edge editable * left back edge resizable * fix statistics bug * added toggles for the back edges * Constraints for the back edges * Fix creation bug * Tightened creation constraints * Fixing the code style * updated message for invalid cuboids * Code style * More style fixes * Codacy fixes * added shift control for edges * More Codacy fixes * More Codacy fixes * Double arrows for cursor * Fix Drag bug * More Codacy fixes * Fix double quotes * Fix camel case * More camelcase fixes * Generic object sink fixes * Various codacy fixes * Codacy * Double quotes * Fix migrations * Updated shape creation Fix jittering * Adjusted constraints * Codacy fixes * Codacy fixes again * Drawing cuboids from the top and bottom * Codacy * Resetting perspective on cuboids * Choosing orientation of cuboids. * Codacy fix * Merge cleanup * revert vs-code settings * Update settings.json Co-authored-by: timbowl <54648082+timbowl@users.noreply.github.com> Co-authored-by: Nikita Manovich <40690625+nmanovic@users.noreply.github.com> * Update yolo format description (#1173) * Replace tfrecord format support in CVAT with Datumaro (#1157) * Replace mask format support with Datumaro (#1163) * Add box to mask transform * Fix 'source' labelmap mode in voc converter * Import groups * Replace mask format support * Update mask format documentation * codacy * Fix tests * Fix dataset * Fix segments grouping * Merge instances in mask export * Update Onepanel demo information and link (#1189) * Added displayed versions of core, canvas, and ui in about (#1191) * Added displayed versions of core, canvas, and ui in about * Removed extra method * React UI: ZOrder implementation (#1176) * Drawn z-order switcher * Z layer was added to state * Added ZLayer API method cvat-canvas * Added sorting by Z * Displaying points in top * Removed old code * Improved sort function * Drawn a couple of icons * Send to foreground / send to background * Updated unit tests * Added unit tests for filter parser * Removed extra code * Updated README.md * Replace VOC format support in CVAT with Datumaro (#1167) * Add image meta reading to voc * Replace voc support in cvat * Bump format version * Materialize lazy transforms in voc export * Store voc instance id as group id * Add flat format import * Add documentation * Fix format name in doc * [Datumaro] Remote project export fixes (#1193) * Export project with trask name * Do not expose server paths * Fix tfrecord mask reading in tf>1.14 * Setuptools compatibility * Replace COCO implementation (#1195) * Fixed lags (#1197) * React UI: Changing color for a shape (#1194) * Minimized size of an element in side panel * To background / to foreground like in legacy UI * Added color changer for a shape * Adjusted color updating * React-UI: settings (#1164) * Image filters: brightness, contrast, saturation * Auto saving * Frame auto fit * Player speed * Leave confirmation for unsaved changes * React UI: Changing color for a group (#1205) * Added license headers (#1208) * Added licenser * Added license headers for cvat-canvas and cvat-ui * Move project dir to .datumaro (#1207) * Updated svg.js version (#1212) * React UI: Batch of fixes (#1211) * Disabled tracks for polyshapes in UI * RectDrawingMethod enum pushed to cvat-canvas, fixed some code issues * Optional arguments * Draw a text for locked shapes, some fixes with not keyframe shapes * Fixed zooming & batch grouping * Reset zoom for tasks with images * Fixed putting shapes out of canvas * Fixed grid opacity, little refactoring of componentDidUpdate in canvas-wrapper component * Fixed corner cases for drawing * Fixed putting shapes out of canvas * Improved drawing * Removed extra event handler * Auto-generate labelmap for voc from task (#1214) * Add random split transform (#1213) * React UI: Improved rotation feature (#1206) Co-authored-by: Boris Sekachev <40690378+bsekachev@users.noreply.github.com> * Az/cvat proxy (#1177) * added nginx proxy * removed unnecessary port configuration & build arg * updated installation guide * Add tags to cvat xml (#1200) * Extend cvat format test * Add tags to cvat for images * Add tags to cvat format in dm * Add import of tags from datumaro * React UI: Pinned option was added (#1202) * Fix remainder logic for subset splitting (#1222) * Add tags support for VOC (#1201) * Extend voc format test with tags * Add import and export of voc labels * Fix voc and yolo format version numbers * React UI: batch of fixes (#1227) * Fix: keyframes navigation * Fix: handled removing of the latest keyframe * Fix: activating a shape when another shape is being changed * Fix: up points in the side bar on points click * Fix: editable shape isn't transformed when change zoom * Updated message * React UI: Filters history (#1225) * Added filters history * Fixed unclosed dropdown * Added saving filters to localStrorage * Added button to cancel started automatic annotation (#1198) * [WIP] Cuboid feature user guide (#1218) * Initial cuboid description * Added Gifs * Added gifs to descriptions * Formatting fixes * Codacy Fixes * Az/fix annotation dump upload (#1229) * fixed upload annotation in case of frame step != 1 * fixed upload annotation in case of attribute value is empty * React UI: Added shortcuts (#1230) * [Datumaro] Label remapping transform (#1233) * Add label remapping transform * Apply transforms before project saving * Refactor voc converter * [Datumaro] Optimize mask operations (#1232) * Optimize mask to rle * Optimize mask operations * Fix dm format cmdline * Use RLE masks in datumaro format * Fixed date in CHANGELOG.md * sort frame shapes by z_order (#1258) Co-authored-by: vfdev <vfdev.5@gmail.com> Co-authored-by: Boris Sekachev <40690378+bsekachev@users.noreply.github.com> Co-authored-by: Ben Hoff <hoff.benjamin.k@gmail.com> Co-authored-by: Boris Sekachev <boris.sekachev@yandex.ru> Co-authored-by: Ben Hoff <bhoff@nciinc.com> Co-authored-by: telenachos <54951461+telenachos@users.noreply.github.com> Co-authored-by: Johannes222 <johannes.halaoui@alumni.fh-aachen.de> Co-authored-by: RS Nikhil Krishna <rsnk96@users.noreply.github.com> Co-authored-by: Andrey Zhavoronkov <41117609+azhavoro@users.noreply.github.com> Co-authored-by: Reza Malek <malekabbasi@meam.ir> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: zhiltsov-max <zhiltsov.max35@gmail.com> Co-authored-by: a-andre <a-andre@users.noreply.github.com> Co-authored-by: Maksim Markelov <maks-markel@mail.ru> Co-authored-by: himalayanZephyr <42401082+himalayanZephyr@users.noreply.github.com> Co-authored-by: Seungwon Jeong <jsw1295@gmail.com> Co-authored-by: Maya <49038720+Marishka17@users.noreply.github.com> Co-authored-by: TOsmanov <54434686+TOsmanov@users.noreply.github.com> Co-authored-by: vugia truong <vugiatruong88@gmail.com> Co-authored-by: roho <mrtn.etchart@gmail.com> Co-authored-by: Christian <christian.roemer@udo.edu> Co-authored-by: provider161 <provider8@yandex.ru> Co-authored-by: Radhika <43014570+radhika1601@users.noreply.github.com> Co-authored-by: Tanvi Anand <tanviaanand@gmail.com> Co-authored-by: Lisa <38404726+LiSa20120@users.noreply.github.com> Co-authored-by: Josh Bradley <jgbrad1@umd.edu> Co-authored-by: Priya4607 <59498234+Priya4607@users.noreply.github.com> Co-authored-by: LukeAI <43993778+LukeAI@users.noreply.github.com> Co-authored-by: Jijoong Kim <joong937@gmail.com> Co-authored-by: Nikita Glazov <nglazov@gmail.com> Co-authored-by: Tritin Truong <tritin_truong@yahoo.com> Co-authored-by: timbowl <54648082+timbowl@users.noreply.github.com> Co-authored-by: Rush Tehrani <r@onepanel.io> Co-authored-by: Dmitry Kalinin <chchchoon.dk@gmail.com> Co-authored-by: Tritin Truong <truongtritin98@gmail.com>
parent
42aad8b56b
commit
8bf647b360
@ -1,3 +1,4 @@
|
|||||||
exclude_paths:
|
exclude_paths:
|
||||||
- '**/3rdparty/**'
|
- '**/3rdparty/**'
|
||||||
- '**/engine/js/cvat-core.min.js'
|
- '**/engine/js/cvat-core.min.js'
|
||||||
|
- CHANGELOG.md
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
# EditorConfig helps developers define and maintain consistent
|
||||||
|
# coding styles between different editors and IDEs
|
||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
|
||||||
|
# Change these settings to your own preference
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# We recommend you to keep these unchanged
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
@ -0,0 +1 @@
|
|||||||
|
PYTHONPATH="datumaro/:$PYTHONPATH"
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
FROM cvat
|
||||||
|
|
||||||
|
ENV DJANGO_CONFIGURATION=testing
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
|
||||||
|
echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \
|
||||||
|
curl https://deb.nodesource.com/setup_9.x | bash - && \
|
||||||
|
apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||||
|
google-chrome-stable \
|
||||||
|
nodejs && \
|
||||||
|
rm -rf /var/lib/apt/lists/*;
|
||||||
|
|
||||||
|
RUN python3 -m pip install --no-cache-dir -r /tmp/requirements/${DJANGO_CONFIGURATION}.txt
|
||||||
|
|
||||||
|
# RUN all commands below as 'django' user
|
||||||
|
USER ${USER}
|
||||||
|
|
||||||
|
RUN mkdir -p tests && cd tests && npm install \
|
||||||
|
eslint \
|
||||||
|
eslint-detailed-reporter \
|
||||||
|
karma \
|
||||||
|
karma-chrome-launcher \
|
||||||
|
karma-coveralls \
|
||||||
|
karma-coverage \
|
||||||
|
karma-junit-reporter \
|
||||||
|
karma-qunit \
|
||||||
|
qunit; \
|
||||||
|
echo "export PATH=~/tests/node_modules/.bin:${PATH}" >> ~/.bashrc;
|
||||||
|
|
||||||
|
ENTRYPOINT []
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
FROM node:lts-alpine AS cvat-ui
|
||||||
|
|
||||||
|
ARG http_proxy
|
||||||
|
ARG https_proxy
|
||||||
|
ARG no_proxy
|
||||||
|
ARG socks_proxy
|
||||||
|
|
||||||
|
ENV TERM=xterm \
|
||||||
|
http_proxy=${http_proxy} \
|
||||||
|
https_proxy=${https_proxy} \
|
||||||
|
no_proxy=${no_proxy} \
|
||||||
|
socks_proxy=${socks_proxy}
|
||||||
|
|
||||||
|
ENV LANG='C.UTF-8' \
|
||||||
|
LC_ALL='C.UTF-8'
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
COPY cvat-core/package*.json /tmp/cvat-core/
|
||||||
|
COPY cvat-canvas/package*.json /tmp/cvat-canvas/
|
||||||
|
COPY cvat-ui/package*.json /tmp/cvat-ui/
|
||||||
|
|
||||||
|
# Install cvat-core dependencies
|
||||||
|
WORKDIR /tmp/cvat-core/
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Install cvat-canvas dependencies
|
||||||
|
WORKDIR /tmp/cvat-canvas/
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Install cvat-ui dependencies
|
||||||
|
WORKDIR /tmp/cvat-ui/
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Build source code
|
||||||
|
COPY cvat-core/ /tmp/cvat-core/
|
||||||
|
COPY cvat-canvas/ /tmp/cvat-canvas/
|
||||||
|
COPY cvat-ui/ /tmp/cvat-ui/
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
# Replace default.conf configuration to remove unnecessary rules
|
||||||
|
COPY cvat-ui/react_nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY --from=cvat-ui /tmp/cvat-ui/dist /usr/share/nginx/html/
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
## [Keras+Tensorflow Mask R-CNN Segmentation](https://github.com/matterport/Mask_RCNN)
|
||||||
|
|
||||||
|
### What is it?
|
||||||
|
- This application allows you automatically to segment many various objects on images.
|
||||||
|
- It's based on Feature Pyramid Network (FPN) and a ResNet101 backbone.
|
||||||
|
|
||||||
|
- It uses a pre-trained model on MS COCO dataset
|
||||||
|
- It supports next classes (use them in "labels" row):
|
||||||
|
```python
|
||||||
|
'BG', 'person', 'bicycle', 'car', 'motorcycle', 'airplane',
|
||||||
|
'bus', 'train', 'truck', 'boat', 'traffic light',
|
||||||
|
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird',
|
||||||
|
'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear',
|
||||||
|
'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie',
|
||||||
|
'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
|
||||||
|
'kite', 'baseball bat', 'baseball glove', 'skateboard',
|
||||||
|
'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup',
|
||||||
|
'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
|
||||||
|
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
|
||||||
|
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed',
|
||||||
|
'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
|
||||||
|
'keyboard', 'cell phone', 'microwave', 'oven', 'toaster',
|
||||||
|
'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors',
|
||||||
|
'teddy bear', 'hair drier', 'toothbrush'.
|
||||||
|
```
|
||||||
|
- Component adds "Run Auto Segmentation" button into dashboard.
|
||||||
|
|
||||||
|
### Build docker image
|
||||||
|
```bash
|
||||||
|
# From project root directory
|
||||||
|
docker-compose -f docker-compose.yml -f components/auto_segmentation/docker-compose.auto_segmentation.yml build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run docker container
|
||||||
|
```bash
|
||||||
|
# From project root directory
|
||||||
|
docker-compose -f docker-compose.yml -f components/auto_segmentation/docker-compose.auto_segmentation.yml up -d
|
||||||
|
```
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2018 Intel Corporation
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
version: "2.3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
cvat:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
AUTO_SEGMENTATION: "yes"
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
MASK_RCNN_URL=https://github.com/matterport/Mask_RCNN
|
||||||
|
|
||||||
|
cd ${HOME} && \
|
||||||
|
git clone ${MASK_RCNN_URL}.git && \
|
||||||
|
curl -L ${MASK_RCNN_URL}/releases/download/v2.0/mask_rcnn_coco.h5 -o Mask_RCNN/mask_rcnn_coco.h5
|
||||||
|
|
||||||
|
# TODO remove useless files
|
||||||
|
# tensorflow and Keras are installed globally
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (C) 2019-2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
module.exports = {
|
||||||
|
parser: false,
|
||||||
|
plugins: {
|
||||||
|
'postcss-preset-env': {
|
||||||
|
browsers: '> 2.5%', // https://github.com/browserslist/browserslist
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,145 @@
|
|||||||
|
// Copyright (C) 2019-2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import * as SVG from 'svg.js';
|
||||||
|
import consts from './consts';
|
||||||
|
|
||||||
|
import {
|
||||||
|
translateToSVG,
|
||||||
|
} from './shared';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Geometry,
|
||||||
|
} from './canvasModel';
|
||||||
|
|
||||||
|
|
||||||
|
export interface ZoomHandler {
|
||||||
|
zoom(): void;
|
||||||
|
cancel(): void;
|
||||||
|
transform(geometry: Geometry): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZoomHandlerImpl implements ZoomHandler {
|
||||||
|
private onZoomRegion: (x: number, y: number, width: number, height: number) => void;
|
||||||
|
private bindedOnSelectStart: (event: MouseEvent) => void;
|
||||||
|
private bindedOnSelectUpdate: (event: MouseEvent) => void;
|
||||||
|
private bindedOnSelectStop: (event: MouseEvent) => void;
|
||||||
|
private geometry: Geometry;
|
||||||
|
private canvas: SVG.Container;
|
||||||
|
private selectionRect: SVG.Rect | null;
|
||||||
|
private startSelectionPoint: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
private onSelectStart(event: MouseEvent): void {
|
||||||
|
if (!this.selectionRect && event.which === 1) {
|
||||||
|
const point = translateToSVG(
|
||||||
|
(this.canvas.node as any as SVGSVGElement),
|
||||||
|
[event.clientX, event.clientY],
|
||||||
|
);
|
||||||
|
this.startSelectionPoint = {
|
||||||
|
x: point[0],
|
||||||
|
y: point[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectionRect = this.canvas.rect().addClass('cvat_canvas_zoom_selection');
|
||||||
|
this.selectionRect.attr({
|
||||||
|
'stroke-width': consts.BASE_STROKE_WIDTH / this.geometry.scale,
|
||||||
|
...this.startSelectionPoint,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSelectionBox(event: MouseEvent): {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
} {
|
||||||
|
const point = translateToSVG(
|
||||||
|
(this.canvas.node as any as SVGSVGElement),
|
||||||
|
[event.clientX, event.clientY],
|
||||||
|
);
|
||||||
|
const stopSelectionPoint = {
|
||||||
|
x: point[0],
|
||||||
|
y: point[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
const xtl = Math.min(this.startSelectionPoint.x, stopSelectionPoint.x);
|
||||||
|
const ytl = Math.min(this.startSelectionPoint.y, stopSelectionPoint.y);
|
||||||
|
const xbr = Math.max(this.startSelectionPoint.x, stopSelectionPoint.x);
|
||||||
|
const ybr = Math.max(this.startSelectionPoint.y, stopSelectionPoint.y);
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: xtl,
|
||||||
|
y: ytl,
|
||||||
|
width: xbr - xtl,
|
||||||
|
height: ybr - ytl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSelectUpdate(event: MouseEvent): void {
|
||||||
|
if (this.selectionRect) {
|
||||||
|
this.selectionRect.attr({
|
||||||
|
...this.getSelectionBox(event),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSelectStop(event: MouseEvent): void {
|
||||||
|
if (this.selectionRect) {
|
||||||
|
const box = this.getSelectionBox(event);
|
||||||
|
this.selectionRect.remove();
|
||||||
|
this.selectionRect = null;
|
||||||
|
this.startSelectionPoint = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
const threshold = 5;
|
||||||
|
if (box.width > threshold && box.height > threshold) {
|
||||||
|
this.onZoomRegion(box.x, box.y, box.width, box.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
onZoomRegion: (x: number, y: number, width: number, height: number) => void,
|
||||||
|
canvas: SVG.Container,
|
||||||
|
geometry: Geometry,
|
||||||
|
) {
|
||||||
|
this.onZoomRegion = onZoomRegion;
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.geometry = geometry;
|
||||||
|
this.selectionRect = null;
|
||||||
|
this.startSelectionPoint = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
this.bindedOnSelectStart = this.onSelectStart.bind(this);
|
||||||
|
this.bindedOnSelectUpdate = this.onSelectUpdate.bind(this);
|
||||||
|
this.bindedOnSelectStop = this.onSelectStop.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public zoom(): void {
|
||||||
|
this.canvas.node.addEventListener('mousedown', this.bindedOnSelectStart);
|
||||||
|
this.canvas.node.addEventListener('mousemove', this.bindedOnSelectUpdate);
|
||||||
|
this.canvas.node.addEventListener('mouseup', this.bindedOnSelectStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public cancel(): void {
|
||||||
|
this.canvas.node.removeEventListener('mousedown', this.bindedOnSelectStart);
|
||||||
|
this.canvas.node.removeEventListener('mousemove', this.bindedOnSelectUpdate);
|
||||||
|
this.canvas.node.removeEventListener('mouseup ', this.bindedOnSelectStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public transform(geometry: Geometry): void {
|
||||||
|
this.geometry = geometry;
|
||||||
|
if (this.selectionRect) {
|
||||||
|
this.selectionRect.style({
|
||||||
|
'stroke-width': consts.BASE_STROKE_WIDTH / geometry.scale,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
/dist
|
||||||
|
/docs
|
||||||
|
/node_modules
|
||||||
|
/reports
|
||||||
|
|
||||||
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* global
|
||||||
|
require:false
|
||||||
|
*/
|
||||||
|
|
||||||
|
const jsonpath = require('jsonpath');
|
||||||
|
const { AttributeType } = require('./enums');
|
||||||
|
const { ArgumentError } = require('./exceptions');
|
||||||
|
|
||||||
|
|
||||||
|
class AnnotationsFilter {
|
||||||
|
constructor() {
|
||||||
|
// eslint-disable-next-line security/detect-unsafe-regex
|
||||||
|
this.operatorRegex = /(==|!=|<=|>=|>|<|~=)(?=(?:[^"]*(["])[^"]*\2)*[^"]*$)/g;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method splits expression by operators that are outside of any brackets
|
||||||
|
_splitWithOperator(container, expression) {
|
||||||
|
const operators = ['|', '&'];
|
||||||
|
const splitted = [];
|
||||||
|
let nestedCounter = 0;
|
||||||
|
let isQuotes = false;
|
||||||
|
let start = -1;
|
||||||
|
|
||||||
|
for (let i = 0; i < expression.length; i++) {
|
||||||
|
if (expression[i] === '"') {
|
||||||
|
// all quotes inside other quotes must
|
||||||
|
// be escaped by a user and changed to ` above
|
||||||
|
isQuotes = !isQuotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't split with operator inside brackets
|
||||||
|
// It will be done later in recursive call
|
||||||
|
if (!isQuotes && expression[i] === '(') {
|
||||||
|
nestedCounter++;
|
||||||
|
}
|
||||||
|
if (!isQuotes && expression[i] === ')') {
|
||||||
|
nestedCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operators.includes(expression[i])) {
|
||||||
|
if (!nestedCounter) {
|
||||||
|
const subexpression = expression
|
||||||
|
.substr(start + 1, i - start - 1).trim();
|
||||||
|
splitted.push(subexpression);
|
||||||
|
splitted.push(expression[i]);
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const subexpression = expression
|
||||||
|
.substr(start + 1).trim();
|
||||||
|
splitted.push(subexpression);
|
||||||
|
|
||||||
|
splitted.forEach((internalExpression) => {
|
||||||
|
if (internalExpression === '|' || internalExpression === '&') {
|
||||||
|
container.push(internalExpression);
|
||||||
|
} else {
|
||||||
|
this._groupByBrackets(
|
||||||
|
container,
|
||||||
|
internalExpression,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method groups bracket containings to nested arrays of container
|
||||||
|
_groupByBrackets(container, expression) {
|
||||||
|
if (!(expression.startsWith('(') && expression.endsWith(')'))) {
|
||||||
|
container.push(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
let nestedCounter = 0;
|
||||||
|
let startBracket = null;
|
||||||
|
let endBracket = null;
|
||||||
|
let isQuotes = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < expression.length; i++) {
|
||||||
|
if (expression[i] === '"') {
|
||||||
|
// all quotes inside other quotes must
|
||||||
|
// be escaped by a user and changed to ` above
|
||||||
|
isQuotes = !isQuotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isQuotes && expression[i] === '(') {
|
||||||
|
nestedCounter++;
|
||||||
|
if (startBracket === null) {
|
||||||
|
startBracket = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isQuotes && expression[i] === ')') {
|
||||||
|
nestedCounter--;
|
||||||
|
if (!nestedCounter) {
|
||||||
|
endBracket = i;
|
||||||
|
|
||||||
|
const subcontainer = [];
|
||||||
|
const subexpression = expression
|
||||||
|
.substr(startBracket + 1, endBracket - 1 - startBracket);
|
||||||
|
this._splitWithOperator(
|
||||||
|
subcontainer,
|
||||||
|
subexpression,
|
||||||
|
);
|
||||||
|
|
||||||
|
container.push(subcontainer);
|
||||||
|
|
||||||
|
startBracket = null;
|
||||||
|
endBracket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startBracket !== null) {
|
||||||
|
throw Error('Extra opening bracket found');
|
||||||
|
}
|
||||||
|
if (endBracket !== null) {
|
||||||
|
throw Error('Extra closing bracket found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse(expression) {
|
||||||
|
const groups = [];
|
||||||
|
this._splitWithOperator(groups, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
_join(groups) {
|
||||||
|
let expression = '';
|
||||||
|
for (const group of groups) {
|
||||||
|
if (Array.isArray(group)) {
|
||||||
|
expression += `(${this._join(group)})`;
|
||||||
|
} else if (typeof (group) === 'string') {
|
||||||
|
// it can be operator or expression
|
||||||
|
if (group === '|' || group === '&') {
|
||||||
|
expression += group;
|
||||||
|
} else {
|
||||||
|
let [field, operator, , value] = group.split(this.operatorRegex);
|
||||||
|
field = `@.${field.trim()}`;
|
||||||
|
operator = operator.trim();
|
||||||
|
value = value.trim();
|
||||||
|
if (value === 'width' || value === 'height' || value.startsWith('attr')) {
|
||||||
|
value = `@.${value}`;
|
||||||
|
}
|
||||||
|
expression += [field, operator, value].join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
_convertObjects(statesData) {
|
||||||
|
const objects = statesData.map((state) => {
|
||||||
|
const labelAttributes = state.label.attributes
|
||||||
|
.reduce((acc, attr) => {
|
||||||
|
acc[attr.id] = attr;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
let xtl = Number.MAX_SAFE_INTEGER;
|
||||||
|
let xbr = Number.MIN_SAFE_INTEGER;
|
||||||
|
let ytl = Number.MAX_SAFE_INTEGER;
|
||||||
|
let ybr = Number.MIN_SAFE_INTEGER;
|
||||||
|
|
||||||
|
state.points.forEach((coord, idx) => {
|
||||||
|
if (idx % 2) { // y
|
||||||
|
ytl = Math.min(ytl, coord);
|
||||||
|
ybr = Math.max(ybr, coord);
|
||||||
|
} else { // x
|
||||||
|
xtl = Math.min(xtl, coord);
|
||||||
|
xbr = Math.max(xbr, coord);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [width, height] = [xbr - xtl, ybr - ytl];
|
||||||
|
const attributes = {};
|
||||||
|
Object.keys(state.attributes).reduce((acc, key) => {
|
||||||
|
const attr = labelAttributes[key];
|
||||||
|
let value = state.attributes[key].replace(/\\"/g, '`');
|
||||||
|
if (attr.inputType === AttributeType.NUMBER) {
|
||||||
|
value = +value;
|
||||||
|
} else if (attr.inputType === AttributeType.CHECKBOX) {
|
||||||
|
value = value === 'true';
|
||||||
|
}
|
||||||
|
acc[attr.name] = value;
|
||||||
|
return acc;
|
||||||
|
}, attributes);
|
||||||
|
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
attr: attributes,
|
||||||
|
label: state.label.name.replace(/\\"/g, '`'),
|
||||||
|
serverID: state.serverID,
|
||||||
|
clientID: state.clientID,
|
||||||
|
type: state.objectType,
|
||||||
|
shape: state.objectShape,
|
||||||
|
occluded: state.occluded,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
objects,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSONQuery(filters) {
|
||||||
|
try {
|
||||||
|
if (!Array.isArray(filters) || filters.some((value) => typeof (value) !== 'string')) {
|
||||||
|
throw Error('Argument must be an array of strings');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filters.length) {
|
||||||
|
return [[], '$.objects[*].clientID'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const groups = [];
|
||||||
|
const expression = filters.map((filter) => `(${filter})`).join('|').replace(/\\"/g, '`');
|
||||||
|
this._splitWithOperator(groups, expression);
|
||||||
|
return [groups, `$.objects[?(${this._join(groups)})].clientID`];
|
||||||
|
} catch (error) {
|
||||||
|
throw new ArgumentError(`Wrong filter expression. ${error.toString()}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(statesData, query) {
|
||||||
|
try {
|
||||||
|
const objects = this._convertObjects(statesData);
|
||||||
|
return jsonpath.query(objects, query);
|
||||||
|
} catch (error) {
|
||||||
|
throw new ArgumentError(`Could not apply the filter. ${error.toString()}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AnnotationsFilter;
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019-2020 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
const MAX_HISTORY_LENGTH = 128;
|
||||||
|
|
||||||
|
class AnnotationHistory {
|
||||||
|
constructor() {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return {
|
||||||
|
undo: this._undo.map((undo) => undo.action),
|
||||||
|
redo: this._redo.map((redo) => redo.action),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
do(action, undo, redo, clientIDs) {
|
||||||
|
const actionItem = {
|
||||||
|
clientIDs,
|
||||||
|
action,
|
||||||
|
undo,
|
||||||
|
redo,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._undo = this._undo.slice(-MAX_HISTORY_LENGTH + 1);
|
||||||
|
this._undo.push(actionItem);
|
||||||
|
this._redo = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
undo(count) {
|
||||||
|
const affectedObjects = [];
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const action = this._undo.pop();
|
||||||
|
if (action) {
|
||||||
|
action.undo();
|
||||||
|
this._redo.push(action);
|
||||||
|
affectedObjects.push(...action.clientIDs);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affectedObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
redo(count) {
|
||||||
|
const affectedObjects = [];
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const action = this._redo.pop();
|
||||||
|
if (action) {
|
||||||
|
action.redo();
|
||||||
|
this._undo.push(action);
|
||||||
|
affectedObjects.push(...action.clientIDs);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affectedObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this._undo = [];
|
||||||
|
this._redo = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AnnotationHistory;
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2020 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* global
|
||||||
|
require:false
|
||||||
|
jest:false
|
||||||
|
describe:false
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Setup mock for a server
|
||||||
|
jest.mock('../../src/server-proxy', () => {
|
||||||
|
const mock = require('../mocks/server-proxy.mock');
|
||||||
|
return mock;
|
||||||
|
});
|
||||||
|
|
||||||
|
const AnnotationsFilter = require('../../src/annotations-filter');
|
||||||
|
// Initialize api
|
||||||
|
window.cvat = require('../../src/api');
|
||||||
|
|
||||||
|
// Test cases
|
||||||
|
describe('Feature: toJSONQuery', () => {
|
||||||
|
test('convert filters to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [groups, query] = annotationsFilter.toJSONQuery([]);
|
||||||
|
expect(Array.isArray(groups)).toBeTruthy();
|
||||||
|
expect(typeof (query)).toBe('string');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert empty fitlers to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [, query] = annotationsFilter.toJSONQuery([]);
|
||||||
|
expect(query).toBe('$.objects[*].clientID');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert wrong fitlers (empty string) to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
expect(() => {
|
||||||
|
annotationsFilter.toJSONQuery(['']);
|
||||||
|
}).toThrow(window.cvat.exceptions.ArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert wrong fitlers (wrong number argument) to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
expect(() => {
|
||||||
|
annotationsFilter.toJSONQuery(1);
|
||||||
|
}).toThrow(window.cvat.exceptions.ArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert wrong fitlers (wrong array argument) to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
expect(() => {
|
||||||
|
annotationsFilter.toJSONQuery(['clientID ==6', 1]);
|
||||||
|
}).toThrow(window.cvat.exceptions.ArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert wrong filters (wrong expression) to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
expect(() => {
|
||||||
|
annotationsFilter.toJSONQuery(['clientID=5']);
|
||||||
|
}).toThrow(window.cvat.exceptions.ArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert filters to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [groups, query] = annotationsFilter
|
||||||
|
.toJSONQuery(['clientID==5 & shape=="rectangle" & label==["car"]']);
|
||||||
|
expect(groups).toEqual([
|
||||||
|
['clientID==5', '&', 'shape=="rectangle"', '&', 'label==["car"]'],
|
||||||
|
]);
|
||||||
|
expect(query).toBe('$.objects[?((@.clientID==5&@.shape=="rectangle"&@.label==["car"]))].clientID');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert filters to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [groups, query] = annotationsFilter
|
||||||
|
.toJSONQuery(['label=="car" | width >= height & type=="track"']);
|
||||||
|
expect(groups).toEqual([
|
||||||
|
['label=="car"', '|', 'width >= height', '&', 'type=="track"'],
|
||||||
|
]);
|
||||||
|
expect(query).toBe('$.objects[?((@.label=="car"|@.width>=@.height&@.type=="track"))].clientID');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert filters to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [groups, query] = annotationsFilter
|
||||||
|
.toJSONQuery(['label=="person" & attr["Attribute 1"] ==attr["Attribute 2"]']);
|
||||||
|
expect(groups).toEqual([
|
||||||
|
['label=="person"', '&', 'attr["Attribute 1"] ==attr["Attribute 2"]'],
|
||||||
|
]);
|
||||||
|
expect(query).toBe('$.objects[?((@.label=="person"&@.attr["Attribute 1"]==@.attr["Attribute 2"]))].clientID');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert filters to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [groups, query] = annotationsFilter
|
||||||
|
.toJSONQuery(['label=="car" & attr["parked"]==true', 'label=="pedestrian" & width > 150']);
|
||||||
|
expect(groups).toEqual([
|
||||||
|
['label=="car"', '&', 'attr["parked"]==true'],
|
||||||
|
'|',
|
||||||
|
['label=="pedestrian"', '&', 'width > 150'],
|
||||||
|
]);
|
||||||
|
expect(query).toBe('$.objects[?((@.label=="car"&@.attr["parked"]==true)|(@.label=="pedestrian"&@.width>150))].clientID');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert filters to a json query', () => {
|
||||||
|
const annotationsFilter = new AnnotationsFilter();
|
||||||
|
const [groups, query] = annotationsFilter
|
||||||
|
.toJSONQuery(['(( label==["car \\"mazda\\""]) & (attr["sunglass ( help ) es"]==true | (width > 150 | height > 150 & (clientID == serverID))))) ']);
|
||||||
|
expect(groups).toEqual([[[
|
||||||
|
['label==["car `mazda`"]'],
|
||||||
|
'&',
|
||||||
|
['attr["sunglass ( help ) es"]==true', '|',
|
||||||
|
['width > 150', '|', 'height > 150', '&',
|
||||||
|
[
|
||||||
|
'clientID == serverID',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]]]);
|
||||||
|
expect(query).toBe('$.objects[?((((@.label==["car `mazda`"])&(@.attr["sunglass ( help ) es"]==true|(@.width>150|@.height>150&(@.clientID==serverID))))))].clientID');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,2 +1 @@
|
|||||||
build
|
/node_modules
|
||||||
node_modules
|
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
REACT_APP_VERSION=${npm_package_version}
|
|
||||||
|
|
||||||
REACT_APP_API_PROTOCOL=http
|
|
||||||
REACT_APP_API_HOST=localhost
|
|
||||||
REACT_APP_API_PORT=8080
|
|
||||||
REACT_APP_API_HOST_URL=${REACT_APP_API_PROTOCOL}://${REACT_APP_API_HOST}:${REACT_APP_API_PORT}
|
|
||||||
REACT_APP_API_FULL_URL=${REACT_APP_API_PROTOCOL}://${REACT_APP_API_HOST}:${REACT_APP_API_PORT}/api/v1
|
|
||||||
|
|
||||||
SKIP_PREFLIGHT_CHECK=true
|
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
'env': {
|
||||||
|
'node': true,
|
||||||
|
'browser': true,
|
||||||
|
'es6': true,
|
||||||
|
},
|
||||||
|
'parserOptions': {
|
||||||
|
'parser': '@typescript-eslint/parser',
|
||||||
|
'ecmaVersion': 6,
|
||||||
|
'project': './tsconfig.json',
|
||||||
|
},
|
||||||
|
'plugins': [
|
||||||
|
'@typescript-eslint',
|
||||||
|
'import',
|
||||||
|
],
|
||||||
|
'ignorePatterns': ['*.svg', '*.scss'],
|
||||||
|
'extends': [
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'airbnb-typescript',
|
||||||
|
'plugin:import/errors',
|
||||||
|
'plugin:import/warnings',
|
||||||
|
'plugin:import/typescript',
|
||||||
|
],
|
||||||
|
'rules': {
|
||||||
|
'@typescript-eslint/indent': ['warn', 4],
|
||||||
|
'react/jsx-indent': ['warn', 4],
|
||||||
|
'react/jsx-indent-props': ['warn', 4],
|
||||||
|
'react/jsx-props-no-spreading': 0,
|
||||||
|
'jsx-quotes': ['error', 'prefer-single'],
|
||||||
|
'arrow-parens': ['error', 'always'],
|
||||||
|
'@typescript-eslint/no-explicit-any': [0],
|
||||||
|
'@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }],
|
||||||
|
'no-restricted-syntax': [0, {'selector': 'ForOfStatement'}],
|
||||||
|
'no-plusplus': [0],
|
||||||
|
'lines-between-class-members': 0,
|
||||||
|
'react/no-did-update-set-state': 0, // https://github.com/airbnb/javascript/issues/1875
|
||||||
|
},
|
||||||
|
'settings': {
|
||||||
|
'import/resolver': {
|
||||||
|
'typescript': {
|
||||||
|
'directory': './tsconfig.json'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,36 +0,0 @@
|
|||||||
FROM ubuntu:18.04 AS cvat-ui
|
|
||||||
|
|
||||||
ARG http_proxy
|
|
||||||
ARG https_proxy
|
|
||||||
ARG no_proxy
|
|
||||||
ARG socks_proxy
|
|
||||||
|
|
||||||
ENV TERM=xterm \
|
|
||||||
http_proxy=${http_proxy} \
|
|
||||||
https_proxy=${https_proxy} \
|
|
||||||
no_proxy=${no_proxy} \
|
|
||||||
socks_proxy=${socks_proxy}
|
|
||||||
|
|
||||||
ENV LANG='C.UTF-8' \
|
|
||||||
LC_ALL='C.UTF-8'
|
|
||||||
|
|
||||||
# Install necessary apt packages
|
|
||||||
RUN apt update && apt install -yq nodejs npm curl && \
|
|
||||||
npm install -g n && n 10.16.3
|
|
||||||
|
|
||||||
# Create output directory
|
|
||||||
RUN mkdir /tmp/cvat-ui
|
|
||||||
WORKDIR /tmp/cvat-ui/
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
COPY package*.json /tmp/cvat-ui/
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Build source code
|
|
||||||
COPY . /tmp/cvat-ui/
|
|
||||||
RUN mv .env.production .env && npm run build
|
|
||||||
|
|
||||||
FROM nginx
|
|
||||||
# Replace default.conf configuration to remove unnecessary rules
|
|
||||||
COPY react_nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
COPY --from=cvat-ui /tmp/cvat-ui/build /usr/share/nginx/html/
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
const { override, fixBabelImports, addLessLoader } = require('customize-cra');
|
|
||||||
|
|
||||||
module.exports = override(
|
|
||||||
fixBabelImports('import', {
|
|
||||||
libraryName: 'antd',
|
|
||||||
libraryDirectory: 'es',
|
|
||||||
style: true,
|
|
||||||
}),
|
|
||||||
|
|
||||||
addLessLoader({
|
|
||||||
javascriptEnabled: true,
|
|
||||||
// modifyVars: { '@primary-color': '#1DA57A' },
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
@ -0,0 +1,5 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
declare module '*.svg';
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,56 +1,74 @@
|
|||||||
{
|
{
|
||||||
"name": "cvat-ui",
|
"name": "cvat-ui",
|
||||||
"version": "0.1.0",
|
"version": "0.5.2",
|
||||||
|
"description": "CVAT single-page application",
|
||||||
|
"main": "src/index.tsx",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --config ./webpack.config.js",
|
||||||
|
"start": "REACT_APP_API_URL=http://localhost:7000 webpack-dev-server --config ./webpack.config.js --mode=development",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"type-check:watch": "npm run type-check -- --watch",
|
||||||
|
"lint": "eslint './src/**/*.{ts,tsx}'",
|
||||||
|
"lint:fix": "eslint './src/**/*.{ts,tsx}' --fix"
|
||||||
|
},
|
||||||
|
"author": "Intel",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.6.0",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
||||||
|
"@babel/preset-env": "^7.6.0",
|
||||||
|
"@babel/preset-react": "^7.0.0",
|
||||||
|
"@babel/preset-typescript": "^7.6.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.19.2",
|
||||||
|
"@typescript-eslint/parser": "^2.19.2",
|
||||||
|
"babel-loader": "^8.0.6",
|
||||||
|
"babel-plugin-import": "^1.12.2",
|
||||||
|
"css-loader": "^3.2.0",
|
||||||
|
"eslint": "^6.8.0",
|
||||||
|
"eslint-config-airbnb-typescript": "^7.0.0",
|
||||||
|
"eslint-import-resolver-typescript": "^2.0.0",
|
||||||
|
"eslint-plugin-import": "^2.18.2",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||||
|
"eslint-plugin-react": "^7.17.0",
|
||||||
|
"eslint-plugin-react-hooks": "^1.7.0",
|
||||||
|
"html-webpack-plugin": "^3.2.0",
|
||||||
|
"less": "^3.10.3",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"node-sass": "^4.13.0",
|
||||||
|
"postcss-loader": "^3.0.0",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"react-svg-loader": "^3.0.3",
|
||||||
|
"sass-loader": "^8.0.0",
|
||||||
|
"style-loader": "^1.0.0",
|
||||||
|
"tsconfig-paths-webpack-plugin": "^3.2.0",
|
||||||
|
"typescript": "^3.7.3",
|
||||||
|
"webpack": "^4.41.2",
|
||||||
|
"webpack-cli": "^3.3.8",
|
||||||
|
"webpack-dev-server": "^3.8.0"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/jest": "24.0.13",
|
"@types/react": "^16.9.2",
|
||||||
"@types/node": "^12.0.3",
|
"@types/react-dom": "^16.9.0",
|
||||||
"@types/react": "16.8.19",
|
"@types/react-redux": "^7.1.2",
|
||||||
"@types/react-dom": "16.8.4",
|
"@types/react-router": "^5.0.5",
|
||||||
"@types/react-redux": "^7.1.1",
|
"@types/react-router-dom": "^5.1.0",
|
||||||
"@types/react-router-dom": "^4.3.4",
|
"@types/react-share": "^3.0.1",
|
||||||
"@types/redux-logger": "^3.0.7",
|
"@types/redux-logger": "^3.0.7",
|
||||||
"antd": "^3.19.1",
|
"antd": "^3.25.2",
|
||||||
"babel-plugin-import": "^1.11.2",
|
"copy-to-clipboard": "^3.2.0",
|
||||||
"customize-cra": "^0.2.12",
|
"dotenv-webpack": "^1.7.0",
|
||||||
"less": "^3.9.0",
|
"moment": "^2.24.0",
|
||||||
"less-loader": "^5.0.0",
|
"prop-types": "^15.7.2",
|
||||||
"node-sass": "^4.12.0",
|
"react": "^16.9.0",
|
||||||
"query-string": "^6.8.1",
|
"react-dom": "^16.9.0",
|
||||||
"react": "^16.8.6",
|
"react-hotkeys": "^2.0.0",
|
||||||
"react-app-rewired": "^2.1.3",
|
"react-redux": "^7.1.1",
|
||||||
"react-dom": "^16.8.6",
|
"react-router": "^5.1.0",
|
||||||
"react-redux": "^7.1.0",
|
"react-router-dom": "^5.1.0",
|
||||||
"react-router-dom": "^5.0.1",
|
"react-share": "^3.0.1",
|
||||||
"react-scripts": "3.0.1",
|
|
||||||
"react-scripts-ts": "^3.1.0",
|
|
||||||
"redux": "^4.0.4",
|
"redux": "^4.0.4",
|
||||||
|
"redux-devtools-extension": "^2.13.8",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0"
|
||||||
"source-map-explorer": "^1.8.0",
|
|
||||||
"typescript": "3.4.5"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
|
||||||
"start": "react-app-rewired start",
|
|
||||||
"build": "react-app-rewired build",
|
|
||||||
"test": "react-app-rewired test",
|
|
||||||
"eject": "react-scripts eject"
|
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"extends": "react-app"
|
|
||||||
},
|
|
||||||
"browserslist": {
|
|
||||||
"production": [
|
|
||||||
">0.2%",
|
|
||||||
"not dead",
|
|
||||||
"not op_mini all"
|
|
||||||
],
|
|
||||||
"development": [
|
|
||||||
"last 1 chrome version",
|
|
||||||
"last 1 firefox version",
|
|
||||||
"last 1 safari version"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
module.exports = {
|
||||||
|
parser: false,
|
||||||
|
plugins: {
|
||||||
|
'postcss-preset-env': {
|
||||||
|
browsers: '> 2.5%', // https://github.com/browserslist/browserslist
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
@ -1 +0,0 @@
|
|||||||
<svg width="98" height="27" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M101 0v29l-52.544.001C44.326 35.511 35.598 40 25.5 40 11.417 40 0 31.27 0 20.5S11.417 1 25.5 1c4.542 0 8.807.908 12.5 2.5V0h63z" id="a"/></defs><g transform="translate(-2 -1)" fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><path d="M48.142 1c4.736 0 6.879 3.234 6.879 5.904v2.068h-4.737V6.904c0-.79-.789-2.144-2.142-2.144-1.654 0-2.368 1.354-2.368 2.144v15.192c0 .79.714 2.144 2.368 2.144 1.353 0 2.142-1.354 2.142-2.144v-2.068h4.737v2.068c0 2.67-2.143 5.904-6.88 5.904C42.956 28 41 24.766 41 22.134V6.904C41 4.234 42.955 1 48.142 1zM19-6c9.389 0 17 7.611 17 17s-7.611 17-17 17S2 20.389 2 11 9.611-6 19-6zm42.256 7.338l3.345 19.48h.075l3.42-19.48h5l-6.052 26.324h-5L56.22 1.338h5.037zm20.706 0l5.413 26.324h-4.699l-.94-6.13h-4.548l-.902 6.13h-4.435l5.413-26.324h4.698zm18.038 0v3.723h-4.849v22.6h-4.699v-22.6h-4.81V1.338H100zM19 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zm60.557 4.295h-.113l-1.466 9.439h3.007l-1.428-9.439z" fill="#000" fill-rule="nonzero" mask="url(#b)"/></g></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1 +0,0 @@
|
|||||||
<svg width="90" height="78" xmlns="http://www.w3.org/2000/svg"><path d="M84.27 0c2.753 0 5.007 2.167 5.12 4.874l.005.215v67.148c0 2.734-2.183 4.972-4.908 5.085l-.217.004H5.123c-2.751 0-5.005-2.167-5.118-4.874L0 72.237V5.09C0 2.355 2.183.117 4.907.004L5.123 0H84.27zm1.58 16.242H3.546v55.995c0 .816.632 1.488 1.434 1.56l.144.007H84.27c.824 0 1.501-.627 1.574-1.424l.007-.143V16.242zM12.658 38.48h4.328c.59 0 1.076.452 1.138 1.031l.007.126v1.03h15.02v-1.03c0-.596.446-1.087 1.02-1.15l.125-.007h4.328c.59 0 1.076.451 1.138 1.03l.006.127v4.372c0 .596-.446 1.087-1.02 1.15l-.124.007h-1.02v10.548h1.019c.59 0 1.077.451 1.139 1.031l.006.126v4.372c0 .596-.446 1.087-1.02 1.15l-.125.007h-4.327a1.15 1.15 0 0 1-1.139-1.03l-.006-.127v-1.03H18.13v1.03c0 .596-.446 1.087-1.02 1.15l-.125.007h-4.328a1.15 1.15 0 0 1-1.138-1.03l-.007-.127v-4.372c0-.596.447-1.087 1.02-1.15l.125-.007h1.019V45.166h-1.02a1.15 1.15 0 0 1-1.138-1.03l-.006-.127v-4.372c0-.596.446-1.087 1.02-1.15l.125-.007h4.328zm3.183 19.548h-2.038v2.058h2.038v-2.058zm21.638 0h-2.039v2.058h2.039v-2.058zM33.15 42.98H18.13v1.03c0 .595-.447 1.087-1.02 1.15l-.125.006h-1.019v10.548h1.019c.59 0 1.076.451 1.138 1.031l.007.126V57.9h15.02V56.87c0-.596.446-1.087 1.02-1.15l.125-.007h1.019V45.166h-1.019a1.15 1.15 0 0 1-1.139-1.031l-.006-.126v-1.03zm21.575-7.62c.398 0 .72.338.72.755v.67h9.458v-.67c0-.417.323-.755.721-.755h2.725c.398 0 .72.338.72.754v2.852c0 .416-.322.754-.72.754h-.641v6.88h.64c.399 0 .722.337.722.754v2.852c0 .416-.323.754-.721.754h-2.725c-.398 0-.721-.338-.721-.754v-.672h-9.457v.672c0 .416-.322.754-.72.754H52c-.398 0-.72-.338-.72-.754v-2.852c0-.416.322-.754.72-.754h.642v-6.88H52c-.398 0-.72-.337-.72-.754v-2.851c0-.417.322-.755.72-.755zm-.72 12.749H52.72v1.342h1.283V48.11zm13.623 0h-1.283v1.342h1.283V48.11zm-2.725-9.814h-9.457v.671c0 .417-.323.755-.721.755h-.641V46.6h.641c.399 0 .721.337.721.754v.671h9.457v-.67c0-.417.323-.755.72-.755h.642v-6.88h-.64c-.4 0-.722-.338-.722-.754v-.671zm-49.063 2.5h-2.038v2.058h2.038v-2.058zm21.638-.001H35.44v2.058h2.038v-2.058zm30.15-3.925h-1.283v1.342h1.283V36.87zm-13.624 0h-1.283v1.343h1.283v-1.343zM9.098 19.76c.93 0 1.692.711 1.766 1.616l.006.145v.118c0 .973-.793 1.761-1.772 1.761-.93 0-1.693-.711-1.767-1.616l-.005-.145v-.118c0-.973.793-1.761 1.772-1.761zm21.65 0c.978 0 1.771.788 1.771 1.76 0 .974-.793 1.762-1.771 1.762H16.423c-.98 0-1.772-.788-1.772-1.761 0-.973.792-1.761 1.772-1.761h14.325zm13.988 0c.98 0 1.772.788 1.772 1.76 0 .974-.792 1.762-1.772 1.762h-5.29a1.768 1.768 0 0 1-1.772-1.761c0-.973.796-1.761 1.772-1.761h5.29zm9.868 0c.977 0 1.773.788 1.773 1.76 0 .974-.796 1.762-1.773 1.762H53.05a1.766 1.766 0 0 1-1.772-1.761c0-.973.793-1.761 1.772-1.761h1.553zm17.107 0c.977 0 1.772.788 1.772 1.76 0 .974-.795 1.762-1.772 1.762h-8.194c-.98 0-1.773-.788-1.773-1.761 0-.973.793-1.761 1.773-1.761h8.194zm12.56-16.238H5.122c-.82 0-1.5.628-1.572 1.424l-.006.143v7.631H85.85V5.09c0-.863-.709-1.567-1.58-1.567zM9.125 6.24c.98 0 1.772.787 1.772 1.76s-.793 1.761-1.772 1.761c-.977 0-1.8-.788-1.8-1.76 0-.974.761-1.761 1.741-1.761h.059zm7.354 0c.979 0 1.772.787 1.772 1.76s-.793 1.761-1.772 1.761c-.977 0-1.829-.788-1.829-1.76 0-.974.734-1.761 1.712-1.761h.117zm7.297 0c.977 0 1.773.787 1.773 1.76s-.796 1.761-1.773 1.761c-.979 0-1.8-.788-1.8-1.76 0-.974.764-1.761 1.743-1.761h.057z" fill="#9B9B9B" fill-rule="evenodd"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.3 KiB |
@ -1,40 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
|
||||||
-->
|
|
||||||
<title>CVAT</title>
|
|
||||||
|
|
||||||
<script src="./cvat-core.min.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
||||||
<div id="root"></div>
|
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"short_name": "CVAT",
|
|
||||||
"name": "Computer Vision Annotation Tool",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "favicon.ico",
|
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
|
||||||
"type": "image/x-icon"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"start_url": ".",
|
|
||||||
"display": "standalone",
|
|
||||||
"theme_color": "#000000",
|
|
||||||
"background_color": "#ffffff"
|
|
||||||
}
|
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
|
||||||
|
import getCore from 'cvat-core';
|
||||||
|
|
||||||
|
const core = getCore();
|
||||||
|
|
||||||
|
export enum AboutActionTypes {
|
||||||
|
GET_ABOUT = 'GET_ABOUT',
|
||||||
|
GET_ABOUT_SUCCESS = 'GET_ABOUT_SUCCESS',
|
||||||
|
GET_ABOUT_FAILED = 'GET_ABOUT_FAILED',
|
||||||
|
}
|
||||||
|
|
||||||
|
const aboutActions = {
|
||||||
|
getAbout: () => createAction(AboutActionTypes.GET_ABOUT),
|
||||||
|
getAboutSuccess: (server: any) => createAction(AboutActionTypes.GET_ABOUT_SUCCESS, { server }),
|
||||||
|
getAboutFailed: (error: any) => createAction(AboutActionTypes.GET_ABOUT_FAILED, { error }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AboutActions = ActionUnion<typeof aboutActions>;
|
||||||
|
|
||||||
|
export const getAboutAsync = (): ThunkAction => async (dispatch): Promise<void> => {
|
||||||
|
dispatch(aboutActions.getAbout());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const about = await core.server.about();
|
||||||
|
dispatch(
|
||||||
|
aboutActions.getAboutSuccess(about),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(aboutActions.getAboutFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,75 +0,0 @@
|
|||||||
import { Dispatch, ActionCreator } from 'redux';
|
|
||||||
|
|
||||||
|
|
||||||
export const dumpAnnotation = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'DUMP_ANNOTATION',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const dumpAnnotationSuccess = (downloadLink: string) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'DUMP_ANNOTATION_SUCCESS',
|
|
||||||
payload: downloadLink,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const dumpAnnotationError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'DUMP_ANNOTATION_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadAnnotation = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'UPLOAD_ANNOTATION',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadAnnotationSuccess = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'UPLOAD_ANNOTATION_SUCCESS',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadAnnotationError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'UPLOAD_ANNOTATION_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const dumpAnnotationAsync = (task: any, dumper: any) => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(dumpAnnotation());
|
|
||||||
|
|
||||||
return task.annotations.dump(task.name, dumper).then(
|
|
||||||
(downloadLink: string) => {
|
|
||||||
dispatch(dumpAnnotationSuccess(downloadLink));
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(dumpAnnotationError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadAnnotationAsync = (task: any, file: File, loader: any) => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(uploadAnnotation());
|
|
||||||
|
|
||||||
return task.annotations.upload(file, loader).then(
|
|
||||||
(response: any) => {
|
|
||||||
dispatch(uploadAnnotationSuccess());
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(uploadAnnotationError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
|
||||||
|
import getCore from 'cvat-core';
|
||||||
|
|
||||||
|
const cvat = getCore();
|
||||||
|
|
||||||
|
export enum AuthActionTypes {
|
||||||
|
AUTHORIZED_SUCCESS = 'AUTHORIZED_SUCCESS',
|
||||||
|
AUTHORIZED_FAILED = 'AUTHORIZED_FAILED',
|
||||||
|
LOGIN = 'LOGIN',
|
||||||
|
LOGIN_SUCCESS = 'LOGIN_SUCCESS',
|
||||||
|
LOGIN_FAILED = 'LOGIN_FAILED',
|
||||||
|
REGISTER = 'REGISTER',
|
||||||
|
REGISTER_SUCCESS = 'REGISTER_SUCCESS',
|
||||||
|
REGISTER_FAILED = 'REGISTER_FAILED',
|
||||||
|
LOGOUT = 'LOGOUT',
|
||||||
|
LOGOUT_SUCCESS = 'LOGOUT_SUCCESS',
|
||||||
|
LOGOUT_FAILED = 'LOGOUT_FAILED',
|
||||||
|
}
|
||||||
|
|
||||||
|
const authActions = {
|
||||||
|
authorizeSuccess: (user: any) => createAction(AuthActionTypes.AUTHORIZED_SUCCESS, { user }),
|
||||||
|
authorizeFailed: (error: any) => createAction(AuthActionTypes.AUTHORIZED_FAILED, { error }),
|
||||||
|
login: () => createAction(AuthActionTypes.LOGIN),
|
||||||
|
loginSuccess: (user: any) => createAction(AuthActionTypes.LOGIN_SUCCESS, { user }),
|
||||||
|
loginFailed: (error: any) => createAction(AuthActionTypes.LOGIN_FAILED, { error }),
|
||||||
|
register: () => createAction(AuthActionTypes.REGISTER),
|
||||||
|
registerSuccess: (user: any) => createAction(AuthActionTypes.REGISTER_SUCCESS, { user }),
|
||||||
|
registerFailed: (error: any) => createAction(AuthActionTypes.REGISTER_FAILED, { error }),
|
||||||
|
logout: () => createAction(AuthActionTypes.LOGOUT),
|
||||||
|
logoutSuccess: () => createAction(AuthActionTypes.LOGOUT_SUCCESS),
|
||||||
|
logoutFailed: (error: any) => createAction(AuthActionTypes.LOGOUT_FAILED, { error }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AuthActions = ActionUnion<typeof authActions>;
|
||||||
|
|
||||||
|
export const registerAsync = (
|
||||||
|
username: string,
|
||||||
|
firstName: string,
|
||||||
|
lastName: string,
|
||||||
|
email: string,
|
||||||
|
password1: string,
|
||||||
|
password2: string,
|
||||||
|
): ThunkAction => async (
|
||||||
|
dispatch,
|
||||||
|
) => {
|
||||||
|
dispatch(authActions.register());
|
||||||
|
|
||||||
|
try {
|
||||||
|
await cvat.server.register(username, firstName, lastName, email, password1, password2);
|
||||||
|
const users = await cvat.users.get({ self: true });
|
||||||
|
|
||||||
|
dispatch(authActions.registerSuccess(users[0]));
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(authActions.registerFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loginAsync = (username: string, password: string): ThunkAction => async (dispatch) => {
|
||||||
|
dispatch(authActions.login());
|
||||||
|
|
||||||
|
try {
|
||||||
|
await cvat.server.login(username, password);
|
||||||
|
const users = await cvat.users.get({ self: true });
|
||||||
|
|
||||||
|
dispatch(authActions.loginSuccess(users[0]));
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(authActions.loginFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const logoutAsync = (): ThunkAction => async (dispatch) => {
|
||||||
|
dispatch(authActions.logout());
|
||||||
|
|
||||||
|
try {
|
||||||
|
await cvat.server.logout();
|
||||||
|
dispatch(authActions.logoutSuccess());
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(authActions.logoutFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const authorizedAsync = (): ThunkAction => async (dispatch) => {
|
||||||
|
try {
|
||||||
|
const result = await cvat.server.authorized();
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
const userInstance = (await cvat.users.get({ self: true }))[0];
|
||||||
|
dispatch(authActions.authorizeSuccess(userInstance));
|
||||||
|
} else {
|
||||||
|
dispatch(authActions.authorizeSuccess(null));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(authActions.authorizeFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,172 +0,0 @@
|
|||||||
import { History } from 'history';
|
|
||||||
import { Dispatch, ActionCreator } from 'redux';
|
|
||||||
|
|
||||||
|
|
||||||
export const login = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'LOGIN',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loginSuccess = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'LOGIN_SUCCESS',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loginError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'LOGIN_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const logout = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'LOGOUT',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const logoutSuccess = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'LOGOUT_SUCCESS',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const logoutError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'LOGOUT_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isAuthenticated = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'IS_AUTHENTICATED',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isAuthenticatedSuccess = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'IS_AUTHENTICATED_SUCCESS',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isAuthenticatedFail = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'IS_AUTHENTICATED_FAIL',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isAuthenticatedError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'IS_AUTHENTICATED_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const register = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'REGISTER',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const registerSuccess = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'REGISTER_SUCCESS',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const registerError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'REGISTER_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loginAsync = (username: string, password: string, history: History) => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(login());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.login(username, password).then(
|
|
||||||
(loggedIn: any) => {
|
|
||||||
dispatch(loginSuccess());
|
|
||||||
|
|
||||||
history.push(history.location.state ? history.location.state.from : '/tasks');
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(loginError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const logoutAsync = () => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(logout());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.logout().then(
|
|
||||||
(loggedOut: any) => {
|
|
||||||
dispatch(logoutSuccess());
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(logoutError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isAuthenticatedAsync = () => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(isAuthenticated());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.authorized().then(
|
|
||||||
(isAuthenticated: boolean) => {
|
|
||||||
isAuthenticated ? dispatch(isAuthenticatedSuccess()) : dispatch(isAuthenticatedFail());
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(isAuthenticatedError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const registerAsync = (
|
|
||||||
username: string,
|
|
||||||
firstName: string,
|
|
||||||
lastName: string,
|
|
||||||
email: string,
|
|
||||||
password: string,
|
|
||||||
passwordConfirmation: string,
|
|
||||||
history: History,
|
|
||||||
) => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(register());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.register(
|
|
||||||
username,
|
|
||||||
firstName,
|
|
||||||
lastName,
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
passwordConfirmation,
|
|
||||||
).then(
|
|
||||||
(registered: any) => {
|
|
||||||
dispatch(registerSuccess());
|
|
||||||
|
|
||||||
history.replace('/login');
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(registerError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
|
||||||
|
import getCore from 'cvat-core';
|
||||||
|
|
||||||
|
const cvat = getCore();
|
||||||
|
|
||||||
|
export enum FormatsActionTypes {
|
||||||
|
GET_FORMATS = 'GET_FORMATS',
|
||||||
|
GET_FORMATS_SUCCESS = 'GET_FORMATS_SUCCESS',
|
||||||
|
GET_FORMATS_FAILED = 'GET_FORMATS_FAILED',
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatsActions = {
|
||||||
|
getFormats: () => createAction(FormatsActionTypes.GET_FORMATS),
|
||||||
|
getFormatsSuccess: (annotationFormats: any[], datasetFormats: any[]) => (
|
||||||
|
createAction(FormatsActionTypes.GET_FORMATS_SUCCESS, {
|
||||||
|
annotationFormats,
|
||||||
|
datasetFormats,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
getFormatsFailed: (error: any) => (
|
||||||
|
createAction(FormatsActionTypes.GET_FORMATS_FAILED, { error })
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FormatsActions = ActionUnion<typeof formatsActions>;
|
||||||
|
|
||||||
|
export function getFormatsAsync(): ThunkAction {
|
||||||
|
return async (dispatch): Promise<void> => {
|
||||||
|
dispatch(formatsActions.getFormats());
|
||||||
|
let annotationFormats = null;
|
||||||
|
let datasetFormats = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
annotationFormats = await cvat.server.formats();
|
||||||
|
datasetFormats = await cvat.server.datasetFormats();
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
formatsActions.getFormatsSuccess(annotationFormats, datasetFormats),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(formatsActions.getFormatsFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,547 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
|
||||||
|
import {
|
||||||
|
Model,
|
||||||
|
ModelType,
|
||||||
|
ModelFiles,
|
||||||
|
ActiveInference,
|
||||||
|
CombinedState,
|
||||||
|
} from 'reducers/interfaces';
|
||||||
|
import getCore from 'cvat-core';
|
||||||
|
|
||||||
|
export enum PreinstalledModels {
|
||||||
|
RCNN = 'RCNN Object Detector',
|
||||||
|
MaskRCNN = 'Mask RCNN Object Detector',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ModelsActionTypes {
|
||||||
|
GET_MODELS = 'GET_MODELS',
|
||||||
|
GET_MODELS_SUCCESS = 'GET_MODELS_SUCCESS',
|
||||||
|
GET_MODELS_FAILED = 'GET_MODELS_FAILED',
|
||||||
|
DELETE_MODEL = 'DELETE_MODEL',
|
||||||
|
DELETE_MODEL_SUCCESS = 'DELETE_MODEL_SUCCESS',
|
||||||
|
DELETE_MODEL_FAILED = 'DELETE_MODEL_FAILED',
|
||||||
|
CREATE_MODEL = 'CREATE_MODEL',
|
||||||
|
CREATE_MODEL_SUCCESS = 'CREATE_MODEL_SUCCESS',
|
||||||
|
CREATE_MODEL_FAILED = 'CREATE_MODEL_FAILED',
|
||||||
|
CREATE_MODEL_STATUS_UPDATED = 'CREATE_MODEL_STATUS_UPDATED',
|
||||||
|
START_INFERENCE_FAILED = 'START_INFERENCE_FAILED',
|
||||||
|
GET_INFERENCE_STATUS_SUCCESS = 'GET_INFERENCE_STATUS_SUCCESS',
|
||||||
|
GET_INFERENCE_STATUS_FAILED = 'GET_INFERENCE_STATUS_FAILED',
|
||||||
|
FETCH_META_FAILED = 'FETCH_META_FAILED',
|
||||||
|
SHOW_RUN_MODEL_DIALOG = 'SHOW_RUN_MODEL_DIALOG',
|
||||||
|
CLOSE_RUN_MODEL_DIALOG = 'CLOSE_RUN_MODEL_DIALOG',
|
||||||
|
CANCEL_INFERENCE_SUCCESS = 'CANCEL_INFERENCE_SUCCESS',
|
||||||
|
CANCEL_INFERENCE_FAILED = 'CANCEL_INFERENCE_FAILED',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const modelsActions = {
|
||||||
|
getModels: () => createAction(ModelsActionTypes.GET_MODELS),
|
||||||
|
getModelsSuccess: (models: Model[]) => createAction(
|
||||||
|
ModelsActionTypes.GET_MODELS_SUCCESS, {
|
||||||
|
models,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
getModelsFailed: (error: any) => createAction(
|
||||||
|
ModelsActionTypes.GET_MODELS_FAILED, {
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
deleteModelSuccess: (id: number) => createAction(
|
||||||
|
ModelsActionTypes.DELETE_MODEL_SUCCESS, {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
deleteModelFailed: (id: number, error: any) => createAction(
|
||||||
|
ModelsActionTypes.DELETE_MODEL_FAILED, {
|
||||||
|
error, id,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
createModel: () => createAction(ModelsActionTypes.CREATE_MODEL),
|
||||||
|
createModelSuccess: () => createAction(ModelsActionTypes.CREATE_MODEL_SUCCESS),
|
||||||
|
createModelFailed: (error: any) => createAction(
|
||||||
|
ModelsActionTypes.CREATE_MODEL_FAILED, {
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
createModelUpdateStatus: (status: string) => createAction(
|
||||||
|
ModelsActionTypes.CREATE_MODEL_STATUS_UPDATED, {
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
fetchMetaFailed: (error: any) => createAction(ModelsActionTypes.FETCH_META_FAILED, { error }),
|
||||||
|
getInferenceStatusSuccess: (taskID: number, activeInference: ActiveInference) => createAction(
|
||||||
|
ModelsActionTypes.GET_INFERENCE_STATUS_SUCCESS, {
|
||||||
|
taskID,
|
||||||
|
activeInference,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
getInferenceStatusFailed: (taskID: number, error: any) => createAction(
|
||||||
|
ModelsActionTypes.GET_INFERENCE_STATUS_FAILED, {
|
||||||
|
taskID,
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
startInferenceFailed: (taskID: number, error: any) => createAction(
|
||||||
|
ModelsActionTypes.START_INFERENCE_FAILED, {
|
||||||
|
taskID,
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
cancelInferenceSuccess: (taskID: number) => createAction(
|
||||||
|
ModelsActionTypes.CANCEL_INFERENCE_SUCCESS, {
|
||||||
|
taskID,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
cancelInferenceFaild: (taskID: number, error: any) => createAction(
|
||||||
|
ModelsActionTypes.CANCEL_INFERENCE_FAILED, {
|
||||||
|
taskID,
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
closeRunModelDialog: () => createAction(ModelsActionTypes.CLOSE_RUN_MODEL_DIALOG),
|
||||||
|
showRunModelDialog: (taskInstance: any) => createAction(
|
||||||
|
ModelsActionTypes.SHOW_RUN_MODEL_DIALOG, {
|
||||||
|
taskInstance,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ModelsActions = ActionUnion<typeof modelsActions>;
|
||||||
|
|
||||||
|
const core = getCore();
|
||||||
|
const baseURL = core.config.backendAPI.slice(0, -7);
|
||||||
|
|
||||||
|
export function getModelsAsync(): ThunkAction {
|
||||||
|
return async (dispatch, getState): Promise<void> => {
|
||||||
|
const state: CombinedState = getState();
|
||||||
|
const OpenVINO = state.plugins.list.AUTO_ANNOTATION;
|
||||||
|
const RCNN = state.plugins.list.TF_ANNOTATION;
|
||||||
|
const MaskRCNN = state.plugins.list.TF_SEGMENTATION;
|
||||||
|
|
||||||
|
dispatch(modelsActions.getModels());
|
||||||
|
const models: Model[] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (OpenVINO) {
|
||||||
|
const response = await core.server.request(
|
||||||
|
`${baseURL}/auto_annotation/meta/get`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
data: JSON.stringify([]),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
for (const model of response.models) {
|
||||||
|
models.push({
|
||||||
|
id: model.id,
|
||||||
|
ownerID: model.owner,
|
||||||
|
primary: model.primary,
|
||||||
|
name: model.name,
|
||||||
|
uploadDate: model.uploadDate,
|
||||||
|
updateDate: model.updateDate,
|
||||||
|
labels: [...model.labels],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RCNN) {
|
||||||
|
models.push({
|
||||||
|
id: null,
|
||||||
|
ownerID: null,
|
||||||
|
primary: true,
|
||||||
|
name: PreinstalledModels.RCNN,
|
||||||
|
uploadDate: '',
|
||||||
|
updateDate: '',
|
||||||
|
labels: ['surfboard', 'car', 'skateboard', 'boat', 'clock',
|
||||||
|
'cat', 'cow', 'knife', 'apple', 'cup', 'tv',
|
||||||
|
'baseball_bat', 'book', 'suitcase', 'tennis_racket',
|
||||||
|
'stop_sign', 'couch', 'cell_phone', 'keyboard',
|
||||||
|
'cake', 'tie', 'frisbee', 'truck', 'fire_hydrant',
|
||||||
|
'snowboard', 'bed', 'vase', 'teddy_bear',
|
||||||
|
'toaster', 'wine_glass', 'traffic_light',
|
||||||
|
'broccoli', 'backpack', 'carrot', 'potted_plant',
|
||||||
|
'donut', 'umbrella', 'parking_meter', 'bottle',
|
||||||
|
'sandwich', 'motorcycle', 'bear', 'banana',
|
||||||
|
'person', 'scissors', 'elephant', 'dining_table',
|
||||||
|
'toothbrush', 'toilet', 'skis', 'bowl', 'sheep',
|
||||||
|
'refrigerator', 'oven', 'microwave', 'train',
|
||||||
|
'orange', 'mouse', 'laptop', 'bench', 'bicycle',
|
||||||
|
'fork', 'kite', 'zebra', 'baseball_glove', 'bus',
|
||||||
|
'spoon', 'horse', 'handbag', 'pizza', 'sports_ball',
|
||||||
|
'airplane', 'hair_drier', 'hot_dog', 'remote',
|
||||||
|
'sink', 'dog', 'bird', 'giraffe', 'chair',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaskRCNN) {
|
||||||
|
models.push({
|
||||||
|
id: null,
|
||||||
|
ownerID: null,
|
||||||
|
primary: true,
|
||||||
|
name: PreinstalledModels.MaskRCNN,
|
||||||
|
uploadDate: '',
|
||||||
|
updateDate: '',
|
||||||
|
labels: ['BG', 'person', 'bicycle', 'car', 'motorcycle', 'airplane',
|
||||||
|
'bus', 'train', 'truck', 'boat', 'traffic light',
|
||||||
|
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird',
|
||||||
|
'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear',
|
||||||
|
'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie',
|
||||||
|
'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
|
||||||
|
'kite', 'baseball bat', 'baseball glove', 'skateboard',
|
||||||
|
'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup',
|
||||||
|
'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
|
||||||
|
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
|
||||||
|
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed',
|
||||||
|
'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
|
||||||
|
'keyboard', 'cell phone', 'microwave', 'oven', 'toaster',
|
||||||
|
'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors',
|
||||||
|
'teddy bear', 'hair drier', 'toothbrush',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.getModelsFailed(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(modelsActions.getModelsSuccess(models));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteModelAsync(id: number): ThunkAction {
|
||||||
|
return async (dispatch): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await core.server.request(`${baseURL}/auto_annotation/delete/${id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.deleteModelFailed(id, error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(modelsActions.deleteModelSuccess(id));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createModelAsync(name: string, files: ModelFiles, global: boolean): ThunkAction {
|
||||||
|
return async (dispatch): Promise<void> => {
|
||||||
|
async function checkCallback(id: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const data = await core.server.request(
|
||||||
|
`${baseURL}/auto_annotation/check/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (data.status) {
|
||||||
|
case 'failed':
|
||||||
|
dispatch(modelsActions.createModelFailed(
|
||||||
|
`Checking request has returned the "${data.status}" status. Message: ${data.error}`,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case 'unknown':
|
||||||
|
dispatch(modelsActions.createModelFailed(
|
||||||
|
`Checking request has returned the "${data.status}" status.`,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case 'finished':
|
||||||
|
dispatch(modelsActions.createModelSuccess());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ('progress' in data) {
|
||||||
|
modelsActions.createModelUpdateStatus(data.progress);
|
||||||
|
}
|
||||||
|
setTimeout(checkCallback.bind(null, id), 1000);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.createModelFailed(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(modelsActions.createModel());
|
||||||
|
const data = new FormData();
|
||||||
|
data.append('name', name);
|
||||||
|
data.append('storage', typeof files.bin === 'string' ? 'shared' : 'local');
|
||||||
|
data.append('shared', global.toString());
|
||||||
|
Object.keys(files).reduce((acc, key: string): FormData => {
|
||||||
|
acc.append(key, files[key]);
|
||||||
|
return acc;
|
||||||
|
}, data);
|
||||||
|
|
||||||
|
try {
|
||||||
|
dispatch(modelsActions.createModelUpdateStatus('Request is beign sent..'));
|
||||||
|
const response = await core.server.request(
|
||||||
|
`${baseURL}/auto_annotation/create`, {
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(modelsActions.createModelUpdateStatus('Request is being processed..'));
|
||||||
|
setTimeout(checkCallback.bind(null, response.id), 1000);
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.createModelFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InferenceMeta {
|
||||||
|
active: boolean;
|
||||||
|
taskID: number;
|
||||||
|
requestID: string;
|
||||||
|
modelType: ModelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timers: any = {};
|
||||||
|
|
||||||
|
async function timeoutCallback(
|
||||||
|
url: string,
|
||||||
|
taskID: number,
|
||||||
|
modelType: ModelType,
|
||||||
|
dispatch: (action: ModelsActions) => void,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
delete timers[taskID];
|
||||||
|
|
||||||
|
const response = await core.server.request(url, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeInference: ActiveInference = {
|
||||||
|
status: response.status,
|
||||||
|
progress: +response.progress || 0,
|
||||||
|
error: response.error || response.stderr || '',
|
||||||
|
modelType,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (activeInference.status === 'unknown') {
|
||||||
|
dispatch(modelsActions.getInferenceStatusFailed(
|
||||||
|
taskID,
|
||||||
|
new Error(
|
||||||
|
`Inference status for the task ${taskID} is unknown.`,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeInference.status === 'failed') {
|
||||||
|
dispatch(modelsActions.getInferenceStatusFailed(
|
||||||
|
taskID,
|
||||||
|
new Error(
|
||||||
|
`Inference status for the task ${taskID} is failed. ${activeInference.error}`,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeInference.status !== 'finished') {
|
||||||
|
timers[taskID] = setTimeout(
|
||||||
|
timeoutCallback.bind(
|
||||||
|
null,
|
||||||
|
url,
|
||||||
|
taskID,
|
||||||
|
modelType,
|
||||||
|
dispatch,
|
||||||
|
), 3000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(modelsActions.getInferenceStatusSuccess(taskID, activeInference));
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.getInferenceStatusFailed(taskID, new Error(
|
||||||
|
`Server request for the task ${taskID} was failed`,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribe(
|
||||||
|
inferenceMeta: InferenceMeta,
|
||||||
|
dispatch: (action: ModelsActions) => void,
|
||||||
|
): void {
|
||||||
|
if (!(inferenceMeta.taskID in timers)) {
|
||||||
|
let requestURL = `${baseURL}`;
|
||||||
|
if (inferenceMeta.modelType === ModelType.OPENVINO) {
|
||||||
|
requestURL = `${requestURL}/auto_annotation/check`;
|
||||||
|
} else if (inferenceMeta.modelType === ModelType.RCNN) {
|
||||||
|
requestURL = `${requestURL}/tensorflow/annotation/check/task`;
|
||||||
|
} else if (inferenceMeta.modelType === ModelType.MASK_RCNN) {
|
||||||
|
requestURL = `${requestURL}/tensorflow/segmentation/check/task`;
|
||||||
|
}
|
||||||
|
requestURL = `${requestURL}/${inferenceMeta.requestID}`;
|
||||||
|
timers[inferenceMeta.taskID] = setTimeout(
|
||||||
|
timeoutCallback.bind(
|
||||||
|
null,
|
||||||
|
requestURL,
|
||||||
|
inferenceMeta.taskID,
|
||||||
|
inferenceMeta.modelType,
|
||||||
|
dispatch,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getInferenceStatusAsync(tasks: number[]): ThunkAction {
|
||||||
|
return async (dispatch, getState): Promise<void> => {
|
||||||
|
function parse(response: any, modelType: ModelType): InferenceMeta[] {
|
||||||
|
return Object.keys(response).map((key: string): InferenceMeta => ({
|
||||||
|
taskID: +key,
|
||||||
|
requestID: response[key].rq_id || key,
|
||||||
|
active: typeof (response[key].active) === 'undefined' ? ['queued', 'started']
|
||||||
|
.includes(response[key].status.toLowerCase()) : response[key].active,
|
||||||
|
modelType,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const state: CombinedState = getState();
|
||||||
|
const OpenVINO = state.plugins.list.AUTO_ANNOTATION;
|
||||||
|
const RCNN = state.plugins.list.TF_ANNOTATION;
|
||||||
|
const MaskRCNN = state.plugins.list.TF_SEGMENTATION;
|
||||||
|
|
||||||
|
const dispatchCallback = (action: ModelsActions): void => {
|
||||||
|
dispatch(action);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (OpenVINO) {
|
||||||
|
const response = await core.server.request(
|
||||||
|
`${baseURL}/auto_annotation/meta/get`, {
|
||||||
|
method: 'POST',
|
||||||
|
data: JSON.stringify(tasks),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
parse(response.run, ModelType.OPENVINO)
|
||||||
|
.filter((inferenceMeta: InferenceMeta): boolean => inferenceMeta.active)
|
||||||
|
.forEach((inferenceMeta: InferenceMeta): void => {
|
||||||
|
subscribe(inferenceMeta, dispatchCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RCNN) {
|
||||||
|
const response = await core.server.request(
|
||||||
|
`${baseURL}/tensorflow/annotation/meta/get`, {
|
||||||
|
method: 'POST',
|
||||||
|
data: JSON.stringify(tasks),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
parse(response, ModelType.RCNN)
|
||||||
|
.filter((inferenceMeta: InferenceMeta): boolean => inferenceMeta.active)
|
||||||
|
.forEach((inferenceMeta: InferenceMeta): void => {
|
||||||
|
subscribe(inferenceMeta, dispatchCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaskRCNN) {
|
||||||
|
const response = await core.server.request(
|
||||||
|
`${baseURL}/tensorflow/segmentation/meta/get`, {
|
||||||
|
method: 'POST',
|
||||||
|
data: JSON.stringify(tasks),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
parse(response, ModelType.MASK_RCNN)
|
||||||
|
.filter((inferenceMeta: InferenceMeta): boolean => inferenceMeta.active)
|
||||||
|
.forEach((inferenceMeta: InferenceMeta): void => {
|
||||||
|
subscribe(inferenceMeta, dispatchCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.fetchMetaFailed(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startInferenceAsync(
|
||||||
|
taskInstance: any,
|
||||||
|
model: Model,
|
||||||
|
mapping: {
|
||||||
|
[index: string]: string;
|
||||||
|
},
|
||||||
|
cleanOut: boolean,
|
||||||
|
): ThunkAction {
|
||||||
|
return async (dispatch): Promise<void> => {
|
||||||
|
try {
|
||||||
|
if (model.name === PreinstalledModels.RCNN) {
|
||||||
|
await core.server.request(
|
||||||
|
`${baseURL}/tensorflow/annotation/create/task/${taskInstance.id}`,
|
||||||
|
);
|
||||||
|
} else if (model.name === PreinstalledModels.MaskRCNN) {
|
||||||
|
await core.server.request(
|
||||||
|
`${baseURL}/tensorflow/segmentation/create/task/${taskInstance.id}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await core.server.request(
|
||||||
|
`${baseURL}/auto_annotation/start/${model.id}/${taskInstance.id}`, {
|
||||||
|
method: 'POST',
|
||||||
|
data: JSON.stringify({
|
||||||
|
reset: cleanOut,
|
||||||
|
labels: mapping,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(getInferenceStatusAsync([taskInstance.id]));
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.startInferenceFailed(taskInstance.id, error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cancelInferenceAsync(taskID: number): ThunkAction {
|
||||||
|
return async (dispatch, getState): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const inference = getState().models.inferences[taskID];
|
||||||
|
if (inference) {
|
||||||
|
if (inference.modelType === ModelType.OPENVINO) {
|
||||||
|
await core.server.request(
|
||||||
|
`${baseURL}/auto_annotation/cancel/${taskID}`,
|
||||||
|
);
|
||||||
|
} else if (inference.modelType === ModelType.RCNN) {
|
||||||
|
await core.server.request(
|
||||||
|
`${baseURL}/tensorflow/annotation/cancel/task/${taskID}`,
|
||||||
|
);
|
||||||
|
} else if (inference.modelType === ModelType.MASK_RCNN) {
|
||||||
|
await core.server.request(
|
||||||
|
`${baseURL}/tensorflow/segmentation/cancel/task/${taskID}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timers[taskID]) {
|
||||||
|
clearTimeout(timers[taskID]);
|
||||||
|
delete timers[taskID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(modelsActions.cancelInferenceSuccess(taskID));
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(modelsActions.cancelInferenceFaild(taskID, error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
export enum NotificationsActionType {
|
||||||
|
RESET_ERRORS = 'RESET_ERRORS',
|
||||||
|
RESET_MESSAGES = 'RESET_MESSAGES',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetErrors(): AnyAction {
|
||||||
|
const action = {
|
||||||
|
type: NotificationsActionType.RESET_ERRORS,
|
||||||
|
payload: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetMessages(): AnyAction {
|
||||||
|
const action = {
|
||||||
|
type: NotificationsActionType.RESET_MESSAGES,
|
||||||
|
payload: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
|
||||||
|
import { SupportedPlugins } from 'reducers/interfaces';
|
||||||
|
import PluginChecker from 'utils/plugin-checker';
|
||||||
|
|
||||||
|
export enum PluginsActionTypes {
|
||||||
|
CHECK_PLUGINS = 'CHECK_PLUGINS',
|
||||||
|
CHECKED_ALL_PLUGINS = 'CHECKED_ALL_PLUGINS'
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginObjects = Record<SupportedPlugins, boolean>;
|
||||||
|
|
||||||
|
const pluginActions = {
|
||||||
|
checkPlugins: () => createAction(PluginsActionTypes.CHECK_PLUGINS),
|
||||||
|
checkedAllPlugins: (list: PluginObjects) => (
|
||||||
|
createAction(PluginsActionTypes.CHECKED_ALL_PLUGINS, {
|
||||||
|
list,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PluginActions = ActionUnion<typeof pluginActions>;
|
||||||
|
|
||||||
|
export function checkPluginsAsync(): ThunkAction {
|
||||||
|
return async (dispatch): Promise<void> => {
|
||||||
|
dispatch(pluginActions.checkPlugins());
|
||||||
|
const plugins: PluginObjects = {
|
||||||
|
ANALYTICS: false,
|
||||||
|
AUTO_ANNOTATION: false,
|
||||||
|
GIT_INTEGRATION: false,
|
||||||
|
TF_ANNOTATION: false,
|
||||||
|
TF_SEGMENTATION: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const promises: Promise<boolean>[] = [
|
||||||
|
PluginChecker.check(SupportedPlugins.ANALYTICS),
|
||||||
|
PluginChecker.check(SupportedPlugins.AUTO_ANNOTATION),
|
||||||
|
PluginChecker.check(SupportedPlugins.GIT_INTEGRATION),
|
||||||
|
PluginChecker.check(SupportedPlugins.TF_ANNOTATION),
|
||||||
|
PluginChecker.check(SupportedPlugins.TF_SEGMENTATION),
|
||||||
|
];
|
||||||
|
|
||||||
|
const values = await Promise.all(promises);
|
||||||
|
[plugins.ANALYTICS] = values;
|
||||||
|
[, plugins.AUTO_ANNOTATION] = values;
|
||||||
|
[,, plugins.GIT_INTEGRATION] = values;
|
||||||
|
[,,, plugins.TF_ANNOTATION] = values;
|
||||||
|
[,,,, plugins.TF_SEGMENTATION] = values;
|
||||||
|
|
||||||
|
dispatch(pluginActions.checkedAllPlugins(plugins));
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,109 +0,0 @@
|
|||||||
import { Dispatch, ActionCreator } from 'redux';
|
|
||||||
|
|
||||||
|
|
||||||
export const getServerInfo = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_SERVER_INFO',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getServerInfoSuccess = (information: null) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_SERVER_INFO_SUCCESS',
|
|
||||||
payload: information,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getServerInfoError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_SERVER_INFO_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getShareFiles = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_SHARE_FILES',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getShareFilesSuccess = (files: []) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_SHARE_FILES_SUCCESS',
|
|
||||||
payload: files,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getShareFilesError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_SHARE_FILES_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAnnotationFormats = () => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_ANNOTATION_FORMATS',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAnnotationFormatsSuccess = (annotationFormats: []) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_ANNOTATION_FORMATS_SUCCESS',
|
|
||||||
payload: annotationFormats,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAnnotationFormatsError = (error = {}) => (dispatch: Dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'GET_ANNOTATION_FORMATS_ERROR',
|
|
||||||
payload: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getServerInfoAsync = () => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(getServerInfo());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.about().then(
|
|
||||||
(information: any) => {
|
|
||||||
dispatch(getServerInfoSuccess(information));
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(getServerInfoError(error));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getShareFilesAsync = (directory: string) => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(getShareFiles());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.share(directory).then(
|
|
||||||
(files: any) => {
|
|
||||||
dispatch(getShareFilesSuccess(files));
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(getShareFilesError(error));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAnnotationFormatsAsync = () => {
|
|
||||||
return (dispatch: ActionCreator<Dispatch>) => {
|
|
||||||
dispatch(getAnnotationFormats());
|
|
||||||
|
|
||||||
return (window as any).cvat.server.formats().then(
|
|
||||||
(formats: any) => {
|
|
||||||
dispatch(getAnnotationFormatsSuccess(formats));
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
dispatch(getAnnotationFormatsError(error));
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
import {
|
||||||
|
GridColor,
|
||||||
|
ColorBy,
|
||||||
|
} from 'reducers/interfaces';
|
||||||
|
|
||||||
|
export enum SettingsActionTypes {
|
||||||
|
SWITCH_ROTATE_ALL = 'SWITCH_ROTATE_ALL',
|
||||||
|
SWITCH_GRID = 'SWITCH_GRID',
|
||||||
|
CHANGE_GRID_SIZE = 'CHANGE_GRID_SIZE',
|
||||||
|
CHANGE_GRID_COLOR = 'CHANGE_GRID_COLOR',
|
||||||
|
CHANGE_GRID_OPACITY = 'CHANGE_GRID_OPACITY',
|
||||||
|
CHANGE_SHAPES_OPACITY = 'CHANGE_SHAPES_OPACITY',
|
||||||
|
CHANGE_SELECTED_SHAPES_OPACITY = 'CHANGE_SELECTED_SHAPES_OPACITY',
|
||||||
|
CHANGE_SHAPES_COLOR_BY = 'CHANGE_SHAPES_COLOR_BY',
|
||||||
|
CHANGE_SHAPES_BLACK_BORDERS = 'CHANGE_SHAPES_BLACK_BORDERS',
|
||||||
|
CHANGE_FRAME_STEP = 'CHANGE_FRAME_STEP',
|
||||||
|
CHANGE_FRAME_SPEED = 'CHANGE_FRAME_SPEED',
|
||||||
|
SWITCH_RESET_ZOOM = 'SWITCH_RESET_ZOOM',
|
||||||
|
CHANGE_BRIGHTNESS_LEVEL = 'CHANGE_BRIGHTNESS_LEVEL',
|
||||||
|
CHANGE_CONTRAST_LEVEL = 'CHANGE_CONTRAST_LEVEL',
|
||||||
|
CHANGE_SATURATION_LEVEL = 'CHANGE_SATURATION_LEVEL',
|
||||||
|
SWITCH_AUTO_SAVE = 'SWITCH_AUTO_SAVE',
|
||||||
|
CHANGE_AUTO_SAVE_INTERVAL = 'CHANGE_AUTO_SAVE_INTERVAL',
|
||||||
|
CHANGE_AAM_ZOOM_MARGIN = 'CHANGE_AAM_ZOOM_MARGIN',
|
||||||
|
SWITCH_SHOWNIG_INTERPOLATED_TRACKS = 'SWITCH_SHOWNIG_INTERPOLATED_TRACKS',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeShapesOpacity(opacity: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_SHAPES_OPACITY,
|
||||||
|
payload: {
|
||||||
|
opacity,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeSelectedShapesOpacity(selectedOpacity: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_SELECTED_SHAPES_OPACITY,
|
||||||
|
payload: {
|
||||||
|
selectedOpacity,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeShapesColorBy(colorBy: ColorBy): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_SHAPES_COLOR_BY,
|
||||||
|
payload: {
|
||||||
|
colorBy,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeShapesBlackBorders(blackBorders: boolean): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_SHAPES_BLACK_BORDERS,
|
||||||
|
payload: {
|
||||||
|
blackBorders,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function switchRotateAll(rotateAll: boolean): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.SWITCH_ROTATE_ALL,
|
||||||
|
payload: {
|
||||||
|
rotateAll,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function switchGrid(grid: boolean): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.SWITCH_GRID,
|
||||||
|
payload: {
|
||||||
|
grid,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeGridSize(gridSize: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_GRID_SIZE,
|
||||||
|
payload: {
|
||||||
|
gridSize,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeGridColor(gridColor: GridColor): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_GRID_COLOR,
|
||||||
|
payload: {
|
||||||
|
gridColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeGridOpacity(gridOpacity: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_GRID_OPACITY,
|
||||||
|
payload: {
|
||||||
|
gridOpacity,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeFrameStep(frameStep: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_FRAME_STEP,
|
||||||
|
payload: {
|
||||||
|
frameStep,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeFrameSpeed(frameSpeed: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_FRAME_SPEED,
|
||||||
|
payload: {
|
||||||
|
frameSpeed,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function switchResetZoom(resetZoom: boolean): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.SWITCH_RESET_ZOOM,
|
||||||
|
payload: {
|
||||||
|
resetZoom,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeBrightnessLevel(level: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL,
|
||||||
|
payload: {
|
||||||
|
level,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeContrastLevel(level: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_CONTRAST_LEVEL,
|
||||||
|
payload: {
|
||||||
|
level,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeSaturationLevel(level: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_SATURATION_LEVEL,
|
||||||
|
payload: {
|
||||||
|
level,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function switchAutoSave(autoSave: boolean): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.SWITCH_AUTO_SAVE,
|
||||||
|
payload: {
|
||||||
|
autoSave,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeAutoSaveInterval(autoSaveInterval: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_AUTO_SAVE_INTERVAL,
|
||||||
|
payload: {
|
||||||
|
autoSaveInterval,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeAAMZoomMargin(aamZoomMargin: number): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.CHANGE_AAM_ZOOM_MARGIN,
|
||||||
|
payload: {
|
||||||
|
aamZoomMargin,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function switchShowingInterpolatedTracks(showAllInterpolationTracks: boolean): AnyAction {
|
||||||
|
return {
|
||||||
|
type: SettingsActionTypes.SWITCH_SHOWNIG_INTERPOLATED_TRACKS,
|
||||||
|
payload: {
|
||||||
|
showAllInterpolationTracks,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue