diff --git a/packages/slycat/web/server/engine.py b/packages/slycat/web/server/engine.py index 7fd48157a..3c6e9c096 100644 --- a/packages/slycat/web/server/engine.py +++ b/packages/slycat/web/server/engine.py @@ -158,6 +158,9 @@ def abspath(path): dispatcher.connect("post-remotes", "/remotes", slycat.web.server.handlers.post_remotes, conditions={"method" : ["POST"]}) dispatcher.connect("post-remotes-smb", "/remotes/smb", slycat.web.server.handlers.post_remotes_smb, conditions={"method" : ["POST"]}) dispatcher.connect("post-smb-browse", "/smb/remotes/:hostname/browse{path:.*}", slycat.web.server.handlers.post_smb_browse, conditions={"method" : ["POST"]}) + dispatcher.connect("post-hdf5-browse", "/hdf5/browse/:path/:pid/:mid", slycat.web.server.handlers.post_browse_hdf5, conditions={"method" : ["POST"]}) + dispatcher.connect("post-hdf5-table", "/hdf5/table/:path/:pid/:mid", slycat.web.server.handlers.post_hdf5_table, conditions={"method" : ["POST"]}) + dispatcher.connect("post-combine-hdf5-tables", "/hdf5/combine/:mid", slycat.web.server.handlers.post_combine_hdf5_tables, conditions={"method": ["POST"]}) dispatcher.connect("put-model-arrayset-array", "/models/:mid/arraysets/:aid/arrays/:array", slycat.web.server.handlers.put_model_arrayset_array, conditions={"method" : ["PUT"]}) dispatcher.connect("put-model-arrayset-data", "/models/:mid/arraysets/:aid/data", slycat.web.server.handlers.put_model_arrayset_data, conditions={"method" : ["PUT"]}) dispatcher.connect("put-model-arrayset", "/models/:mid/arraysets/:aid", slycat.web.server.handlers.put_model_arrayset, conditions={"method" : ["PUT"]}) diff --git a/packages/slycat/web/server/handlers.py b/packages/slycat/web/server/handlers.py index 71022e37a..f44e8e7f4 100644 --- a/packages/slycat/web/server/handlers.py +++ b/packages/slycat/web/server/handlers.py @@ -2702,7 +2702,6 @@ def post_remotes(): msg = "login could not save session for remote host" return {"sid": sid, "status": True, "msg": msg} - @cherrypy.tools.json_in(on=True) @cherrypy.tools.json_out(on=True) def post_remotes_smb(): @@ -2759,6 +2758,142 @@ def post_smb_browse(hostname, path): with slycat.web.server.smb.get_session(sid) as session: return session.browse(path=path) +def post_hdf5_table(path, pid, mid): + """ + Takes a user selected path inside an HDF5 file, and stores the + table at that path as either inputs or outputs for the model. + + path {string} -- path to table inside of HDF5 file + """ + # Need to find the HDF5 stored on Slycat server, so we can query it for the path. + path = path.replace('-', '/') + database = slycat.web.server.database.couchdb.connect() + model = database.get("model", mid) + project = database.get("project", pid) + did = model['project_data'][0] + project_data = database.get("project_data", did) + file_name = project_data['hdf5_name'] + hdf5_path = cherrypy.request.app.config["slycat-web-server"]["data-store"] + "/" + file_name + h5 = h5py.File(hdf5_path, 'r') + table = list(h5[path]) + column_headers = list(h5[path].dims[1][0]) + headers = [] + attributes = [] + dimensions = [{"name": "row", "type": "int64", "begin": 0, "end": len(table[0])}] + + if 'hdf5-inputs' not in model: + model['hdf5-inputs'] = path + else: + model['hdf5-outputs'] = path + slycat.web.server.authentication.require_project_writer(project) + database.save(model) + + cherrypy.response.status = "200 Project updated." + +def post_combine_hdf5_tables(mid): + """ + Combines user selected input/output tables inside of an HDF5 file into one table. + Uses the hdf5-input and hdf5-output paths in the model to find the tables in the HDF5 file. + """ + + database = slycat.web.server.database.couchdb.connect() + model = database.get("model", mid) + project = model['project'] + slycat.web.server.authentication.require_project_writer(project) + input_path = '/' + model['hdf5-inputs'] + output_path = '/' + model['hdf5-outputs'] + did = model['project_data'][0] + project_data = database.get("project_data", did) + file_name = project_data['hdf5_name'] + hdf5_path = cherrypy.request.app.config["slycat-web-server"]["data-store"] + "/" + file_name + h5 = h5py.File(hdf5_path, 'r') + + # Getting indices for input/output columns + unformatted_input = list(h5[input_path]) + input_column_headers_indices = [i for i in range(0, len(unformatted_input[0]))] + unformatted_output = list(h5[output_path]) + output_column_headers_indices = [i for i in range(len(unformatted_input[0]), (len(unformatted_input[0]) + len(unformatted_output[0])))] + + slycat.web.server.put_model_parameter(database, model, 'input-columns', input_column_headers_indices, True) + slycat.web.server.put_model_parameter(database, model, 'output-columns', output_column_headers_indices, True) + + combined_dataset = [] + output_headers = [] + input_headers = [] + attributes = [] + + column_headers_input = list(h5[input_path].dims[1][0]) + column_headers_output = list(h5[output_path].dims[1][0]) + + # Once we have column headers, this is how we can get/store them. + for i, column in enumerate(column_headers_input): + input_headers.append(str(column.decode('utf-8'))) + attributes.append({"name": str(column.decode('utf-8')), "type": str(type(unformatted_input[0][i])).split('numpy.')[1].split("'>")[0]}) + for j, column in enumerate(column_headers_output): + output_headers.append(str(column.decode('utf-8'))) + attributes.append({"name": str(column.decode('utf-8')), "type": str(type(unformatted_output[0][j])).split('numpy.')[1].split("'>")[0]}) + + combined_headers = numpy.concatenate((input_headers, output_headers), axis=0) + combined_headers = combined_headers.tolist() + combined_data = numpy.concatenate((unformatted_input, unformatted_output), axis=1) + combined_data = numpy.transpose(combined_data) + + combined_data = combined_data.tolist() + + for row in combined_data: + combined_dataset.append(numpy.asarray(row)) + + dimensions = [{"name": "row", "type": "int64", "begin": 0, "end": len(combined_dataset[0])}] + + array_index = 0 + slycat.web.server.put_model_arrayset(database, model, 'data-table', input) + slycat.web.server.put_model_array(database, model, 'data-table', 0, attributes, dimensions) + slycat.web.server.put_model_arrayset_data(database, model, 'data-table', "%s/.../..." % array_index, combined_data) + + cherrypy.response.status = "200 Project updated." + +def post_browse_hdf5(path, pid, mid): + """ + Given a path inside of an HDF5 file, builds out the current tree at that path. + Formats the tree structure to conform with remote/hdf5 browser requirements. + """ + def allkeys_single_level(obj, tree_structure): + path = obj.name # This is current top level path + # Need to include all these fields because we are repurposing the remote file browser, which expects all these + tree_structure['path'] = path + tree_structure['name'] = [] + tree_structure['sizes'] = [] + tree_structure['types'] = [] + tree_structure['mtimes'] = [] + tree_structure['mime-types'] = [] + all_items = obj.items() + for key, value in all_items: + # key will be all the sub groups and datasets in the current path + tree_structure['name'].append(key) + tree_structure['sizes'].append(0) + tree_structure['mtimes'].append('2024') + if isinstance(value, h5py.Group): + tree_structure['mime-types'].append('application/x-directory') + tree_structure['types'].append('d') + else: + tree_structure['mime-types'].append('file') + tree_structure['types'].append('f') + return tree_structure + # Need to find the HDF5 stored on Slycat server, so we can query it for the path. + path = path.replace('-', '/') + database = slycat.web.server.database.couchdb.connect() + model = database.get("model", mid) + did = model['project_data'][0] + project_data = database.get("project_data", did) + file_name = project_data['hdf5_name'] + hdf5_path = cherrypy.request.app.config["slycat-web-server"]["data-store"] + "/" + file_name + h5 = h5py.File(hdf5_path, 'r') + tree_structure = {} + current_level = allkeys_single_level(h5[path], tree_structure) + json_payload = json.dumps(current_level) + + return json_payload + @cherrypy.tools.json_out(on=True) def get_remotes(hostname): """ diff --git a/packages/slycat/web/server/upload.py b/packages/slycat/web/server/upload.py index a6e1feb9e..02345b3e2 100644 --- a/packages/slycat/web/server/upload.py +++ b/packages/slycat/web/server/upload.py @@ -245,6 +245,10 @@ def numeric_order(x): # adding this check for backwards compatibility # new way self._aids[0] is the file name being added to the model and hdf5 # self._aids[1] is the name of the file being pushed to the project_data data object + if len(self._aids) > 1: + if '.h5' in self._aids[1] or '.hdf5' in self._aids[1]: + slycat.web.server.plugin.manager.parsers[self._parser]["parse"](database, model, self._input, + files, self._aids, **self._kwargs) if isinstance(self._aids[0], list): slycat.web.server.plugin.manager.parsers[self._parser]["parse"](database, model, self._input, files, self._aids[0], **self._kwargs) diff --git a/web-server/components/HDF5Browser.tsx b/web-server/components/HDF5Browser.tsx new file mode 100644 index 000000000..3970c94f0 --- /dev/null +++ b/web-server/components/HDF5Browser.tsx @@ -0,0 +1,399 @@ +'use strict'; +import * as React from 'react'; +import client from 'js/slycat-web-client'; +import SlycatSelector, {Option} from 'components/SlycatSelector.tsx'; + +/** + * @member hostname name of the host we are connecting + * (assumes we have a connection already to the host) + * @member persistenceId uuid for local storage + * @member onSelectFileCallBack called every time a file is selected + * returns the files info (path, file.type, file:FileMetaData) + * @member onSelectParserCallBack called every time a parser is selected + * returns the parser type (dakota or csv) + * @member onReauthCallBack called every time we lose connection to the host + * @export + * @interface HDF5BrowserProps + */ +export interface HDF5BrowserProps { + hostname: string + persistenceId?: string + onSelectFileCallBack: Function + onSelectParserCallBack: Function + onReauthCallBack: Function + pid: string + mid: string +} + +/** + * @member path path shown in box + * @member pathInput path to current file when selected + * @member persistenceId uuid add to get local storage say if there were + * two of these classes being used + * @member rawFiles list of the current files meta data we are looking at + * @member pathError do we have a path error + * @member browseError do we have a browsing error + * @member browserUpdating are we in the middle of getting data + * @member selected id of selected file + * @export + * @interface HDF5BrowserState + */ +export interface HDF5BrowserState { + path:string + pathInput:string + persistenceId:string + rawFiles: FileMetaData[] + pathError: boolean + browseError: boolean + browserUpdating: boolean + selected:number, + pid:string, + mid:string +} + +/** + * @member type file type + * @member name filename + * @member size size of file + * @member mtime last accessed time + * @member mimeType type of file + * @interface FileMetaData + */ +interface FileMetaData { + type: string + name: string + size: string + mtime: string + mimeType: string +} + +/** + * used to create a file browsing window like using 'ls' and 'cd' in a linux terminal + * + * @export + * @class RemoteFileBrowser + * @extends {React.Component} + */ +export default class HDF5Browser extends React.Component { + public constructor(props:HDF5BrowserProps) { + super(props) + this.state = { + path:"//", + pathInput: "//", + rawFiles: [], + pathError: false, + browseError: false, + persistenceId: props.persistenceId === undefined ? '' : props.persistenceId, + browserUpdating: false, + selected:-1, + pid: props.pid, + mid: props.mid + } + } + + /** + * given a path return all the items in said path (like ls) + * + * @param pathInput path to return all ls properties from + * @private + * @memberof HDF5Browser + */ + private browse = (pathInput:string) => { + let first_char = Array.from(pathInput)[0]; + if(first_char != '/') { + pathInput = '/' + pathInput; + } + this.setState({pathInput:pathInput}); + pathInput = pathInput.replace(/(?!^)\//g, "-"); + client.post_browse_hdf5( + { + hostname : this.props.hostname, + path : pathInput, + pid: this.props.pid, + mid: this.props.mid, + success : (results:any) => + { + localStorage.setItem("slycat-remote-browser-path-" + this.state.persistenceId + this.props.hostname, pathInput); + this.setState({ + browseError:false, + pathError:false, + }); + let json_results = JSON.parse(results) + let files: FileMetaData[] = [] + if(pathInput != "/") + files.push({type: "", name: "..", size: "", mtime: "", mimeType:"application/x-directory"}); + for(let i = 0; i != json_results['name'].length; ++i) + files.push({name:json_results['name'][i], size:json_results['sizes'][i], type:json_results['types'][i], mtime:json_results['mtimes'][i], mimeType:json_results["mime-types"][i]}); + this.setState({ + rawFiles:files, + browserUpdating:false + }); + }, + error : (results:any) => + { + if(this.state.path != this.state.pathInput) + { + this.setState({pathError:true, browserUpdating:false}); + } + if(results.status == 400){ + alert("bad file path") + } + this.setState({browseError:true, browserUpdating:false}); + } + }); + } + + /** + * takes a path and returns the directory above it + * + * @param path string path + * @private + * @returns new string path one level up + * @memberof RemoteFileBrowser + */ + private pathDirname = (path:string):string => + { + var new_path = path.replace(/\/\.?(\w|\-|\.)*\/?$/, ""); + if(new_path == "") + new_path = "/"; + return new_path; + } + + /** + * takes left path and right path and joins them + * @param right string path + * @param left string path + * @private + * @requires joined paths + * @memberof RemoteFileBrowser + */ + private pathJoin = (left:string, right:string):string => + { + var new_path = left; + if(new_path.slice(-1) != "/") + new_path += "/"; + new_path += right; + return new_path; + } + + private browseUpDirectory = (currentPath:string) => { + let split_path = currentPath.split('/'); + let parent_directory = ''; + for (let i = 1; i < split_path.length - 1; i++) { + parent_directory = parent_directory + '/' + split_path[i]; + } + if (parent_directory == '/' || parent_directory == '') { + parent_directory = '//'; + } + this.browse(parent_directory); + } + + /** + * given a file(which includes its full path), browse to the path above it + * + * @param file meta data for the file selected to browse up + * one level from said path + * @private + * @memberof RemoteFileBrowser + */ + private browseUpByFile = (file:FileMetaData) => { + this.setState({selected:-1}); + // If it's a table, need to parse + if(file.type === "f") { + // callback + } + + // If the file is our parent directory, move up the hierarchy. + if(file.name === "..") + { + this.browse(this.pathDirname(this.state.path)); + } + // If the file is a directory, move down the hierarchy. + else if(file.type === "d") + { + let current_path = this.state.pathInput; + let new_path = ''; + if(current_path == '//') { + current_path = current_path.substring(1); + new_path = current_path + file.name; + } + else { + new_path = current_path + '/' + file.name; + } + let substr = new_path.substring(0, 2); + if(substr == '//') { + new_path = new_path.substring(1); + } + this.browse(new_path); + } + } + + keyPress = (event:any, pathInput:string) => { + if (event.key == 'Enter'){ + this.browse(pathInput); + } + } + + /** + * Given a row id and file info set the selected file and + * callBack to tell caller Path, file.type, file:FileMetaData + * + * @param file an object of FileMetaData + * @param i index of selected row in the table + * @private + * @memberof RemoteFileBrowser + */ + private selectRow = (file:FileMetaData, i:number) => { + let newPath:string = this.state.path; + const path_split:string[] = this.state.path.split("/"); + + /** + * If the user types out the full path, including file name, + * we don't want to join the file name with the path + * (resulting in duplicate file names). + */ + + if(path_split[path_split.length - 1] !== file.name) { + newPath = this.pathJoin(this.state.path, file.name); + } + + this.setState({selected:i},() => { + // tell our create what we selected + this.props.onSelectFileCallBack((this.state.pathInput + '/' + file.name), file.type, file); + }) + } + + /** + * takes a list of file info from the state and converts it + * to an html + * + * @private + * @memberof RemoteFileBrowser + * @returns JSX.Element[] with the styled file list + */ + private getFilesAsJsx = ():JSX.Element[] => { + const rawFilesJSX = this.state.rawFiles.map((rawFile, i) => { + return ( + this.selectRow(rawFile,i)} + onDoubleClick={()=> this.browseUpByFile(rawFile)}> + + {rawFile.mimeType === "application/x-directory"? + : + } + + {rawFile.name} + {rawFile.size} + {rawFile.mtime} + + ) + }) + return rawFilesJSX; + // if(file.mime_type() in component.icon_map) + // { + // icon = component.icon_map[file.mime_type()]; + // } + // else if(_.startsWith(file.mime_type(), "text/")) + // { + // icon = ""; + // } + // else if(_.startsWith(file.mime_type(), "image/")) + // { + // icon = ""; + // } + // else if(_.startsWith(file.mime_type(), "video/")) + // { + // icon = ""; + // } + } + + public async componentDidMount() { + // const path = localStorage.getItem("slycat-remote-browser-path-" + // + this.state.persistenceId + // + this.props.hostname); + if(this.state.pathInput != null){ + // this.setState({path,pathInput:path}); + this.browse(this.state.pathInput); + } + } + + public render() { + const options: Option[] = [{ + text:'Comma separated values (CSV)', + value:'slycat-csv-parser' + }, + { + text:'Dakota tabular', + value:'slycat-dakota-parser' + }]; + const pathStyle:any = { + width: 'calc(100% - 44px)', + float: 'left', + marginRight: '5px' + } + const styleTable:any = { + position: "relative", + height: (window.innerHeight*0.4)+"px", + overflow: "auto", + display: "block", + border: "1px solid rgb(222, 226, 230)", + } + return ( +
+
+
+
+ this.keyPress(event, this.state.pathInput)} + onChange={(e:React.ChangeEvent) => { + this.setState({pathInput:e.target.value}) + } + } + /> +
+ +
+
+
+ +
+
+ {/*
+ Oops, that path is not accessible. Please try again. +
*/} +
+ + {!this.state.browserUpdating? +
+ + + + + + + + + + + {this.getFilesAsJsx()} + +
NameSizeDate Modified
+
: + } +
+ ); + } +} \ No newline at end of file diff --git a/web-server/js/slycat-web-client.js b/web-server/js/slycat-web-client.js index c3bf99c4b..ba1d27c98 100644 --- a/web-server/js/slycat-web-client.js +++ b/web-server/js/slycat-web-client.js @@ -1391,8 +1391,52 @@ module.post_remote_command = function (params) { }); }; +module.post_combine_hdf5_tables = function (params) { + $.ajax({ + contentType: 'application/json', + data: JSON.stringify({}), + type: 'POST', + url: `${api_root}hdf5/combine/${params.mid}`, + success(result) { + if (params.success) params.success(result); + }, + error(request, status, reason_phrase) { + if (params.error) params.error(request, status, reason_phrase); + } + }); +} + +module.post_hdf5_table = function (params) { + $.ajax({ + contentType: 'application/json', + data: JSON.stringify({}), + type: 'POST', + url: `${api_root}hdf5/table${params.path}/${params.pid}/${params.mid}`, + success(result) { + if (params.success) params.success(result); + }, + error(request, status, reason_phrase) { + if (params.error) params.error(request, status, reason_phrase); + } + }); +} + +module.post_browse_hdf5 = function (params) { + $.ajax({ + contentType: 'application/json', + data: JSON.stringify({}), + type: 'POST', + url: `${api_root}hdf5/browse${params.path}/${params.pid}/${params.mid}`, + success(result) { + if (params.success) params.success(result); + }, + error(request, status, reason_phrase) { + if (params.error) params.error(request, status, reason_phrase); + } + }); +}; + module.post_remote_browse_smb = function (params) { - console.log('In browse smb'); $.ajax({ contentType: 'application/json', data: JSON.stringify({}), diff --git a/web-server/plugins/slycat-hdf5-parser.py b/web-server/plugins/slycat-hdf5-parser.py index 09413a126..2c850e602 100644 --- a/web-server/plugins/slycat-hdf5-parser.py +++ b/web-server/plugins/slycat-hdf5-parser.py @@ -78,15 +78,19 @@ def parse_file(file, model, database): def parse(database, model, input, files, aids, **kwargs): # Read HDF5 file + slycat.web.server.handlers.create_project_data(model['_id'], aids, files) start = time.time() - parsed = [parse_file(file, model, database) for file in files] - array_index = int(kwargs.get("array", "0")) - for (attributes, dimensions, combined_data, separate_data), aid in zip(parsed, aids): - slycat.web.server.put_model_arrayset(database, model, aid, input) - slycat.web.server.put_model_array(database, model, aid, 0, attributes, dimensions) - slycat.web.server.put_model_arrayset_data(database, model, aid, "%s/.../..." % array_index, combined_data) + + # parsed = [parse_file(file, model, database) for file in files] + # array_index = int(kwargs.get("array", "0")) + # for (attributes, dimensions, combined_data, separate_data), aid in zip(parsed, aids): + # slycat.web.server.put_model_arrayset(database, model, aid, input) + # slycat.web.server.put_model_array(database, model, aid, 0, attributes, dimensions) + # slycat.web.server.put_model_arrayset_data(database, model, aid, "%s/.../..." % array_index, combined_data) + end = time.time() model = database.get("model", model['_id']) + slycat.web.server.put_model_parameter(database, model, "error-messages", "") model["db_creation_time"] = (end - start) database.save(model) diff --git a/web-server/plugins/slycat-parameter-image/js/wizard-ui.js b/web-server/plugins/slycat-parameter-image/js/wizard-ui.js index 039c88b52..b48955e0c 100644 --- a/web-server/plugins/slycat-parameter-image/js/wizard-ui.js +++ b/web-server/plugins/slycat-parameter-image/js/wizard-ui.js @@ -20,6 +20,7 @@ import ReactDOM from "react-dom"; import { createRoot } from "react-dom/client"; import SmbRemoteFileBrowser from "components/SmbRemoteFileBrowser.tsx"; import SmbAuthentication from "components/SmbAuthentication.tsx"; +import HDF5Browser from "components/HDF5Browser.tsx"; function constructor(params) { var component = {}; @@ -205,8 +206,14 @@ function constructor(params) { component.error_messages(error_messages); } if (component.error_messages().length == 0) { - component.tab(4); - $(".browser-continue").toggleClass("disabled", false); + if (component.parser() == 'slycat-hdf5-parser') { + component.tab(6); + this.hdf5_input_browse(); + } + else{ + component.tab(4); + $(".browser-continue").toggleClass("disabled", false); + } } }); }; @@ -241,7 +248,6 @@ function constructor(params) { }; const onSelectTableFile = function (path, fileType, file) { - console.log(`newPath:: ${path}, fileType:: ${fileType}, file:: ${file}`); if (fileType === "f") { component.browser.path(path); } @@ -298,42 +304,51 @@ function constructor(params) { var upload_success = function (uploader) { uploader.progress(95); uploader.progress_status("Finishing..."); - client.get_model_command({ - mid: component.model._id(), - type: "parameter-image", - command: "media-columns", - success: function (media_columns) { - client.get_model_table_metadata({ - mid: component.model._id(), - aid: "data-table", - success: function (metadata) { - uploader.progress(100); - uploader.progress_status("Finished"); - var attributes = []; - for (var i = 0; i != metadata["column-names"].length; ++i) - attributes.push({ - name: metadata["column-names"][i], - type: metadata["column-types"][i], - input: false, - output: false, - category: false, - rating: false, - image: media_columns.indexOf(i) !== -1, - Classification: "Neither", - Categorical: false, - Editable: false, - hidden: media_columns.indexOf(i) !== -1, - selected: false, - lastSelected: false, - disabled: false, - tooltip: "", - }); - mapping.fromJS(attributes, component.attributes); - component.get_error_messages(); - }, - }); - }, - }); + // Don't need to get column headers if HDF5 file + if(component.parser() == 'slycat-hdf5-parser') { + $(".local-browser-continue").toggleClass("disabled", false); + uploader.progress(100); + uploader.progress_status("Finished"); + component.get_error_messages(); + } + else { + client.get_model_command({ + mid: component.model._id(), + type: "parameter-image", + command: "media-columns", + success: function (media_columns) { + client.get_model_table_metadata({ + mid: component.model._id(), + aid: "data-table", + success: function (metadata) { + uploader.progress(100); + uploader.progress_status("Finished"); + var attributes = []; + for (var i = 0; i != metadata["column-names"].length; ++i) + attributes.push({ + name: metadata["column-names"][i], + type: metadata["column-types"][i], + input: false, + output: false, + category: false, + rating: false, + image: media_columns.indexOf(i) !== -1, + Classification: "Neither", + Categorical: false, + Editable: false, + hidden: media_columns.indexOf(i) !== -1, + selected: false, + lastSelected: false, + disabled: false, + tooltip: "", + }); + mapping.fromJS(attributes, component.attributes); + component.get_error_messages(); + }, + }); + }, + }); + } }; component.existing_table = function () { @@ -357,7 +372,6 @@ function constructor(params) { // get file data $(".local-browser-continue").toggleClass("disabled", true); var file = component.browser.selection()[0]; - var fileObject = { pid: component.project._id(), mid: component.model._id(), @@ -382,6 +396,35 @@ function constructor(params) { fileUploader.uploadFile(fileObject, component.useProjectData()); }; + + component.hdf5_input_browse = function () { + const hdf5_wizard_browse_root = createRoot(document.querySelector(".hdf5-wizard-input-browse")); + hdf5_wizard_browse_root.render( +
+ +
) + } + + component.hdf5_output_browse = function () { + const hdf5_wizard_browse_root = createRoot(document.querySelector(".hdf5-wizard-output-browse")); + hdf5_wizard_browse_root.render( +
+ +
) + } + component.connectSMB = function () { component.remote.enable(false); component.remote.status_type("info"); @@ -476,8 +519,62 @@ function constructor(params) { } }; + component.load_hdf5_input = function () { + const file_name = component.browser.path().split("/")[ + component.browser.path().split("/").length - 1 + ]; + + let pathInput = component.browser.path(); + pathInput = pathInput.replace(/(?!^)\//g, "-"); + client.post_hdf5_table({ + path : pathInput, + pid: component.project._id(), + mid: component.model._id(), + aids: [["data-table"], file_name], + success : (results) => + { + console.log('Success!'); + component.tab(7); + component.hdf5_output_browse(); + }, + error : (results) => + { + console.log('Failure...'); + } + }); + } + + component.load_hdf5_output = function () { + const file_name = component.browser.path().split("/")[ + component.browser.path().split("/").length - 1 + ]; + + let pathInput = component.browser.path(); + pathInput = pathInput.replace(/(?!^)\//g, "-"); + client.post_hdf5_table({ + path : pathInput, + pid: component.project._id(), + mid: component.model._id(), + aids: [["data-table"], file_name], + success : (results) => + { + component.finish(); + client.post_combine_hdf5_tables({ + mid: component.model._id(), + success : (results) => + { + component.tab(5); + } + }) + }, + error : (results) => + { + console.log('Failure...'); + } + }); + } + component.load_table_smb = function () { - console.log("component.browser.path()", component.browser.path()); $(".remote-browser-continue").toggleClass("disabled", true); const file_name = component.browser.path().split("/")[ component.browser.path().split("/").length - 1 @@ -643,7 +740,6 @@ function constructor(params) { component.name_model = function (formElement) { // Validating formElement.classList.add("was-validated"); - // If valid... if (formElement.checkValidity() === true) { // Clearing form validation @@ -722,6 +818,22 @@ function constructor(params) { target--; target--; } + + if (component.tab() == 6) { + target--; + target--; + target--; + target--; + component.browser.progress(null); + component.browser.progress_status(""); + } + + if (component.parser() == 'slycat-hdf5-parser' && component.tab() == 5) { + target++; + target++; + target++; + } + target--; component.tab(target); }; diff --git a/web-server/plugins/slycat-parameter-image/wizard-ui.html b/web-server/plugins/slycat-parameter-image/wizard-ui.html index 47b42e2cc..fd9ec1283 100644 --- a/web-server/plugins/slycat-parameter-image/wizard-ui.html +++ b/web-server/plugins/slycat-parameter-image/wizard-ui.html @@ -9,10 +9,12 @@ +
+
HDF5 Inputs
+
+ +
+
+ +
+
HDF5 Outputs
+
+ +
+
+