diff --git a/omero_mdv/urls.py b/omero_mdv/urls.py index 757322c..6bc4c84 100644 --- a/omero_mdv/urls.py +++ b/omero_mdv/urls.py @@ -18,23 +18,27 @@ re_path(r'^datasets_info/(?P[0-9]+)/$', views.datasets_info, name='mdv_datasets_info'), # MDV viewer - re_path(r"^config/(?P[0-9]+)/json/$", views.config_json, name='mdv_config_json'), + re_path(r"^project/(?P[0-9]+)/json/$", views.config_json, name='mdv_config_json'), # save configs, so a config ID is the FileAnnotation ID for JSON - re_path(r"^config/(?P[0-9]+)/datasources.json$", views.datasources, name='mdv_datasources'), + re_path(r"^project/(?P[0-9]+)/datasources.json$", views.datasources, name='mdv_datasources'), # list configs re_path(r'^open/$', views.list_mdv_configs, name="open_mdv"), # delete config re_path(r'^delete_mdv_config/$', views.delete_mdv_config, name="delete_mdv_config"), - re_path(r"^config/(?P[0-9]+)/state.json$", views.state, name='mdv_state'), - re_path(r"^config/(?P[0-9]+)/views.json$", views.views, name='mdv_views'), + re_path(r"^project/(?P[0-9]+)/state.json$", views.state, name='mdv_state'), + re_path(r"^project/(?P[0-9]+)/views.json$", views.views, name='mdv_views'), + # Not sure why we need get_view AND views.json? + re_path(r"^project/(?P[0-9]+)/get_view$", views.views, name='mdv_get_views'), + # get_data + re_path(r"^project/(?P[0-9]+)/get_data$", views.table_bytes, name='mdv_get_data'), # We name a table datasource mdv_config_ID, so we use that ID (ignore configid for now) - re_path(r"^config/(?P[0-9]+)/mdv_config_(?P[0-9]+).json$", views.table_cols_byte_offsets), - re_path(r"^config/(?P[0-9]+)/mdv_config_(?P[0-9]+).b$", views.table_bytes), + re_path(r"^project/(?P[0-9]+)/mdv_config_(?P[0-9]+).json$", views.table_cols_byte_offsets), + re_path(r"^project/(?P[0-9]+)/mdv_config_(?P[0-9]+).gz$", views.table_bytes), - re_path(r"^config/(?P[0-9]+)/thumbnail/(?P[0-9]+).png$", views.thumbnail), - re_path(r"^config/(?P[0-9]+)/image/(?P[0-9]+).png$", views.image), + re_path(r"^project/(?P[0-9]+)//thumbnail/(?P[0-9]+).png$", views.thumbnail), + re_path(r"^project/(?P[0-9]+)//image/(?P[0-9]+).png/$", views.image), # POST here when user hits "Save" button on MDV re_path(r"^meths/execute_project_action/$", views.save_view), diff --git a/omero_mdv/utils.py b/omero_mdv/utils.py index 34225ca..fa79c3d 100644 --- a/omero_mdv/utils.py +++ b/omero_mdv/utils.py @@ -487,8 +487,11 @@ def marshal_mdv_column(colname, kvp_by_id, primary_key_ids, bytes_offset): byte_count = len(get_column_bytes(kvp_data)) - if datatype == "text" and max_value_count > 1: - datatype = "multitext" + if datatype == "text": + if max_value_count > 1: + datatype = "multitext" + elif len(vals) > 256: + datatype = "text16" col = { "name": colname, "datatype": datatype, diff --git a/omero_mdv/views.py b/omero_mdv/views.py index ad1342a..b57c6c5 100644 --- a/omero_mdv/views.py +++ b/omero_mdv/views.py @@ -325,7 +325,7 @@ def get_column(name): # redirect to app, with absolute config URL... url = reverse("mdv_index") - config_url = f"config/{ann_id}/" + config_url = f"project/{ann_id}/" return HttpResponseRedirect("%s?dir=%s" % (url, config_url)) @@ -340,13 +340,14 @@ def get_webclient_links_column(image_ids, bytes_offset): values.append(f"{url}?show=image-{iid}") indices.append(index) - byte_count = len(get_column_bytes(indices)) + byte_count = len(get_column_bytes(indices, np.int16)) col = { "name": WEBCLIENT_LINK, "field": WEBCLIENT_LINK, "is_url": True, - "datatype": "text", + # text16 allows up to 65536 values instead of 256 + "datatype": "text16", "values": values, "bytes": [bytes_offset, bytes_offset + byte_count], "data": indices, @@ -454,17 +455,25 @@ def table_cols_byte_offsets(request, configid, conn=None, **kwargs): @login_required() def table_bytes(request, configid, conn=None, **kwargs): - range_header = request.headers['Range'] - m = re.search('(\d+)-(\d*)', range_header) - g = m.groups() + print("table_bytes....") + col_names = None + if request.method == "POST": + json_data = json.loads(request.body) + print("table_data POST", json_data) + col_names = [col["name"] for col in json_data.get("columns")] + print("col_names", col_names) - byte1 = int(g[0]) if g[0] else None - byte2 = int(g[1]) if g[1] else None + # range_header = request.headers['Range'] + # m = re.search('(\d+)-(\d*)', range_header) + # g = m.groups() - if byte1 is None or byte2 is None: - raise Http404( - "No byte 'Range' in request Header: got `%s-%s`" % (byte1, byte2)) - size = byte2 - byte1 + # byte1 = int(g[0]) if g[0] else None + # byte2 = int(g[1]) if g[1] else None + + # if byte1 is None or byte2 is None: + # raise Http404( + # "No byte 'Range' in request Header: got `%s-%s`" % (byte1, byte2)) + # size = byte2 - byte1 # get data from config... config_json = _config_json(conn, configid) @@ -475,7 +484,9 @@ def table_bytes(request, configid, conn=None, **kwargs): column_bytes = None # find the column that has the correct byte1 (used as column ID) for col in config_json["columns"]: - if col["bytes"][0] == byte1: + # if col["bytes"][0] == byte1: + if col["name"] in col_names: + print("col", col["name"]) # handle omero tables, load table below if "omero_table_file_id" in col: tableid = col.get("omero_table_file_id") @@ -484,9 +495,10 @@ def table_bytes(request, configid, conn=None, **kwargs): dtype = None if col["datatype"] == "text": dtype = np.int8 - elif col["datatype"] == "multitext": + elif col["datatype"] in ("multitext", "text16"): dtype = np.int16 column_bytes = get_column_bytes(col["data"], dtype) + break if tableid is not None: @@ -500,8 +512,9 @@ def table_bytes(request, configid, conn=None, **kwargs): finally: t.close() + print("bytes!", len(column_bytes)) rsp = HttpResponse(column_bytes, content_type="application/octet-stream") - rsp['Content-Range'] = 'bytes {0}-{1}/{2}'.format(byte1, byte2, size) + # rsp['Content-Range'] = 'bytes {0}-{1}/{2}'.format(byte1, byte2, size) rsp['Accept-Ranges'] = 'bytes' return rsp @@ -539,6 +552,12 @@ def views(request, configid, conn=None, **kwargs): # Load config_json = _config_json(conn, configid) + # Handle POST to project/ID/get_view... + view_name = None + if request.method == "POST": + json_data = json.loads(request.body) + view_name = json_data.get("view") + # If views exist, simply return them... if "views" in config_json: rsp = {} @@ -562,6 +581,9 @@ def views(request, configid, conn=None, **kwargs): ds[datasourceId] = ds_info view_config["dataSources"] = ds rsp[view_id] = view_config + + if view_name is not None and view_name in rsp: + rsp = rsp[view_name] return JsonResponse(rsp) # create a default view... @@ -583,7 +605,7 @@ def add_default_charts(config_json, charts=[], add_table=True, column_names = [] columns = config_json["columns"] # Don't add webclient-link column into Table - column_names = [col["name"] for col in columns if col["name"] != WEBCLIENT_LINK] + column_names = [col["name"] for col in columns] # if col["name"] != WEBCLIENT_LINK] image_col = None for idx, col in enumerate(columns): if col["name"].lower() == "image":