diff --git a/client/package.json b/client/package.json index 63f9728..88deb6c 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "dive-dsa", - "version": "1.10.17", + "version": "1.10.18", "author": { "name": "Kitware, Inc.", "email": "Bryon.Lewis@kitware.com" @@ -25,7 +25,7 @@ "main": "lib/index.js", "types": "lib/types/index.d.ts", "dependencies": { - "vue-girder-slicer-cli-ui": "0.0.8", + "vue-girder-slicer-cli-ui": "0.0.9", "@flatten-js/interval-tree": "^1.0.11", "@girder/components": "^3.2.0", "@mdi/font": "^6.2.95", diff --git a/client/yarn.lock b/client/yarn.lock index 21f0315..1e8cbc4 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -11019,10 +11019,10 @@ vue-eslint-parser@^9.0.1, vue-eslint-parser@^9.0.3, vue-eslint-parser@^9.3.1, vu lodash "^4.17.21" semver "^7.3.6" -vue-girder-slicer-cli-ui@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/vue-girder-slicer-cli-ui/-/vue-girder-slicer-cli-ui-0.0.8.tgz#7c6d91598f54f469e6306cf2fdf9a503b8284099" - integrity sha512-xCVkzDmOTKfukFyYw4NawfOLAelF6iTdyJXDbxQZ6xpdDhuGsJdzlE2xDxQZcGdV0vLX13wWNZvIA+Wn7CMhAQ== +vue-girder-slicer-cli-ui@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/vue-girder-slicer-cli-ui/-/vue-girder-slicer-cli-ui-0.0.9.tgz#7725fbfb8f6b92f917b1e1fc264ad0e868ae47b1" + integrity sha512-IYaecdkcAHgnCvRBaDxLxUrAmYr5Ft70NPwUGLmYvlP95HHgTObuIEqke4b2WU4AIFabwhlP9LeU5KGaUEJW5A== dependencies: "@jamescoyle/vue-icon" "^0.1.2" "@mdi/js" "^7.2.96" diff --git a/server/dive_server/crud_dataset.py b/server/dive_server/crud_dataset.py index 8662655..ecb071c 100644 --- a/server/dive_server/crud_dataset.py +++ b/server/dive_server/crud_dataset.py @@ -179,6 +179,19 @@ def get_task_defaults( ) +def get_recursive_datasets( + dsFolder: types.GirderModel, user: types.GirderUserModel, datasetList: List[types.GirderModel], limit: int = -1 +): + subFolders = list(Folder().childFolders(dsFolder, 'folder', user)) + for child in subFolders: + if child.get('meta', {}).get(constants.DatasetMarker, False): + if limit == -1 or len(datasetList) < limit: + datasetList.append(child) + else: + return + get_recursive_datasets(child, user, datasetList, limit) + + def get_media( dsFolder: types.GirderModel, user: types.GirderUserModel ) -> models.DatasetSourceMedia: diff --git a/server/dive_server/views_annotation.py b/server/dive_server/views_annotation.py index f94f82b..d9e0878 100644 --- a/server/dive_server/views_annotation.py +++ b/server/dive_server/views_annotation.py @@ -10,6 +10,7 @@ from girder.models.folder import Folder from dive_utils import constants, models, setContentDisposition +from dive_utils.serializers import dive, viame from . import crud, crud_annotation @@ -44,6 +45,7 @@ def __init__(self, resourceName): self.route("PATCH", (), self.save_annotations) self.route("PUT", ("track",), self.update_tracks) self.route("POST", ("rollback",), self.rollback) + self.route("POST", ("process_json",), self.process_json) @access.user @autoDescribeRoute(GetAnnotationParams) @@ -195,6 +197,59 @@ def rollback(self, folder, revision): crud.verify_dataset(folder) crud_annotation.rollback(folder, revision) + @access.user + @autoDescribeRoute( + Description("Upload a Complete TrackJSON File to system and process it for attributes") + .modelParam("folderId", **DatasetModelParam, level=AccessType.WRITE) + .jsonParam( + "body", + "TrackJSON data to upload to the folderId", + paramType="body", + requireObject=True, + ) + .param( + "additive", + "Whether to add new annotations to existing ones. Annotations \ + will be added with Ids starting at the last existing Id+1", + paramType="query", + dataType="boolean", + default=False, + required=False, + ) + .param( + "additivePrepend", + "When using additive the prepend to types: I.E. 'prepend_type' \ + so the string will be added to all types that are imported", + paramType="query", + dataType="string", + default='', + required=False, + ) + ) + def process_json(self, folder, body, additive, additivePrepend): + crud.verify_dataset(folder) + user = self.getCurrentUser() + annotations = dive.migrate(body) + _oldannotations, attributes = viame.load_json_as_track_and_attributes(body) + if annotations: + updated_tracks = annotations['tracks'].values() + if additive: # get annotations and add them to the end + tracks = crud_annotation.add_annotations( + folder, annotations['tracks'], additivePrepend + ) + updated_tracks = tracks.values() + print(f'Saving Annotations: {user}') + crud_annotation.save_annotations( + folder, + user, + upsert_tracks=updated_tracks, + upsert_groups=annotations['groups'].values(), + overwrite=True, + description=f'POST trackJSON from {user["login"]}', + ) + if attributes: + crud.saveImportAttributes(folder, attributes, user) + @access.user @autoDescribeRoute( Description("Get all labels visible to a particular user") diff --git a/server/dive_server/views_dataset.py b/server/dive_server/views_dataset.py index 32aed6a..032b496 100644 --- a/server/dive_server/views_dataset.py +++ b/server/dive_server/views_dataset.py @@ -56,6 +56,7 @@ def __init__(self, resourceName): self.route("GET", (":id",), self.get_meta) self.route("GET", (":id", "media"), self.get_media) self.route("GET", (":id", "task-defaults"), self.get_task_defaults) + self.route("GET", (":id", "recursive"), self.get_recursive) self.route("GET", ("export",), self.export) self.route("GET", (":id", "configuration"), self.get_configuration) self.route("GET", (":id", "export_configuration"), self.export_configuration) @@ -509,6 +510,27 @@ def get_media(self, folder): def get_task_defaults(self, folder): return crud_dataset.get_task_defaults(folder, self.getCurrentUser()).dict(exclude_none=True) + @access.public(scope=TokenScope.DATA_READ, cookie=True) + @autoDescribeRoute( + Description("Get a Recursive list of all DIVE Datasets within a parent folder").modelParam( + "id", + level=AccessType.READ, + **DatasetModelParam, + ) + .param( + "limit", + "Limit the number of Datasets returned, -1 is no limit", + dataType="integer", + default=-1, + required=False, + ) + + ) + def get_recursive(self, folder, limit): + datasetList = [] + crud_dataset.get_recursive_datasets(folder, self.getCurrentUser(), datasetList, limit) + return datasetList + @access.public(scope=TokenScope.DATA_READ, cookie=True) @autoDescribeRoute( Description("Export all selected datasets")