Skip to content

Commit

Permalink
Schema cell cleanup (#58)
Browse files Browse the repository at this point in the history
* Fix aggregate heuristic

* More aggregates, style and click cleanup

* Lint, tests
  • Loading branch information
whscullin authored Aug 29, 2023
1 parent b24803a commit 5683e7a
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 134 deletions.
54 changes: 34 additions & 20 deletions src/malloy/ipython/schema_view/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
from .icons import get_icon_path


def is_aggregate(field):
"""
Identify aggregate fields by expressionType
"""
return field.get("expressionType") in [
"aggregate", "scalar_analytic", "aggregate_analytic"
"ungrouped_aggregate"
]


def field_sort(a):
"""
Sorts fields in an order similar to the VS Code extension:
Expand All @@ -33,9 +43,9 @@ def field_sort(a):
3. Measures
4. Joins
"""
is_aggregate = a.get("expressionType") == "aggregate"
return (0 if a["type"] == "turtle" else
3 if a["type"] == "struct" else 2 if is_aggregate else 1, a["name"])
3 if a["type"] == "struct" else 2 if is_aggregate(a) else 1,
a["name"])


def build_title(field, path):
Expand All @@ -61,10 +71,9 @@ def field_sorter(fields):
structs = []

for field in fields:
is_aggregate = field.get("expressionType") == "aggregate"
field_type = field.get("type")

if is_aggregate:
if is_aggregate(field):
measures.append(field)
elif field_type == "turtle":
queries.append(field)
Expand All @@ -78,58 +87,63 @@ def field_sorter(fields):

def render_field(field, path):
field_type = field.get("type")
is_aggregate = field.get("expressionType") == "aggregate"
field_name = field.get("as") or field.get("name")

return f"""<div class="field" title="{build_title(field, path)}">
{get_icon_path(field_type, is_aggregate)}
{get_icon_path(field_type, is_aggregate(field))}
<span class="field_name">{field_name}</span>
</div>"""


def render_fields(root, path=""):
def render_fields(explore, path=""):
"""
Render one level of the schema tree. Used recursively to handle
nested schemas.
"""
html = ""
fields = root["fields"]
join_relationship = root.get("structRelationship")
fields = explore["fields"]
join_relationship = explore.get("structRelationship")
join_type = None
if join_relationship:
join_type = join_relationship.get("type")
icon_type = join_type if join_type else "struct_base"
schema_name = root.get("as") or root.get("name")
explore_name = explore.get("as") or explore.get("name")
html += f"""
<li
class="schema hidden"
title="{build_title(root, path)}"
onclick="toggleClass(event, 'hidden');";
return false;"
title="{build_title(explore, path)}"
return false;
>
{get_icon_path(icon_type, False)} <b class="schema_name">{schema_name}</b>
<div onclick="toggleOpen(event)">\
<span class="open">▼</span><span class="closed">▶</span> \
{get_icon_path(icon_type, False)} \
<b class="explore_name">{explore_name}</b>
</div>
<ul>
"""
[queries, dimensions, measures, structs] = field_sorter(fields)

if len(queries) > 0:
html += """<li class="fields"><label>Queries</label> """
html += """<li class="fields">"""
html += """<label>Queries</label><div class="field_list">"""
html += " ".join(
render_field(field, path) for field in sorted(queries, key=field_sort))
html += "</li>"
html += "</div></li>"

if len(dimensions) > 0:
html += """<li class="fields"><label>Dimensions</label> """
html += """<li class="fields">"""
html += """<label>Dimensions</label><div class="field_list">"""
html += " ".join(
render_field(field, path)
for field in sorted(dimensions, key=field_sort))
html += "</li>"
html += "</div></li>"

if len(measures) > 0:
html += """<li class="fields"><label>Measures</label> """
html += """<li class="fields">"""
html += """<label>Measures</label><div class="field_list">"""
html += " ".join(
render_field(field, path) for field in sorted(measures, key=field_sort))
html += "</li>"
html += "<div></li>"

if len(structs) > 1:
html += """<li class="fields"><label>Relations</label> """
Expand Down
2 changes: 1 addition & 1 deletion src/malloy/ipython/schema_view/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def get_icon_path(field_type: str, is_aggregate: bool):
elif field_type in ["date", "timestamp"]:
image_file_name = time_icon
elif field_type in ["struct_base", "basetable"]:
image_file_name = struct_icon
image_file_name = ""
elif field_type == "one":
image_file_name = one_to_many_icon
elif field_type == "inline":
Expand Down
4 changes: 2 additions & 2 deletions src/malloy/ipython/schema_view/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

schema_scripts = """
<script>
function toggleClass(event, value) {
event.currentTarget.classList.toggle(value)
function toggleOpen(event) {
event.currentTarget.parentElement.classList.toggle('hidden');
event.preventDefault();
event.stopPropagation();
}
Expand Down
112 changes: 67 additions & 45 deletions src/malloy/ipython/schema_view/styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,81 @@

schema_styles = """
<style>
b {
font-size: 12px;
}
body {
color: var(--vscode-foreground, inherit);
}
ul {
margin: 5px 0;
padding: 0 1em;
list-style-type: none;
}
ul {
margin: 5px 0;
padding: 0 0.75em;
list-style-type: none;
}
li.schema {
list-style: "▼";
padding-left: 5px;
}
li.schema {
list-style: none;
}
li.schema.hidden {
list-style: "▶"
}
.hidden ul {
display: none;
}
.hidden ul {
display: none;
}
li.fields {
margin: 2px 0;
}
li.fields {
margin: 2px 0;
}
li.fields label {
display: block;
font-size: 10px;
margin-left: 5px;
text-transform: uppercase;
}
li.fields label {
text-transform: uppercase;
font-size: 10px;
display: block;
margin-left: 5px;
}
.explore_name {
line-height: 2em;
}
div.field {
white-space: nowrap;
display: inline-flex;
vertical-align: middle;
border: 1px solid rgba(128, 128, 128, 0.5);
border-radius: 12px;
padding: 2px 5px;
margin: 2px;
}
.field {
white-space: nowrap;
display: flex;
vertical-align: middle;
border: 1px solid var(--vscode-widget-border, rgba(128, 128, 128, 0.5));
border-radius: 20px;
padding: 0.5em 1em;
margin: 0.25em;
}
.field_name {
padding-left: 3px;
}
.field_list {
display: flex;
flex-wrap: wrap;
margin-top: 0.25em;
}
svg,
.field_name,
.schema_name {
vertical-align: middle;
display: inline-block;
}
.field_name {
padding-left: 3px;
}
.field_name,
svg,
span,
b {
vertical-align: middle;
display: inline-block;
}
span.closed {
display: none;
}
span.open {
display: inline-block;
}
.hidden span.closed {
display: inline-block;
}
.hidden span.open {
display: none;
}
</style>
"""
Loading

0 comments on commit 5683e7a

Please sign in to comment.