import os
import urllib.parse
import streamlit as st
################################################################
from datasize import DataSize
from streamlit.components.v1 import html
from solidipes.loaders.file_sequence import FileSequence
from solidipes.loaders.group import loader_list as group_loader_list
from solidipes.loaders.mime_types import extension2mime_type, is_valid_extension, mime_types2extensions
from solidipes.loaders.pyvista_mesh import PyvistaMesh
from solidipes.loaders.sequence import Sequence
from solidipes.reports.widgets.utils import FileWrapper
from solidipes.utils import get_mimes, logging, set_mimes
from .solidipes_widget import SolidipesWidget as SPW
################################################################
print = logging.invalidPrint
logger = logging.getLogger()
################################################################
[docs]
class DisplayFile(SPW):
def __init__(self, filename: str, loader_name: str, paths_str: str, options_layout=None, **kwargs):
super().__init__(**kwargs)
self.fname = filename
self.f = FileWrapper(self._load(filename, loader_name, paths_str))
self.f.state.valid = self.f.valid_loading
title = self.get_file_title(self.f)
st.markdown("<br>", unsafe_allow_html=True)
with self.layout:
with st.spinner("Loading... please wait"):
st.markdown(title)
self.show_file()
[docs]
def _load(self, filename: str, loader_name: str, paths_str: str):
from solidipes.loaders.file import load_file
group_loader_dict = {loader.__name__: loader for loader in group_loader_list}
if loader_name in group_loader_dict:
dir_path = os.path.dirname(filename)
encoded_paths = paths_str.split(",")
paths = [urllib.parse.unquote(p) for p in encoded_paths]
paths = [os.path.join(dir_path, p) for p in paths]
loader = group_loader_dict[loader_name]
return loader(pattern=filename, paths=paths)
else:
return load_file(filename)
[docs]
def _get_jupyter_link(self):
try:
session = os.environ["SESSION_URL"]
dir_path = os.getcwd()
rel_path = os.path.relpath(dir_path, self.git_infos.root)
if rel_path == ".":
_link = f"{session}/lab/"
else:
_link = f"{session}/lab/tree/{rel_path}"
return _link
except Exception:
raise RuntimeError("Not in a renku session")
[docs]
def show_file(self):
e = self.f
if not e.state.valid and e.errors:
for err in e.errors:
st.error(err)
st.sidebar.button(
"↵ Back to file list",
on_click=lambda: html("<script>window.parent.history.back();</script>"),
use_container_width=True,
type="primary",
)
col1, col2, col3, col4, col5 = st.columns(5)
self.show_discussions(e)
if e.state.adding_comment:
from streamlit_ace import st_ace
content = st_ace(
theme="textmate",
show_gutter=False,
key=f"chat_input_{e.unique_identifier}",
)
if content:
import re
m = re.match(r"(\w+):(.*)", content)
if m:
e.add_message(m[1], m[2].strip())
else:
e.add_message("Unknown", content)
e.state.adding_comment = False
st.rerun()
if isinstance(e.f, Sequence) and not (isinstance(e.f, FileSequence) and e.sequence_type == PyvistaMesh):
sequence_switcher = st.container()
with sequence_switcher:
st.write(f"Sequence of {e._element_count} elements.")
selected_element = st.slider(
"Current element",
min_value=1,
max_value=e._element_count,
step=1,
key="sequence_switcher_" + e.unique_identifier,
)
e.select_element(selected_element - 1, False)
file_size = e.file_info.size
col4.download_button(
f"Download {os.path.basename(e.file_info.path)} ({DataSize(file_size):.2a})",
data=open(e.file_info.path, "rb"),
file_name=os.path.basename(e.file_info.path),
key="download_" + e.unique_identifier,
)
try:
_link = self._get_jupyter_link()
_link += "/" + os.path.dirname(e.file_info.path)
col2.markdown(
f"[Edit in Jupyterlab]({_link}/)",
unsafe_allow_html=True,
)
_link = self._get_filebrowser_link()
_link += "/" + os.path.dirname(e.file_info.path)
col2.markdown(
f"[Edit in Filebrowser]({_link}/)",
unsafe_allow_html=True,
)
except RuntimeError:
pass
col3.button(
":speech_balloon: add a comment",
on_click=lambda: setattr(e.state, "adding_comment", True),
key=f"add_comment_button_{e.unique_identifier}",
)
self.mime_type_information(e, col1, st.container())
container_error = st.container()
with st.container():
try:
with st.spinner(f"Loading {e.file_info.path}..."):
e.view()
except Exception as err:
with container_error.expander(":warning: Error trying to display file"):
st.exception(err)
logger.error("Error trying to display file")
logger.error(err)
# raise err
[docs]
def show_discussions(self, e):
from solidipes.reports.widgets.custom_widgets import SpeechBubble
if not e.discussions:
return
if e.archived_discussions:
st.button("Unarchive messages", on_click=e.archive_discussions(False))
else:
st.markdown("### :speech_balloon: Discussions")
for author, message in e.discussions:
SpeechBubble(author, message)
st.markdown("<br>", unsafe_allow_html=True)
st.button(
"Respond",
on_click=lambda: setattr(e.state, "adding_comment", True),
key=f"respond_button_{e.unique_identifier}",
)
st.button("Mark as resolved", on_click=e.archive_discussions())
st.markdown("---")
[docs]
def get_file_title(self, e):
path = e.file_info.path
if isinstance(e.f, FileSequence):
path = e.f.path
file_title = f"{path}"
if isinstance(e.f, FileSequence):
file_size = e.total_size
else:
file_size = e.file_info.size
file_title += f" **{e.file_info.type.strip()}/{DataSize(file_size):.2a}** "
title = file_title
if e.state.valid and (not e.discussions or e.archived_discussions):
title = ":white_check_mark: " + file_title
else:
title = ":no_entry_sign: " + file_title
# if e.discussions or e.state.view:
# title += " :arrow_forward: "
if e.state.view:
title += " :open_book:"
if e.discussions:
title += " :e-mail: :arrow_forward: **You have a message**"
return title