histomicsui 1.8.1.dev163__tar.gz → 1.8.1.dev194__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.pre-commit-config.yaml +1 -1
- {histomicsui-1.8.1.dev163/histomicsui.egg-info → histomicsui-1.8.1.dev194}/PKG-INFO +1 -1
- histomicsui-1.8.1.dev194/docs/annotation_group_restrictions.rst +41 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/config_options.rst +13 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194/histomicsui.egg-info}/PKG-INFO +1 -1
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/SOURCES.txt +2 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/scm_file_list.json +61 -58
- histomicsui-1.8.1.dev194/histomicsui.egg-info/scm_version.json +8 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/.histomicsui_config.yaml +1 -0
- histomicsui-1.8.1.dev194/tests/web_client_specs/allowedGroupsSpec.js +371 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/annotationSpec.js +125 -4
- histomicsui-1.8.1.dev163/histomicsui.egg-info/scm_version.json +0 -8
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.circleci/config.yml +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.circleci/get_version.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.circleci/publish_pypi.sh +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.editorconfig +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.git-blame-ignore-revs +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/.gitignore +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/LICENSE +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/MANIFEST.in +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/NOTICE +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/README.rst +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/codecov.yml +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/controls.rst +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/images/cut.gif +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/images/difference.gif +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/images/intersect.gif +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/images/union.gif +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/images/xor.gif +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/docs/slicer_cli_plugins.rst +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/__init__.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/constants.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/girder_worker_plugin.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/handlers.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/__init__.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/aperio.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/case.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/cohort.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/image.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/meta.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/pathology.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/models/slide.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/__init__.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/aperio.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/hui_resource.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/image_browse_resource.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/system.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/tcga.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/dependency_links.txt +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/entry_points.txt +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/not-zip-safe +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/requires.txt +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/top_level.txt +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/pyproject.toml +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/requirements-dev.txt +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/ruff.toml +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/sample_data/Easy1.png +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/sample_data/sample_svs_image.TCGA-DU-6399-01A-01-TS1.e8eb65de-d63e-42db-af6f-14fefbbdf7bd.svs +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/setup.cfg +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/setup.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/__init__.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/conftest.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/datastore.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/girder_utilities.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/sample.anot +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/sample.meta +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/sample_girder_id.anot +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/test_analysis_detection.xml +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/test_analysis_features.xml +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_handlers.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_hui_rest.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_image_browse_endpoints.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_load.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_tcga.py +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/.eslintrc +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/analysisSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/girderUISpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/huiSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/huiTest.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/itemSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/metadataPanelSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/metadataPlotSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/overviewPanelSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/panelLayoutSpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/pixelmapCategorySpec.js +0 -0
- {histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tox.ini +0 -0
|
@@ -48,7 +48,7 @@ repos:
|
|
|
48
48
|
- id: codespell
|
|
49
49
|
args:
|
|
50
50
|
- --ignore-words-list
|
|
51
|
-
- "hist,indext,pixelx,thex,subtile,afterAll"
|
|
51
|
+
- "hist,indext,pixelx,thex,subtile,afterAll,groupE"
|
|
52
52
|
- --exclude-file=histomicsui/web_client/package-lock.json
|
|
53
53
|
- repo: https://github.com/syntaqx/git-hooks
|
|
54
54
|
rev: v0.0.18
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Restricting Annotations to Allowed Groups
|
|
2
|
+
==========================================
|
|
3
|
+
|
|
4
|
+
An annotation document can restrict which style groups its elements may be assigned to by setting an ``allowed_groups`` key in the annotation's ``attributes``:
|
|
5
|
+
|
|
6
|
+
::
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
"name": "restricted annotation",
|
|
10
|
+
"attributes": {
|
|
11
|
+
"allowed_groups": ["groupA", "groupB"]
|
|
12
|
+
},
|
|
13
|
+
"elements": [...]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
``allowed_groups`` may also be given as a JSON-stringified array for convenience when setting it through the UI metadata editor:
|
|
17
|
+
|
|
18
|
+
::
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
"attributes": {
|
|
22
|
+
"allowed_groups": "[\"groupA\", \"groupB\"]"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
When this restriction is present, the Draw panel and the annotation element context menu will only offer the listed groups instead of every style group that exists.
|
|
27
|
+
|
|
28
|
+
Validation
|
|
29
|
+
----------
|
|
30
|
+
|
|
31
|
+
``allowed_groups`` is only honored when it is a non-empty array of non-empty strings, or a string that parses as JSON into such an array. Any other value - a missing key, a non-array/non-JSON-array value, an unparsable string, an empty array, or an array containing no valid strings - is treated as *unrestricted*, and every existing style group is offered as usual. Duplicate entries are ignored.
|
|
32
|
+
|
|
33
|
+
Auto-creation of missing groups
|
|
34
|
+
--------------------------------
|
|
35
|
+
|
|
36
|
+
If ``allowed_groups`` names a style group that does not yet exist, it is automatically created the first time the restriction is encountered, by copying the style (fill color, line color, line width, pattern) of the default group. The newly created groups are persisted immediately. This can happen from either the Draw panel or the annotation context menu, whichever sees the restricted annotation first.
|
|
37
|
+
|
|
38
|
+
Effect on the current selection
|
|
39
|
+
--------------------------------
|
|
40
|
+
|
|
41
|
+
- **Draw panel**: If the currently active style group is not one of the annotation's allowed groups, the Draw panel automatically switches to the first allowed group that exists.
|
|
@@ -56,6 +56,10 @@ _________________
|
|
|
56
56
|
fillColor: rgba(0, 128, 0, 0.25)
|
|
57
57
|
lineColor: rgb(0, 128, 0)
|
|
58
58
|
lineWidth: 2
|
|
59
|
+
# patterns can be none, circle, triangle, diamond, flower(number),
|
|
60
|
+
# star(number), jack(number), where number is from 1 to 16. Not
|
|
61
|
+
# specifying a pattern is the same as none.
|
|
62
|
+
pattern: star5
|
|
59
63
|
-
|
|
60
64
|
id: Blue
|
|
61
65
|
fillColor: rgba(0, 0, 255, 0.25)
|
|
@@ -75,6 +79,15 @@ If a hotkey is specified for a group, it will only be active if the group was lo
|
|
|
75
79
|
action: group
|
|
76
80
|
param: Red
|
|
77
81
|
|
|
82
|
+
Unselected Annotation Capacity
|
|
83
|
+
______________________________
|
|
84
|
+
When annotation elements are selected, the annotations not included in the user's selection have their opacity decreased to 0.33 times their specified opacity. This can be modified:
|
|
85
|
+
::
|
|
86
|
+
---
|
|
87
|
+
# A lower value will make unselected annotations more transparent.
|
|
88
|
+
unselectedOpacityMultiplier: 0.33
|
|
89
|
+
|
|
90
|
+
|
|
78
91
|
UI Settings
|
|
79
92
|
___________
|
|
80
93
|
|
|
@@ -16,6 +16,7 @@ tox.ini
|
|
|
16
16
|
.circleci/config.yml
|
|
17
17
|
.circleci/get_version.py
|
|
18
18
|
.circleci/publish_pypi.sh
|
|
19
|
+
docs/annotation_group_restrictions.rst
|
|
19
20
|
docs/config_options.rst
|
|
20
21
|
docs/controls.rst
|
|
21
22
|
docs/slicer_cli_plugins.rst
|
|
@@ -69,6 +70,7 @@ tests/test_files/sample_girder_id.anot
|
|
|
69
70
|
tests/test_files/test_analysis_detection.xml
|
|
70
71
|
tests/test_files/test_analysis_features.xml
|
|
71
72
|
tests/web_client_specs/.eslintrc
|
|
73
|
+
tests/web_client_specs/allowedGroupsSpec.js
|
|
72
74
|
tests/web_client_specs/analysisSpec.js
|
|
73
75
|
tests/web_client_specs/annotationSpec.js
|
|
74
76
|
tests/web_client_specs/girderUISpec.js
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/scm_file_list.json
RENAMED
|
@@ -1,33 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [
|
|
3
|
+
".circleci/config.yml",
|
|
4
|
+
".circleci/get_version.py",
|
|
5
|
+
".circleci/publish_pypi.sh",
|
|
3
6
|
".editorconfig",
|
|
4
|
-
"LICENSE",
|
|
5
|
-
"NOTICE",
|
|
6
|
-
"codecov.yml",
|
|
7
|
-
"pyproject.toml",
|
|
8
|
-
"setup.cfg",
|
|
9
7
|
".git-blame-ignore-revs",
|
|
10
8
|
".gitignore",
|
|
11
9
|
".pre-commit-config.yaml",
|
|
10
|
+
"LICENSE",
|
|
12
11
|
"MANIFEST.in",
|
|
12
|
+
"NOTICE",
|
|
13
13
|
"README.rst",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"setup.py",
|
|
17
|
-
"tox.ini",
|
|
18
|
-
".circleci/config.yml",
|
|
19
|
-
".circleci/get_version.py",
|
|
20
|
-
".circleci/publish_pypi.sh",
|
|
14
|
+
"codecov.yml",
|
|
15
|
+
"docs/annotation_group_restrictions.rst",
|
|
21
16
|
"docs/config_options.rst",
|
|
22
17
|
"docs/controls.rst",
|
|
23
|
-
"docs/slicer_cli_plugins.rst",
|
|
24
18
|
"docs/images/cut.gif",
|
|
25
19
|
"docs/images/difference.gif",
|
|
26
20
|
"docs/images/intersect.gif",
|
|
27
21
|
"docs/images/union.gif",
|
|
28
22
|
"docs/images/xor.gif",
|
|
29
|
-
"
|
|
23
|
+
"docs/slicer_cli_plugins.rst",
|
|
30
24
|
"histomicsui/__init__.py",
|
|
25
|
+
"histomicsui/constants.py",
|
|
31
26
|
"histomicsui/girder_worker_plugin.py",
|
|
32
27
|
"histomicsui/handlers.py",
|
|
33
28
|
"histomicsui/models/__init__.py",
|
|
@@ -40,28 +35,15 @@
|
|
|
40
35
|
"histomicsui/models/slide.py",
|
|
41
36
|
"histomicsui/rest/__init__.py",
|
|
42
37
|
"histomicsui/rest/aperio.py",
|
|
43
|
-
"histomicsui/rest/image_browse_resource.py",
|
|
44
38
|
"histomicsui/rest/hui_resource.py",
|
|
39
|
+
"histomicsui/rest/image_browse_resource.py",
|
|
45
40
|
"histomicsui/rest/system.py",
|
|
46
41
|
"histomicsui/rest/tcga.py",
|
|
47
|
-
"histomicsui/web_client/routes.js",
|
|
48
42
|
"histomicsui/web_client/.gitignore",
|
|
49
43
|
"histomicsui/web_client/app.js",
|
|
50
|
-
"histomicsui/web_client/events.js",
|
|
51
|
-
"histomicsui/web_client/histomicsui.ts",
|
|
52
|
-
"histomicsui/web_client/index.html",
|
|
53
|
-
"histomicsui/web_client/index.js",
|
|
54
|
-
"histomicsui/web_client/main.js",
|
|
55
|
-
"histomicsui/web_client/package-lock.json",
|
|
56
|
-
"histomicsui/web_client/package.json",
|
|
57
|
-
"histomicsui/web_client/playwright.config.ts",
|
|
58
|
-
"histomicsui/web_client/router.js",
|
|
59
|
-
"histomicsui/web_client/tsconfig.json",
|
|
60
|
-
"histomicsui/web_client/vite-env.d.ts",
|
|
61
|
-
"histomicsui/web_client/vite.config.ts",
|
|
62
|
-
"histomicsui/web_client/collections/index.js",
|
|
63
44
|
"histomicsui/web_client/collections/StyleCollection.js",
|
|
64
45
|
"histomicsui/web_client/collections/UserCollection.js",
|
|
46
|
+
"histomicsui/web_client/collections/index.js",
|
|
65
47
|
"histomicsui/web_client/dialogs/confirmDialog.js",
|
|
66
48
|
"histomicsui/web_client/dialogs/editElement.js",
|
|
67
49
|
"histomicsui/web_client/dialogs/editRegionOfInterest.js",
|
|
@@ -71,9 +53,15 @@
|
|
|
71
53
|
"histomicsui/web_client/dialogs/openAnnotatedImage.js",
|
|
72
54
|
"histomicsui/web_client/dialogs/openImage.js",
|
|
73
55
|
"histomicsui/web_client/dialogs/saveAnnotation.js",
|
|
74
|
-
"histomicsui/web_client/
|
|
56
|
+
"histomicsui/web_client/events.js",
|
|
57
|
+
"histomicsui/web_client/histomicsui.ts",
|
|
58
|
+
"histomicsui/web_client/index.html",
|
|
59
|
+
"histomicsui/web_client/index.js",
|
|
60
|
+
"histomicsui/web_client/main.js",
|
|
75
61
|
"histomicsui/web_client/models/StyleModel.js",
|
|
76
|
-
"histomicsui/web_client/
|
|
62
|
+
"histomicsui/web_client/models/index.js",
|
|
63
|
+
"histomicsui/web_client/package-lock.json",
|
|
64
|
+
"histomicsui/web_client/package.json",
|
|
77
65
|
"histomicsui/web_client/panels/AnnotationSelector.js",
|
|
78
66
|
"histomicsui/web_client/panels/DrawWidget.js",
|
|
79
67
|
"histomicsui/web_client/panels/FrameSelectorWidget.js",
|
|
@@ -82,13 +70,17 @@
|
|
|
82
70
|
"histomicsui/web_client/panels/OverviewWidget.js",
|
|
83
71
|
"histomicsui/web_client/panels/RegionSelector.js",
|
|
84
72
|
"histomicsui/web_client/panels/ZoomWidget.js",
|
|
73
|
+
"histomicsui/web_client/panels/index.js",
|
|
74
|
+
"histomicsui/web_client/playwright.config.ts",
|
|
75
|
+
"histomicsui/web_client/router.js",
|
|
76
|
+
"histomicsui/web_client/routes.js",
|
|
85
77
|
"histomicsui/web_client/static/favicon.png",
|
|
86
78
|
"histomicsui/web_client/stylesheets/body/configView.styl",
|
|
87
79
|
"histomicsui/web_client/stylesheets/body/image.styl",
|
|
80
|
+
"histomicsui/web_client/stylesheets/dialogs/editStyleGroups.styl",
|
|
88
81
|
"histomicsui/web_client/stylesheets/dialogs/metadataPlot.styl",
|
|
89
82
|
"histomicsui/web_client/stylesheets/dialogs/openAnnotatedImage.styl",
|
|
90
83
|
"histomicsui/web_client/stylesheets/dialogs/saveAnnotation.styl",
|
|
91
|
-
"histomicsui/web_client/stylesheets/dialogs/editStyleGroups.styl",
|
|
92
84
|
"histomicsui/web_client/stylesheets/layout/header.styl",
|
|
93
85
|
"histomicsui/web_client/stylesheets/layout/headerAnalyses.styl",
|
|
94
86
|
"histomicsui/web_client/stylesheets/layout/headerImage.styl",
|
|
@@ -105,7 +97,6 @@
|
|
|
105
97
|
"histomicsui/web_client/stylesheets/popover/annotationPopover.styl",
|
|
106
98
|
"histomicsui/web_client/stylesheets/views/itemList.styl",
|
|
107
99
|
"histomicsui/web_client/stylesheets/views/searchResultsView.styl",
|
|
108
|
-
"histomicsui/web_client/templates/elementProps.pug",
|
|
109
100
|
"histomicsui/web_client/templates/body/configView.pug",
|
|
110
101
|
"histomicsui/web_client/templates/body/image.pug",
|
|
111
102
|
"histomicsui/web_client/templates/dialogs/annotatedImageList.pug",
|
|
@@ -117,6 +108,7 @@
|
|
|
117
108
|
"histomicsui/web_client/templates/dialogs/openAnnotatedImage.pug",
|
|
118
109
|
"histomicsui/web_client/templates/dialogs/openImage.pug",
|
|
119
110
|
"histomicsui/web_client/templates/dialogs/saveAnnotation.pug",
|
|
111
|
+
"histomicsui/web_client/templates/elementProps.pug",
|
|
120
112
|
"histomicsui/web_client/templates/layout/header.pug",
|
|
121
113
|
"histomicsui/web_client/templates/layout/headerAnalyses.pug",
|
|
122
114
|
"histomicsui/web_client/templates/layout/headerImage.pug",
|
|
@@ -136,57 +128,69 @@
|
|
|
136
128
|
"histomicsui/web_client/templates/popover/annotationPopover.pug",
|
|
137
129
|
"histomicsui/web_client/templates/popover/annotationPopoverMetadata.pug",
|
|
138
130
|
"histomicsui/web_client/templates/popover/pixelmapContextMenu.pug",
|
|
131
|
+
"histomicsui/web_client/tests/server.ts",
|
|
132
|
+
"histomicsui/web_client/tests/spec/viewer.spec.ts",
|
|
133
|
+
"histomicsui/web_client/tests/util.ts",
|
|
134
|
+
"histomicsui/web_client/tsconfig.json",
|
|
135
|
+
"histomicsui/web_client/utilities/allowedGroups.js",
|
|
136
|
+
"histomicsui/web_client/vendor/localStorage/driver.js",
|
|
137
|
+
"histomicsui/web_client/vendor/localStorage/localstorage.js",
|
|
138
|
+
"histomicsui/web_client/vendor/localStorage/sync.js",
|
|
139
|
+
"histomicsui/web_client/vendor/localStorage/utils.js",
|
|
139
140
|
"histomicsui/web_client/views/HierarchyWidget.js",
|
|
140
141
|
"histomicsui/web_client/views/JobDetailsWidget.js",
|
|
141
142
|
"histomicsui/web_client/views/View.js",
|
|
143
|
+
"histomicsui/web_client/views/body/ConfigView.js",
|
|
144
|
+
"histomicsui/web_client/views/body/ImageView.js",
|
|
145
|
+
"histomicsui/web_client/views/body/index.js",
|
|
142
146
|
"histomicsui/web_client/views/index.js",
|
|
143
147
|
"histomicsui/web_client/views/itemList.js",
|
|
144
148
|
"histomicsui/web_client/views/itemPage.js",
|
|
145
|
-
"histomicsui/web_client/views/searchResultsView.js",
|
|
146
|
-
"histomicsui/web_client/views/utils.js",
|
|
147
|
-
"histomicsui/web_client/views/body/index.js",
|
|
148
|
-
"histomicsui/web_client/views/body/ConfigView.js",
|
|
149
|
-
"histomicsui/web_client/views/body/ImageView.js",
|
|
150
|
-
"histomicsui/web_client/views/layout/HeaderView.js",
|
|
151
149
|
"histomicsui/web_client/views/layout/HeaderAnalysesView.js",
|
|
152
150
|
"histomicsui/web_client/views/layout/HeaderImageView.js",
|
|
153
151
|
"histomicsui/web_client/views/layout/HeaderUserView.js",
|
|
152
|
+
"histomicsui/web_client/views/layout/HeaderView.js",
|
|
154
153
|
"histomicsui/web_client/views/layout/LoginView.js",
|
|
155
154
|
"histomicsui/web_client/views/layout/index.js",
|
|
156
|
-
"histomicsui/web_client/views/popover/PixelmapContextMenu.js",
|
|
157
|
-
"histomicsui/web_client/views/popover/index.js",
|
|
158
155
|
"histomicsui/web_client/views/popover/AnnotationContextMenu.js",
|
|
159
156
|
"histomicsui/web_client/views/popover/AnnotationPopover.js",
|
|
160
|
-
"histomicsui/web_client/
|
|
157
|
+
"histomicsui/web_client/views/popover/PixelmapContextMenu.js",
|
|
158
|
+
"histomicsui/web_client/views/popover/index.js",
|
|
159
|
+
"histomicsui/web_client/views/searchResultsView.js",
|
|
160
|
+
"histomicsui/web_client/views/utils.js",
|
|
161
|
+
"histomicsui/web_client/vite-env.d.ts",
|
|
162
|
+
"histomicsui/web_client/vite.config.ts",
|
|
161
163
|
"histomicsui/web_client/vue/components/AnnotationHistoryBrowser.vue",
|
|
162
|
-
"histomicsui/web_client/vue/components/ColorPickerInput.vue",
|
|
163
164
|
"histomicsui/web_client/vue/components/AnnotationHistoryBrowserContainer.vue",
|
|
164
165
|
"histomicsui/web_client/vue/components/AnnotationHistoryGroup.vue",
|
|
166
|
+
"histomicsui/web_client/vue/components/ColorPickerInput.vue",
|
|
165
167
|
"histomicsui/web_client/vue/components/EditHeatmapOrGridData.vue",
|
|
166
168
|
"histomicsui/web_client/vue/components/EditHeatmapOrGridDataContainer.vue",
|
|
167
|
-
"histomicsui/web_client/
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
169
|
+
"histomicsui/web_client/vue/index.js",
|
|
170
|
+
"pyproject.toml",
|
|
171
|
+
"requirements-dev.txt",
|
|
172
|
+
"ruff.toml",
|
|
173
|
+
"sample_data/Easy1.png",
|
|
174
|
+
"sample_data/sample_svs_image.TCGA-DU-6399-01A-01-TS1.e8eb65de-d63e-42db-af6f-14fefbbdf7bd.svs",
|
|
175
|
+
"setup.cfg",
|
|
176
|
+
"setup.py",
|
|
174
177
|
"tests/__init__.py",
|
|
178
|
+
"tests/conftest.py",
|
|
175
179
|
"tests/datastore.py",
|
|
176
180
|
"tests/girder_utilities.py",
|
|
177
|
-
"tests/test_image_browse_endpoints.py",
|
|
178
|
-
"tests/test_load.py",
|
|
179
|
-
"tests/test_tcga.py",
|
|
180
|
-
"tests/conftest.py",
|
|
181
|
-
"tests/test_handlers.py",
|
|
182
|
-
"tests/test_hui_rest.py",
|
|
183
181
|
"tests/test_files/.histomicsui_config.yaml",
|
|
184
182
|
"tests/test_files/sample.anot",
|
|
185
183
|
"tests/test_files/sample.meta",
|
|
186
184
|
"tests/test_files/sample_girder_id.anot",
|
|
187
185
|
"tests/test_files/test_analysis_detection.xml",
|
|
188
186
|
"tests/test_files/test_analysis_features.xml",
|
|
187
|
+
"tests/test_handlers.py",
|
|
188
|
+
"tests/test_hui_rest.py",
|
|
189
|
+
"tests/test_image_browse_endpoints.py",
|
|
190
|
+
"tests/test_load.py",
|
|
191
|
+
"tests/test_tcga.py",
|
|
189
192
|
"tests/web_client_specs/.eslintrc",
|
|
193
|
+
"tests/web_client_specs/allowedGroupsSpec.js",
|
|
190
194
|
"tests/web_client_specs/analysisSpec.js",
|
|
191
195
|
"tests/web_client_specs/annotationSpec.js",
|
|
192
196
|
"tests/web_client_specs/girderUISpec.js",
|
|
@@ -198,7 +202,6 @@
|
|
|
198
202
|
"tests/web_client_specs/overviewPanelSpec.js",
|
|
199
203
|
"tests/web_client_specs/panelLayoutSpec.js",
|
|
200
204
|
"tests/web_client_specs/pixelmapCategorySpec.js",
|
|
201
|
-
"
|
|
202
|
-
"sample_data/sample_svs_image.TCGA-DU-6399-01A-01-TS1.e8eb65de-d63e-42db-af6f-14fefbbdf7bd.svs"
|
|
205
|
+
"tox.ini"
|
|
203
206
|
]
|
|
204
207
|
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/* globals describe, it, expect, waitsFor, runs, huiTest, girderTest */
|
|
2
|
+
|
|
3
|
+
girderTest.importPlugin(
|
|
4
|
+
'jobs', 'large_image', 'large_image_annotation', 'slicer_cli_web', 'histomicsui'
|
|
5
|
+
);
|
|
6
|
+
girderTest.addScripts([
|
|
7
|
+
'/static/built/plugins/histomicsui/huiTest.js',
|
|
8
|
+
'/static/built/plugins/histomicsui/extra/sinon.js'
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
girderTest.promise.done(function () {
|
|
12
|
+
huiTest.startApp();
|
|
13
|
+
|
|
14
|
+
describe('allowed_groups annotation metadata tests', function () {
|
|
15
|
+
var girder, largeImageAnnotation, histomicsUI;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* POST a new annotation with the given name/attributes/elements and fetch it back into a
|
|
19
|
+
* fresh AnnotationModel, storing the result on `result.annotation`.
|
|
20
|
+
*/
|
|
21
|
+
function createAnnotation(name, attributes, elements, result) {
|
|
22
|
+
var annotationId;
|
|
23
|
+
runs(function () {
|
|
24
|
+
girder.rest.restRequest({
|
|
25
|
+
url: 'annotation?itemId=' + huiTest.imageId(),
|
|
26
|
+
contentType: 'application/json',
|
|
27
|
+
processData: false,
|
|
28
|
+
type: 'POST',
|
|
29
|
+
data: JSON.stringify({
|
|
30
|
+
name: name,
|
|
31
|
+
attributes: attributes,
|
|
32
|
+
elements: elements
|
|
33
|
+
})
|
|
34
|
+
}).then(function (resp) {
|
|
35
|
+
annotationId = resp._id;
|
|
36
|
+
return null;
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
waitsFor(function () {
|
|
40
|
+
return annotationId !== undefined;
|
|
41
|
+
});
|
|
42
|
+
girderTest.waitForLoad();
|
|
43
|
+
runs(function () {
|
|
44
|
+
result.annotation = new largeImageAnnotation.models.AnnotationModel({
|
|
45
|
+
_id: annotationId
|
|
46
|
+
});
|
|
47
|
+
result.fetched = false;
|
|
48
|
+
result.annotation.fetch().then(function () {
|
|
49
|
+
result.fetched = true;
|
|
50
|
+
return null;
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
waitsFor(function () {
|
|
54
|
+
return result.fetched;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function rectangleElement(x, y) {
|
|
59
|
+
return {type: 'rectangle', center: [x, y, 0], width: 4, height: 4};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('setup', function () {
|
|
63
|
+
it('login', function () {
|
|
64
|
+
huiTest.login();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('open image', function () {
|
|
68
|
+
huiTest.openImage('image');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('access plugin namespaces', function () {
|
|
72
|
+
girder = window.girder;
|
|
73
|
+
largeImageAnnotation = girder.plugins.large_image_annotation;
|
|
74
|
+
histomicsUI = girder.plugins.histomicsui;
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('#1/#2: no restriction (missing or empty allowed_groups)', function () {
|
|
79
|
+
var result = {};
|
|
80
|
+
var drawWidget;
|
|
81
|
+
|
|
82
|
+
it('creates an annotation with no allowed_groups key', function () {
|
|
83
|
+
createAnnotation('unrestricted annotation', {}, [rectangleElement(0, 0)], result);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('offers every existing group in the Draw panel dropdown', function () {
|
|
87
|
+
var bodyView = huiTest.app.bodyView;
|
|
88
|
+
bodyView.annotations.add(result.annotation);
|
|
89
|
+
bodyView._editAnnotation(result.annotation);
|
|
90
|
+
drawWidget = bodyView.drawWidget;
|
|
91
|
+
waitsFor(function () {
|
|
92
|
+
return !!drawWidget._groups.length;
|
|
93
|
+
});
|
|
94
|
+
runs(function () {
|
|
95
|
+
expect(drawWidget._getAllowedGroups()).toBe(null);
|
|
96
|
+
var expectedIds = drawWidget._groups.map(function (m) { return m.id; }).sort();
|
|
97
|
+
var values = drawWidget.$('.h-style-group option').map(function () {
|
|
98
|
+
return this.value;
|
|
99
|
+
}).get().sort();
|
|
100
|
+
expect(values).toEqual(expectedIds);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('offers every existing group in the context menu', function () {
|
|
105
|
+
var bodyView = huiTest.app.bodyView;
|
|
106
|
+
var element = result.annotation.elements().first();
|
|
107
|
+
bodyView._resetSelection();
|
|
108
|
+
bodyView._selectElement(element);
|
|
109
|
+
var groups = bodyView.contextMenu._getAnnotationGroups();
|
|
110
|
+
var expectedIds = bodyView.contextMenu.styles.map(function (m) { return m.id; });
|
|
111
|
+
expect(groups.sort()).toEqual(expectedIds.sort());
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('treats an empty allowed_groups list the same as no restriction', function () {
|
|
115
|
+
result.annotation.get('annotation').attributes = {allowed_groups: []};
|
|
116
|
+
expect(drawWidget._getAllowedGroups()).toBe(null);
|
|
117
|
+
result.annotation.get('annotation').attributes = {allowed_groups: 'not-an-array'};
|
|
118
|
+
expect(drawWidget._getAllowedGroups()).toBe(null);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('accepts a JSON-stringified array as allowed_groups', function () {
|
|
122
|
+
result.annotation.get('annotation').attributes = {
|
|
123
|
+
allowed_groups: '["groupA", "groupB"]'
|
|
124
|
+
};
|
|
125
|
+
expect(drawWidget._getAllowedGroups()).toEqual(['groupA', 'groupB']);
|
|
126
|
+
result.annotation.get('annotation').attributes = {allowed_groups: '[]'};
|
|
127
|
+
expect(drawWidget._getAllowedGroups()).toBe(null);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('#3/#4: restricted annotation, including auto-created groups', function () {
|
|
132
|
+
var result = {};
|
|
133
|
+
var drawWidget;
|
|
134
|
+
var defaultStyle;
|
|
135
|
+
|
|
136
|
+
it('records the default group style for comparison', function () {
|
|
137
|
+
// StyleModel has no url/urlRoot; styles are only persisted via
|
|
138
|
+
// backbone.localStorage, which is patched onto the *collection*. So a
|
|
139
|
+
// bare model must be fetched through a StyleCollection, not directly.
|
|
140
|
+
var styles = new histomicsUI.collections.StyleCollection();
|
|
141
|
+
var fetched = false;
|
|
142
|
+
runs(function () {
|
|
143
|
+
styles.fetch().always(function () {
|
|
144
|
+
fetched = true;
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
waitsFor(function () {
|
|
148
|
+
return fetched;
|
|
149
|
+
});
|
|
150
|
+
runs(function () {
|
|
151
|
+
defaultStyle = styles.get('default');
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('creates an annotation restricted to a mix of missing groups', function () {
|
|
156
|
+
createAnnotation('restricted annotation', {
|
|
157
|
+
allowed_groups: ['groupA', 'groupB']
|
|
158
|
+
}, [rectangleElement(10, 10)], result);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('#4a/#4b: auto-creates every missing allowed group using the default style', function () {
|
|
162
|
+
var bodyView = huiTest.app.bodyView;
|
|
163
|
+
bodyView.annotations.add(result.annotation);
|
|
164
|
+
bodyView._editAnnotation(result.annotation);
|
|
165
|
+
drawWidget = bodyView.drawWidget;
|
|
166
|
+
waitsFor(function () {
|
|
167
|
+
return drawWidget._groups.has('groupA') && drawWidget._groups.has('groupB');
|
|
168
|
+
});
|
|
169
|
+
runs(function () {
|
|
170
|
+
['groupA', 'groupB'].forEach(function (groupId) {
|
|
171
|
+
var created = drawWidget._groups.get(groupId).toJSON();
|
|
172
|
+
expect(created.fillColor).toBe(defaultStyle.get('fillColor'));
|
|
173
|
+
expect(created.lineColor).toBe(defaultStyle.get('lineColor'));
|
|
174
|
+
expect(created.lineWidth).toBe(defaultStyle.get('lineWidth'));
|
|
175
|
+
expect(created.pattern).toBe(defaultStyle.get('pattern'));
|
|
176
|
+
});
|
|
177
|
+
// the active style switches to the first allowed group
|
|
178
|
+
expect(drawWidget._style.id).toBe('groupA');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('#3/#4c: restriction is immediately reflected in the Draw panel dropdown', function () {
|
|
183
|
+
var values = drawWidget.$('.h-style-group option').map(function () {
|
|
184
|
+
return this.value;
|
|
185
|
+
}).get();
|
|
186
|
+
expect(values).toEqual(['groupA', 'groupB']);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('#3/#4c: restriction is immediately reflected in the context menu', function () {
|
|
190
|
+
var bodyView = huiTest.app.bodyView;
|
|
191
|
+
// select an element of the restricted annotation so the context menu's group
|
|
192
|
+
// list reflects it, rather than a stale selection left over from a previous
|
|
193
|
+
// describe block
|
|
194
|
+
var element = result.annotation.elements().first();
|
|
195
|
+
bodyView._resetSelection();
|
|
196
|
+
bodyView._selectElement(element);
|
|
197
|
+
|
|
198
|
+
var groups = bodyView.contextMenu._getAnnotationGroups();
|
|
199
|
+
expect(groups.sort()).toEqual(['groupA', 'groupB']);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('#5: context menu ignores active selection, uses the clicked annotation', function () {
|
|
204
|
+
var restricted = {};
|
|
205
|
+
var unrestricted = {};
|
|
206
|
+
|
|
207
|
+
it('creates a restricted and an unrestricted annotation', function () {
|
|
208
|
+
createAnnotation('restricted annotation for #5', {
|
|
209
|
+
allowed_groups: ['groupE', 'groupF']
|
|
210
|
+
}, [rectangleElement(30, 30)], restricted);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('creates the unrestricted annotation', function () {
|
|
214
|
+
createAnnotation('unrestricted annotation for #5', {}, [rectangleElement(40, 40)], unrestricted);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('auto-creates the restricted annotation\'s allowed groups (groupE/groupF) as styles', function () {
|
|
218
|
+
// briefly edit the restricted annotation in the Draw panel to create groupE and
|
|
219
|
+
// groupF before switching the active annotation below.
|
|
220
|
+
var bodyView = huiTest.app.bodyView;
|
|
221
|
+
bodyView.annotations.add(restricted.annotation);
|
|
222
|
+
bodyView._editAnnotation(restricted.annotation);
|
|
223
|
+
waitsFor(function () {
|
|
224
|
+
return !!bodyView.drawWidget &&
|
|
225
|
+
bodyView.drawWidget._groups.has('groupE') &&
|
|
226
|
+
bodyView.drawWidget._groups.has('groupF');
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('restricts the context menu to the clicked element\'s annotation regardless of the active annotation/group/shape', function () {
|
|
231
|
+
var bodyView = huiTest.app.bodyView;
|
|
232
|
+
|
|
233
|
+
runs(function () {
|
|
234
|
+
bodyView.annotations.add(unrestricted.annotation);
|
|
235
|
+
bodyView._editAnnotation(unrestricted.annotation);
|
|
236
|
+
});
|
|
237
|
+
waitsFor(function () {
|
|
238
|
+
return !!bodyView.drawWidget && !!bodyView.drawWidget._groups.length;
|
|
239
|
+
});
|
|
240
|
+
runs(function () {
|
|
241
|
+
// pick an arbitrary style group in the Draw panel to prove the context menu
|
|
242
|
+
// restriction is independent of it
|
|
243
|
+
bodyView.drawWidget.setStyleGroupById(bodyView.drawWidget._groups.first().id);
|
|
244
|
+
|
|
245
|
+
var element = restricted.annotation.elements().first();
|
|
246
|
+
bodyView._resetSelection();
|
|
247
|
+
bodyView._selectElement(element);
|
|
248
|
+
|
|
249
|
+
var groups = bodyView.contextMenu._getAnnotationGroups();
|
|
250
|
+
expect(groups.sort()).toEqual(['groupE', 'groupF']);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('renders the clicked annotation\'s restriction on selection, not the active annotation\'s (regression)', function () {
|
|
255
|
+
var bodyView = huiTest.app.bodyView;
|
|
256
|
+
|
|
257
|
+
runs(function () {
|
|
258
|
+
// keep the *unrestricted* annotation active in the panel
|
|
259
|
+
bodyView._editAnnotation(unrestricted.annotation);
|
|
260
|
+
});
|
|
261
|
+
waitsFor(function () {
|
|
262
|
+
return !!bodyView.drawWidget && !!bodyView.drawWidget._groups.length;
|
|
263
|
+
});
|
|
264
|
+
runs(function () {
|
|
265
|
+
// Selecting an element fires the context menu's render synchronously.
|
|
266
|
+
// This asserts on the DOM produced by that render, which is the path that
|
|
267
|
+
// regressed. Previously `originalAnnotation` was assigned only after `add`,
|
|
268
|
+
// so the render fell back to the active annotation and offered the wrong
|
|
269
|
+
// groups when the active annotation did not match the selected one.
|
|
270
|
+
var element = restricted.annotation.elements().first();
|
|
271
|
+
bodyView._resetSelection();
|
|
272
|
+
bodyView._selectElement(element);
|
|
273
|
+
|
|
274
|
+
var renderedGroups = bodyView.contextMenu.$('.h-set-group').map(function () {
|
|
275
|
+
return window.$(this).data('group');
|
|
276
|
+
}).get();
|
|
277
|
+
expect(renderedGroups.sort()).toEqual(['groupE', 'groupF']);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe('#3/#5: live metadata updates without reselecting or reloading', function () {
|
|
283
|
+
var result = {};
|
|
284
|
+
var drawWidget;
|
|
285
|
+
|
|
286
|
+
it('creates an annotation with no restriction', function () {
|
|
287
|
+
createAnnotation('live-update annotation', {}, [rectangleElement(50, 50)], result);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('opens the annotation while unrestricted', function () {
|
|
291
|
+
var bodyView = huiTest.app.bodyView;
|
|
292
|
+
bodyView.annotations.add(result.annotation);
|
|
293
|
+
bodyView._editAnnotation(result.annotation);
|
|
294
|
+
drawWidget = bodyView.drawWidget;
|
|
295
|
+
waitsFor(function () {
|
|
296
|
+
return !!drawWidget._groups.length;
|
|
297
|
+
});
|
|
298
|
+
runs(function () {
|
|
299
|
+
expect(drawWidget._getAllowedGroups()).toBe(null);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('immediately restricts the Draw panel and context menu when allowed_groups is added, without reselecting', function () {
|
|
304
|
+
var bodyView = huiTest.app.bodyView;
|
|
305
|
+
|
|
306
|
+
var element = result.annotation.elements().first();
|
|
307
|
+
bodyView._resetSelection();
|
|
308
|
+
bodyView._selectElement(element);
|
|
309
|
+
|
|
310
|
+
// simulate editing the annotation's metadata via the "Edit annotation" dialog,
|
|
311
|
+
// which mutates attributes directly and triggers 'change:annotation' rather than
|
|
312
|
+
// calling .set()
|
|
313
|
+
result.annotation.get('annotation').attributes = {allowed_groups: ['groupG', 'groupH']};
|
|
314
|
+
result.annotation.trigger('change:annotation', result.annotation, {});
|
|
315
|
+
|
|
316
|
+
waitsFor(function () {
|
|
317
|
+
// the Draw panel's `_groups` collection updates synchronously, but its dropdown
|
|
318
|
+
// DOM is refreshed via a debounced render, so also wait for the DOM to catch up
|
|
319
|
+
// before asserting on it
|
|
320
|
+
return drawWidget._groups.has('groupG') && drawWidget._groups.has('groupH') &&
|
|
321
|
+
drawWidget.$('.h-style-group option').length === 2;
|
|
322
|
+
});
|
|
323
|
+
runs(function () {
|
|
324
|
+
expect(drawWidget._style.id).toBe('groupG');
|
|
325
|
+
var drawValues = drawWidget.$('.h-style-group option').map(function () {
|
|
326
|
+
return this.value;
|
|
327
|
+
}).get();
|
|
328
|
+
expect(drawValues).toEqual(['groupG', 'groupH']);
|
|
329
|
+
});
|
|
330
|
+
// the context menu keeps its own StyleCollection, refetched asynchronously via the
|
|
331
|
+
// 'h:styleGroupsEdited' event once the Draw panel auto-creates the newly allowed
|
|
332
|
+
// groups; wait for that refetch to complete before checking it
|
|
333
|
+
waitsFor(function () {
|
|
334
|
+
return bodyView.contextMenu.styles.get('groupG') && bodyView.contextMenu.styles.get('groupH');
|
|
335
|
+
});
|
|
336
|
+
runs(function () {
|
|
337
|
+
var contextGroups = bodyView.contextMenu._getAnnotationGroups();
|
|
338
|
+
expect(contextGroups.sort()).toEqual(['groupG', 'groupH']);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
describe('#3(consistency): the context menu auto-creates missing allowed groups', function () {
|
|
344
|
+
var restricted = {};
|
|
345
|
+
|
|
346
|
+
it('creates a restricted annotation that is never opened in the Draw panel', function () {
|
|
347
|
+
createAnnotation('context-only restricted annotation', {
|
|
348
|
+
allowed_groups: ['groupK', 'groupL']
|
|
349
|
+
}, [rectangleElement(70, 70)], restricted);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('auto-creates the allowed groups the first time the context menu sees them', function () {
|
|
353
|
+
var bodyView = huiTest.app.bodyView;
|
|
354
|
+
// the groups must not already exist from an earlier spec
|
|
355
|
+
expect(bodyView.contextMenu.styles.get('groupK')).toBe(undefined);
|
|
356
|
+
expect(bodyView.contextMenu.styles.get('groupL')).toBe(undefined);
|
|
357
|
+
|
|
358
|
+
// select an element of the restricted annotation without ever opening it in the
|
|
359
|
+
// Draw panel, so the context menu is the only code path that can create its groups
|
|
360
|
+
var element = restricted.annotation.elements().first();
|
|
361
|
+
bodyView._resetSelection();
|
|
362
|
+
bodyView._selectElement(element);
|
|
363
|
+
|
|
364
|
+
var groups = bodyView.contextMenu._getAnnotationGroups();
|
|
365
|
+
expect(groups.sort()).toEqual(['groupK', 'groupL']);
|
|
366
|
+
expect(bodyView.contextMenu.styles.get('groupK')).toBeTruthy();
|
|
367
|
+
expect(bodyView.contextMenu.styles.get('groupL')).toBeTruthy();
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
});
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/annotationSpec.js
RENAMED
|
@@ -276,13 +276,21 @@ girderTest.promise.done(function () {
|
|
|
276
276
|
return $('.h-elements-container .h-element').length === 2;
|
|
277
277
|
}, 'point to be created');
|
|
278
278
|
runs(function () {
|
|
279
|
-
|
|
279
|
+
// Elements are sorted lexically by label, so target the newly drawn point by
|
|
280
|
+
// its label rather than by position.
|
|
281
|
+
expect($('.h-elements-container .h-element .h-element-label').filter(function () {
|
|
282
|
+
return $(this).text() === 'default point 2';
|
|
283
|
+
}).length).toBe(1);
|
|
280
284
|
});
|
|
281
285
|
checkAutoSave('drawn 1', 2, annotationInfo);
|
|
282
286
|
});
|
|
283
287
|
|
|
284
288
|
it('delete the second point', function () {
|
|
285
|
-
|
|
289
|
+
// Elements are sorted lexically by label, so delete the just drawn point by its
|
|
290
|
+
// label rather than by position.
|
|
291
|
+
$('.h-elements-container .h-element').filter(function () {
|
|
292
|
+
return $(this).find('.h-element-label').text() === 'default point 2';
|
|
293
|
+
}).find('.h-delete-element').click();
|
|
286
294
|
expect($('.h-elements-container .h-element').length).toBe(1);
|
|
287
295
|
checkAutoSave('drawn 1', 1, annotationInfo);
|
|
288
296
|
});
|
|
@@ -312,7 +320,11 @@ girderTest.promise.done(function () {
|
|
|
312
320
|
return $('.h-elements-container .h-element').length === 2;
|
|
313
321
|
}, 'point to be created');
|
|
314
322
|
runs(function () {
|
|
315
|
-
|
|
323
|
+
// Elements are sorted lexically by label, so target the newly drawn point by
|
|
324
|
+
// its label rather than by position.
|
|
325
|
+
expect($('.h-elements-container .h-element .h-element-label').filter(function () {
|
|
326
|
+
return $(this).text() === 'default point 2';
|
|
327
|
+
}).length).toBe(1);
|
|
316
328
|
});
|
|
317
329
|
checkAutoSave('drawn 1', 2, annotationInfo);
|
|
318
330
|
});
|
|
@@ -349,7 +361,11 @@ girderTest.promise.done(function () {
|
|
|
349
361
|
});
|
|
350
362
|
|
|
351
363
|
it('delete the last point', function () {
|
|
352
|
-
|
|
364
|
+
// Elements are sorted lexically by label, so delete the just drawn point by its
|
|
365
|
+
// label rather than by position.
|
|
366
|
+
$('.h-elements-container .h-element').filter(function () {
|
|
367
|
+
return $(this).find('.h-element-label').text() === 'default point 2';
|
|
368
|
+
}).find('.h-delete-element').click();
|
|
353
369
|
expect($('.h-elements-container .h-element').length).toBe(1);
|
|
354
370
|
|
|
355
371
|
// reset the draw state
|
|
@@ -609,6 +625,106 @@ girderTest.promise.done(function () {
|
|
|
609
625
|
});
|
|
610
626
|
});
|
|
611
627
|
|
|
628
|
+
describe('Sort By', function () {
|
|
629
|
+
var drawWidget;
|
|
630
|
+
var testLabels = ['Alpha', 'Bravo', 'Charlie', 'Delta'];
|
|
631
|
+
var testIds = ['sort-test-alpha', 'sort-test-bravo', 'sort-test-charlie', 'sort-test-delta'];
|
|
632
|
+
|
|
633
|
+
function testElementLabels() {
|
|
634
|
+
return $('.h-elements-container .h-element-label').map(function () {
|
|
635
|
+
return $(this).text();
|
|
636
|
+
}).get().filter(function (text) {
|
|
637
|
+
return testLabels.indexOf(text) !== -1;
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
it('add elements with distinct labels, groups, and shapes', function () {
|
|
642
|
+
runs(function () {
|
|
643
|
+
drawWidget = huiTest.app.bodyView.drawWidget;
|
|
644
|
+
drawWidget.collection.add([
|
|
645
|
+
{id: 'sort-test-charlie', type: 'point', label: {value: 'Charlie'}, group: 'rareGroup'},
|
|
646
|
+
{id: 'sort-test-alpha', type: 'point', label: {value: 'Alpha'}, group: 'commonGroup'},
|
|
647
|
+
{id: 'sort-test-bravo', type: 'rectangle', label: {value: 'Bravo'}, group: 'commonGroup'},
|
|
648
|
+
{id: 'sort-test-delta', type: 'polyline', closed: false, label: {value: 'Delta'}, group: 'commonGroup'}
|
|
649
|
+
]);
|
|
650
|
+
});
|
|
651
|
+
waitsFor(function () {
|
|
652
|
+
return testElementLabels().length === testLabels.length;
|
|
653
|
+
}, 'test elements to be added');
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it('defaults to sorting by label, ascending', function () {
|
|
657
|
+
runs(function () {
|
|
658
|
+
expect($('.h-sort-mode').val()).toBe('label');
|
|
659
|
+
expect($('.h-sort-order i').hasClass('icon-sort-alt-up')).toBe(true);
|
|
660
|
+
expect(testElementLabels()).toEqual(['Alpha', 'Bravo', 'Charlie', 'Delta']);
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it('toggles to descending order', function () {
|
|
665
|
+
runs(function () {
|
|
666
|
+
$('.h-sort-order').click();
|
|
667
|
+
});
|
|
668
|
+
runs(function () {
|
|
669
|
+
expect($('.h-sort-order i').hasClass('icon-sort-alt-down')).toBe(true);
|
|
670
|
+
expect($('.h-sort-order').attr('title')).toMatch(/^Sort descending/);
|
|
671
|
+
expect(testElementLabels()).toEqual(['Delta', 'Charlie', 'Bravo', 'Alpha']);
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
it('toggles back to ascending order', function () {
|
|
676
|
+
runs(function () {
|
|
677
|
+
$('.h-sort-order').click();
|
|
678
|
+
});
|
|
679
|
+
runs(function () {
|
|
680
|
+
expect($('.h-sort-order i').hasClass('icon-sort-alt-up')).toBe(true);
|
|
681
|
+
expect($('.h-sort-order').attr('title')).toMatch(/^Sort ascending/);
|
|
682
|
+
expect(testElementLabels()).toEqual(['Alpha', 'Bravo', 'Charlie', 'Delta']);
|
|
683
|
+
});
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
it('sorts by group', function () {
|
|
687
|
+
runs(function () {
|
|
688
|
+
$('.h-sort-mode').val('group').trigger('change');
|
|
689
|
+
});
|
|
690
|
+
runs(function () {
|
|
691
|
+
var order = testElementLabels();
|
|
692
|
+
// "commonGroup" sorts before "rareGroup" lexically.
|
|
693
|
+
expect(order.indexOf('Charlie')).toBe(order.length - 1);
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
it('sorts by shape', function () {
|
|
698
|
+
runs(function () {
|
|
699
|
+
$('.h-sort-mode').val('shape').trigger('change');
|
|
700
|
+
});
|
|
701
|
+
runs(function () {
|
|
702
|
+
var order = testElementLabels();
|
|
703
|
+
expect(order.indexOf('Delta')).toBeLessThan(order.indexOf('Bravo'));
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
it('sorts by count, rare groups first', function () {
|
|
708
|
+
runs(function () {
|
|
709
|
+
$('.h-sort-mode').val('count').trigger('change');
|
|
710
|
+
});
|
|
711
|
+
runs(function () {
|
|
712
|
+
var order = testElementLabels();
|
|
713
|
+
expect(order[0]).toBe('Charlie');
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
it('removes the test elements and restores label sort', function () {
|
|
718
|
+
runs(function () {
|
|
719
|
+
drawWidget.collection.remove(testIds);
|
|
720
|
+
$('.h-sort-mode').val('label').trigger('change');
|
|
721
|
+
});
|
|
722
|
+
waitsFor(function () {
|
|
723
|
+
return testElementLabels().length === 0;
|
|
724
|
+
}, 'test elements to be removed');
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
|
|
612
728
|
describe('Annotation styles', function () {
|
|
613
729
|
it('create a new annotation', function () {
|
|
614
730
|
$('.h-create-annotation').click();
|
|
@@ -1812,6 +1928,11 @@ girderTest.promise.done(function () {
|
|
|
1812
1928
|
it('open image', function () {
|
|
1813
1929
|
huiTest.openImage('image.svs', ['subfolder']);
|
|
1814
1930
|
});
|
|
1931
|
+
it('respects unselected opacity config', function () {
|
|
1932
|
+
girderTest.waitForLoad();
|
|
1933
|
+
expect(huiTest.app.bodyView._unselectedOpacityMultiplier).toBe(0.5);
|
|
1934
|
+
expect(huiTest.app.bodyView.viewerWidget._unselectedOpacityMultiplier).toBe(0.5);
|
|
1935
|
+
});
|
|
1815
1936
|
it('create a new annotation', function () {
|
|
1816
1937
|
girderTest.waitForLoad();
|
|
1817
1938
|
runs(function () {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui/rest/image_browse_resource.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/histomicsui.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/sample_girder_id.anot
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/test_analysis_detection.xml
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/test_files/test_analysis_features.xml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/analysisSpec.js
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/girderUISpec.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/metadataPanelSpec.js
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/metadataPlotSpec.js
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/overviewPanelSpec.js
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/panelLayoutSpec.js
RENAMED
|
File without changes
|
{histomicsui-1.8.1.dev163 → histomicsui-1.8.1.dev194}/tests/web_client_specs/pixelmapCategorySpec.js
RENAMED
|
File without changes
|
|
File without changes
|