mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
parent
33251d04e7
commit
4535568f2c
11 changed files with 39 additions and 18 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import hashlib
|
||||||
import janus
|
import janus
|
||||||
import queue
|
import queue
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -62,6 +63,12 @@ class Database:
|
||||||
}
|
}
|
||||||
return self._cached_table_counts
|
return self._cached_table_counts
|
||||||
|
|
||||||
|
@property
|
||||||
|
def color(self):
|
||||||
|
if self.hash:
|
||||||
|
return self.hash[:6]
|
||||||
|
return hashlib.md5(self.name.encode("utf8")).hexdigest()[:6]
|
||||||
|
|
||||||
def suggest_name(self):
|
def suggest_name(self):
|
||||||
if self.path:
|
if self.path:
|
||||||
return Path(self.path).stem
|
return Path(self.path).stem
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
{% block body_class %}db db-{{ database|to_css_class }}{% endblock %}
|
{% block body_class %}db db-{{ database|to_css_class }}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="page-header" style="border-color: #{{ database_color(database) }}">
|
<div class="page-header" style="border-color: #{{ database_color }}">
|
||||||
<h1>{{ metadata.title or database }}{% if private %} 🔒{% endif %}</h1>
|
<h1>{{ metadata.title or database }}{% if private %} 🔒{% endif %}</h1>
|
||||||
{% set links = database_actions() %}{% if links %}
|
{% set links = database_actions() %}{% if links %}
|
||||||
<details class="actions-menu-links details-menu">
|
<details class="actions-menu-links details-menu">
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
<p class="message-error">This query cannot be executed because the database is immutable.</p>
|
<p class="message-error">This query cannot be executed because the database is immutable.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_color(database) }}">{{ metadata.title or database }}{% if canned_query and not metadata.title %}: {{ canned_query }}{% endif %}{% if private %} 🔒{% endif %}</h1>
|
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_color }}">{{ metadata.title or database }}{% if canned_query and not metadata.title %}: {{ canned_query }}{% endif %}{% if private %} 🔒{% endif %}</h1>
|
||||||
|
|
||||||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_color(database) }}">{{ table }}: {{ ', '.join(primary_key_values) }}{% if private %} 🔒{% endif %}</h1>
|
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_color }}">{{ table }}: {{ ', '.join(primary_key_values) }}{% if private %} 🔒{% endif %}</h1>
|
||||||
|
|
||||||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="page-header" style="border-color: #{{ database_color(database) }}">
|
<div class="page-header" style="border-color: #{{ database_color }}">
|
||||||
<h1>{{ metadata.get("title") or table }}{% if is_view %} (view){% endif %}{% if private %} 🔒{% endif %}</h1>
|
<h1>{{ metadata.get("title") or table }}{% if is_view %} (view){% endif %}{% if private %} 🔒{% endif %}</h1>
|
||||||
{% set links = table_actions() %}{% if links %}
|
{% set links = table_actions() %}{% if links %}
|
||||||
<details class="actions-menu-links details-menu">
|
<details class="actions-menu-links details-menu">
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,6 @@ class BaseView:
|
||||||
response.body = b""
|
response.body = b""
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def database_color(self, database):
|
|
||||||
return "ff0000"
|
|
||||||
|
|
||||||
async def method_not_allowed(self, request):
|
async def method_not_allowed(self, request):
|
||||||
if (
|
if (
|
||||||
request.path.endswith(".json")
|
request.path.endswith(".json")
|
||||||
|
|
@ -150,7 +147,6 @@ class BaseView:
|
||||||
template_context = {
|
template_context = {
|
||||||
**context,
|
**context,
|
||||||
**{
|
**{
|
||||||
"database_color": self.database_color,
|
|
||||||
"select_templates": [
|
"select_templates": [
|
||||||
f"{'*' if template_name == template.name else ''}{template_name}"
|
f"{'*' if template_name == template.name else ''}{template_name}"
|
||||||
for template_name in templates
|
for template_name in templates
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ class DatabaseView(View):
|
||||||
template = datasette.jinja_env.select_template(templates)
|
template = datasette.jinja_env.select_template(templates)
|
||||||
context = {
|
context = {
|
||||||
**json_data,
|
**json_data,
|
||||||
|
"database_color": db.color,
|
||||||
"database_actions": database_actions,
|
"database_actions": database_actions,
|
||||||
"show_hidden": request.args.get("_show_hidden"),
|
"show_hidden": request.args.get("_show_hidden"),
|
||||||
"editable": True,
|
"editable": True,
|
||||||
|
|
@ -154,7 +155,6 @@ class DatabaseView(View):
|
||||||
and not db.is_mutable
|
and not db.is_mutable
|
||||||
and not db.is_memory,
|
and not db.is_memory,
|
||||||
"attached_databases": attached_databases,
|
"attached_databases": attached_databases,
|
||||||
"database_color": lambda _: "#ff0000",
|
|
||||||
"alternate_url_json": alternate_url_json,
|
"alternate_url_json": alternate_url_json,
|
||||||
"select_templates": [
|
"select_templates": [
|
||||||
f"{'*' if template_name == template.name else ''}{template_name}"
|
f"{'*' if template_name == template.name else ''}{template_name}"
|
||||||
|
|
@ -179,6 +179,7 @@ class DatabaseView(View):
|
||||||
@dataclass
|
@dataclass
|
||||||
class QueryContext:
|
class QueryContext:
|
||||||
database: str = field(metadata={"help": "The name of the database being queried"})
|
database: str = field(metadata={"help": "The name of the database being queried"})
|
||||||
|
database_color: str = field(metadata={"help": "The color of the database"})
|
||||||
query: dict = field(
|
query: dict = field(
|
||||||
metadata={"help": "The SQL query object containing the `sql` string"}
|
metadata={"help": "The SQL query object containing the `sql` string"}
|
||||||
)
|
)
|
||||||
|
|
@ -232,9 +233,6 @@ class QueryContext:
|
||||||
show_hide_hidden: str = field(
|
show_hide_hidden: str = field(
|
||||||
metadata={"help": "Hidden input field for the _show_sql parameter"}
|
metadata={"help": "Hidden input field for the _show_sql parameter"}
|
||||||
)
|
)
|
||||||
database_color: Callable = field(
|
|
||||||
metadata={"help": "Function that returns a color for a given database name"}
|
|
||||||
)
|
|
||||||
table_columns: dict = field(
|
table_columns: dict = field(
|
||||||
metadata={"help": "Dictionary of table name to list of column names"}
|
metadata={"help": "Dictionary of table name to list of column names"}
|
||||||
)
|
)
|
||||||
|
|
@ -689,6 +687,7 @@ class QueryView(View):
|
||||||
template,
|
template,
|
||||||
QueryContext(
|
QueryContext(
|
||||||
database=database,
|
database=database,
|
||||||
|
database_color=db.color,
|
||||||
query={
|
query={
|
||||||
"sql": sql,
|
"sql": sql,
|
||||||
"params": params,
|
"params": params,
|
||||||
|
|
@ -721,7 +720,6 @@ class QueryView(View):
|
||||||
),
|
),
|
||||||
show_hide_hidden=markupsafe.Markup(show_hide_hidden),
|
show_hide_hidden=markupsafe.Markup(show_hide_hidden),
|
||||||
metadata=canned_query or metadata,
|
metadata=canned_query or metadata,
|
||||||
database_color=lambda _: "#ff0000",
|
|
||||||
alternate_url_json=alternate_url_json,
|
alternate_url_json=alternate_url_json,
|
||||||
select_templates=[
|
select_templates=[
|
||||||
f"{'*' if template_name == template.name else ''}{template_name}"
|
f"{'*' if template_name == template.name else ''}{template_name}"
|
||||||
|
|
|
||||||
|
|
@ -105,9 +105,7 @@ class IndexView(BaseView):
|
||||||
{
|
{
|
||||||
"name": name,
|
"name": name,
|
||||||
"hash": db.hash,
|
"hash": db.hash,
|
||||||
"color": db.hash[:6]
|
"color": db.color,
|
||||||
if db.hash
|
|
||||||
else hashlib.md5(name.encode("utf8")).hexdigest()[:6],
|
|
||||||
"path": self.ds.urls.database(name),
|
"path": self.ds.urls.database(name),
|
||||||
"tables_and_views_truncated": tables_and_views_truncated,
|
"tables_and_views_truncated": tables_and_views_truncated,
|
||||||
"tables_and_views_more": (len(visible_tables) + len(views))
|
"tables_and_views_more": (len(visible_tables) + len(views))
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ class RowView(DataView):
|
||||||
|
|
||||||
async def data(self, request, default_labels=False):
|
async def data(self, request, default_labels=False):
|
||||||
resolved = await self.ds.resolve_row(request)
|
resolved = await self.ds.resolve_row(request)
|
||||||
database = resolved.db.name
|
db = resolved.db
|
||||||
|
database = db.name
|
||||||
table = resolved.table
|
table = resolved.table
|
||||||
pk_values = resolved.pk_values
|
pk_values = resolved.pk_values
|
||||||
|
|
||||||
|
|
@ -60,6 +61,7 @@ class RowView(DataView):
|
||||||
"foreign_key_tables": await self.foreign_key_tables(
|
"foreign_key_tables": await self.foreign_key_tables(
|
||||||
database, table, pk_values
|
database, table, pk_values
|
||||||
),
|
),
|
||||||
|
"database_color": db.color,
|
||||||
"display_columns": display_columns,
|
"display_columns": display_columns,
|
||||||
"display_rows": display_rows,
|
"display_rows": display_rows,
|
||||||
"custom_table_templates": [
|
"custom_table_templates": [
|
||||||
|
|
|
||||||
|
|
@ -1408,7 +1408,7 @@ async def table_view_data(
|
||||||
return table_name
|
return table_name
|
||||||
|
|
||||||
async def extra_database_color():
|
async def extra_database_color():
|
||||||
return lambda _: "ff0000"
|
return db.color
|
||||||
|
|
||||||
async def extra_form_hidden_args():
|
async def extra_form_hidden_args():
|
||||||
form_hidden_args = []
|
form_hidden_args = []
|
||||||
|
|
|
||||||
|
|
@ -1103,3 +1103,23 @@ async def test_breadcrumbs_respect_permissions(
|
||||||
assert actual == expected_links
|
assert actual == expected_links
|
||||||
finally:
|
finally:
|
||||||
ds_client.ds._metadata_local = orig
|
ds_client.ds._metadata_local = orig
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_database_color(ds_client):
|
||||||
|
expected_color = ds_client.ds.get_database("fixtures").color
|
||||||
|
# Should be something like #9403e5
|
||||||
|
expected_fragments = (
|
||||||
|
"10px solid #{}".format(expected_color),
|
||||||
|
"border-color: #{}".format(expected_color),
|
||||||
|
)
|
||||||
|
assert len(expected_color) == 6
|
||||||
|
for path in (
|
||||||
|
"/",
|
||||||
|
"/fixtures",
|
||||||
|
"/fixtures/facetable",
|
||||||
|
"/fixtures/paginated_view",
|
||||||
|
"/fixtures/pragma_cache_size",
|
||||||
|
):
|
||||||
|
response = await ds_client.get(path)
|
||||||
|
assert any(fragment in response.text for fragment in expected_fragments)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue