Skip to content

Commit 76be4fc

Browse files
committed
chore: add datastore pages
1 parent 0fd8ff1 commit 76be4fc

12 files changed

Lines changed: 240 additions & 43 deletions

File tree

ckanext/theming/lib.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,13 @@ def __init__(self, app: types.CKANApp):
228228

229229
@override
230230
def __getattr__(self, name: str):
231-
if config["debug"]:
232-
tpl = self.__env.get_template(self.source)
233-
mod = tpl.make_module()
234-
else:
235-
mod = self.__tpl.module
231+
# reset macro cache at the beginning of the request in debug mode. This
232+
# allows to edit UI macros without restarting the server.
233+
if config["debug"] and not getattr(tk.g, "_ui_compiled", False):
234+
self.__tpl._module = self.__tpl.make_module()
235+
tk.g._ui_compiled = True
236+
237+
mod = self.__tpl.module
236238
el: PElement = getattr(mod, name)
237239
return el
238240

ckanext/theming/themes/bare/assets/style.css

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ img {
125125
gap: 1rem;
126126
}
127127

128-
#breadcrumb {background: var(--breadcrumb-bg);}
129-
#breadcrumb > a:not(:first-child):before {content: " / ";}
130-
#breadcrumb > a:last-child {
128+
.breadcrumbs {background: var(--breadcrumb-bg);}
129+
.breadcrumbs > a:not(:first-child):before {content: " / ";}
130+
.breadcrumbs > a:last-child {
131131
text-decoration: none;
132132
pointer-events: none;
133133
font-weight: bold;
@@ -164,6 +164,7 @@ table.table-striped tbody tr:nth-child(2n+1) {
164164

165165
.dropdown {
166166
position: relative;
167+
display: inline-block;
167168
}
168169

169170
.dropdown .dropdown-menu {

ckanext/theming/themes/bare/templates/_page.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
{%- block zone_toolbar %}
1313
{%- block breadcrumb %}
14-
{%- call ui.util.call(ui.breadcrumb_wrapper, attrs={"id": "breadcrumb"}) -%}
14+
{%- call ui.util.call(ui.breadcrumb_wrapper) -%}
1515
{{ ui.breadcrumb_item("Home", h.url_for("home.index"), is_first=true) }}
1616
{%- block breadcrumb_content %}{% endblock %}
1717
{%- endcall %}
Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,48 @@
1-
{% extends "_layout.html" %}
1+
{%- extends "package/_resource_edit_base.html" -%}
2+
3+
{%- set options = [
4+
{'name': '', 'value': ''},
5+
{'name': 'text', 'value': 'text'},
6+
{'name': 'numeric', 'value': 'numeric'},
7+
{'name': 'timestamp', 'value': 'timestamp'},
8+
] -%}
9+
10+
11+
{%- block primary_content_inner -%}
12+
{%- call ui.util.call(ui.form, method="POST") -%}
13+
{% block errors %}{{ ui.form_errors(error_summary) }}{% endblock %}
14+
15+
{% block dictionary_form %}
16+
{%- call ui.util.call(ui.accordion_wrapper) -%}
17+
{% for field in fields %}
18+
{%- set position = loop.index -%}
19+
20+
{%- call ui.util.call(ui.accordion_item, title=_( "Field {num}.").format(num=position) ~ " " ~ field.id ~ " " ~ field.type ~ (", " ~ _("Primary key") if field.schema and field.schema.is_index else "")) -%}
21+
22+
23+
24+
{% block datapusher_xloader_fields scoped %}
25+
{{ ui.select(name='info__' ~ position ~ '__type_override', label=_('Type Override'), options=options, selected=field.get('info', {}).get('type_override', '')) }}
26+
{% endblock %}
27+
28+
{% block standard_fields scoped %}
29+
{{ ui.input(name='info__' ~ position ~ '__label', label=_('Label'), value=field.get('info', {}).get('label', ''), classes=['control-full']) }}
30+
31+
{{ ui.markdown(name='info__' ~ position ~ '__notes', label=_('Description'), value=field.get('info', {}).get('notes', '')) }}
32+
{% endblock %}
33+
34+
{% block additional_fields scoped %}
35+
{% endblock %}
36+
37+
{%- endcall %}
38+
{% endfor %}
39+
40+
{%- endcall %}
41+
{% endblock %}
42+
43+
{{ ui.form_actions(ui.button(_("Save"), type="submit")) }}
44+
45+
{%- endcall %}
46+
47+
48+
{%- endblock %}
Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,92 @@
1-
{% extends "_layout.html" %}
1+
{#
2+
Displays information about accessing a resource via the API.
3+
4+
resource_id - The resource id
5+
embedded - If true will not include the "modal" classes on the snippet.
6+
7+
Example
8+
9+
{% snippet 'datastore/snippets/api_info.html', resource_id=resource_id, embedded=true %}
10+
11+
#}
12+
13+
{% set code_examples = {} %}
14+
{% macro register_example(clang, example) %}
15+
{% set ex = code_examples.setdefault(clang, {}) %}
16+
{% set _ignore = ex.update({example: caller()}) %}
17+
{% endmacro %}
18+
19+
{% set code_languages = ['curl', 'javascript', 'powershell', 'python', 'r'] %}
20+
21+
{% block register_examples %}
22+
{# register examples by including templates here #}
23+
{% for clang in code_languages %}
24+
{% include "/datastore/api_examples/" + clang + ".html" %}
25+
{% endfor %}
26+
{% endblock %}
27+
28+
{%- call ui.util.call(ui.modal, title=_('CKAN Data API'), id="api-info-modal", dismissible=true) -%}
29+
30+
<p><strong>{{ _('Access resource data via a web API with powerful query support') }}</strong>.
31+
{% trans url="https://docs.ckan.org/en/latest/maintaining/datastore.html#api-reference" %}
32+
Further information in the
33+
<a href="{{ url }}" target="_blank">main CKAN Data API and DataStore documentation</a>.
34+
{% endtrans %}
35+
</p>
36+
37+
{%- call ui.util.call(ui.panel_wrapper) -%}
38+
<p>{{ _("Code examples:") }}</p>
39+
{% for clang in code_languages %}
40+
{{ ui.panel_handle(code_examples[clang]['button_label'], id="lang-" ~ clang) }}
41+
{% endfor %}
42+
43+
{%- call ui.util.call(ui.accordion_wrapper) -%}
44+
{%- call ui.util.call(ui.accordion_item, title=_('Querying')) -%}
45+
{% block query_examples %}
46+
<strong>{{ _('Get 5 results containing "jones" in any field:') }}</strong>
47+
{% for clang in code_languages %}
48+
{{ ui.panel(code_examples[clang]['request_limit'], id="lang-" ~ clang, open=loop.index == 1) }}
49+
{% endfor %}
50+
<strong>{{ _('Get results with either "watershed" or "survey" as subject and "active" as its stage:') }}</strong>
51+
{% for clang in code_languages %}
52+
{{ ui.panel(code_examples[clang]['request_filter'], id="lang-" ~ clang) }}
53+
{% endfor %}
54+
{% if h.datastore_search_sql_enabled() %}
55+
<strong>{{ _('SQL query example:') }}</strong>
56+
{% for clang in code_languages %}
57+
{{ ui.panel(code_examples[clang]['request_sql'], id="lang-" ~ clang) }}
58+
{% endfor %}
59+
{% endif %}
60+
{% endblock %}
61+
{%- endcall %}
62+
{%- endcall %}
63+
64+
{%- call ui.util.call(ui.accordion_wrapper) -%}
65+
{%- call ui.util.call(ui.accordion_item, title=_('Using the API with this Web Browser')) -%}
66+
{% block get_query_examples %}
67+
<p>{{ _('Some API endpoints may be accessed using a GET query string.') }}</p>
68+
<strong>{{ _('Query example (first 5 results)') }}</strong>
69+
<p>
70+
<code><a href="{{ h.url_for('api.action', logic_function='datastore_search', resource_id=resource_id, limit=5, qualified=True) }}" target="_blank" rel="noreferrer">{{ h.url_for('api.action', logic_function='datastore_search', resource_id=resource_id, limit=5, qualified=True) }}</a></code>
71+
</p>
72+
<strong>{{ _('Query example (results containing \'jones\')') }}</strong>
73+
<p>
74+
<code><a href="{{ h.url_for('api.action', logic_function='datastore_search', resource_id=resource_id, q='jones', qualified=True) }}" target="_blank" rel="noreferrer">{{ h.url_for('api.action', logic_function='datastore_search', resource_id=resource_id, q='jones', qualified=True) }}</a></code>
75+
</p>
76+
{% if h.datastore_search_sql_enabled() %}
77+
{# not urlencoding the sql because its clearer #}
78+
{% set sql_example_url = h.url_for(
79+
'api.action', logic_function='datastore_search_sql', qualified=True
80+
) + '?sql=SELECT * from "' + resource_id + '" WHERE title LIKE \'jones\'' %}
81+
<strong>{{ _('Query example (via SQL statement)') }}</strong>
82+
<p>
83+
<code><a href="{{sql_example_url}}" target="_blank" rel="noreferrer">{{ sql_example_url }}</a></code>
84+
</p>
85+
{% endif %}
86+
{% endblock %}
87+
{%- endcall %}
88+
{%- endcall %}
89+
90+
{%- endcall %}
91+
92+
{%- endcall %}
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,25 @@
1-
{% extends "_layout.html" %}
1+
{% extends "_page.html" %}
2+
3+
{%- block secondary_content -%}
4+
{%- endblock %}
5+
6+
{% block primary_content_inner %}
7+
{%- call ui.util.call(ui.section) -%}
8+
{{ ui.heading("Breadcrumbs", level=2) }}
9+
{%- for size in range(1, 4) -%}
10+
{%- call ui.util.call(ui.breadcrumb_wrapper) -%}
11+
{%- for _ in range(size) -%}
12+
{{ ui.breadcrumb_item(lipsum(1, false, 1, 3), "#") }}
13+
{%- endfor %}
14+
{%- endcall %}
15+
{%- endfor %}
16+
{%- endcall %}
17+
18+
{%- call ui.util.call(ui.section) -%}
19+
{{ ui.heading("Pagination", level=2) }}
20+
{{ ui.pagination(page=1, total=2) }}
21+
{{ ui.pagination(page=3, total=3) }}
22+
{{ ui.pagination(page=5, total=10) }}
23+
{%- endcall %}
24+
25+
{% endblock %}
Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,28 @@
1-
{% extends "_page.html" %}
1+
{% extends "_layout.html" %}
2+
{%- set _layout = _layout|default("fullwidth") -%}
23

34
{%- block subtitle %}{{ gettext('Error %(error_code)s', error_code=code) }}{% endblock %}
45

5-
{%- block primary_content %}
6-
<article class="module">
7-
<div class="module-content" id="error-content">
8-
{%- if name %}
9-
<h1>{{ code }} {{ name }}</h1>
10-
{%- endif %}
11-
{{ content }}
12-
</div>
6+
{%- block primary_content_inner %}
7+
{%- call ui.util.call(ui.section) -%}
8+
{{ ui.heading(code ~ " " ~ name, level=1) }}
9+
{{ ui.text(content) }}
10+
1311
{%- block login_redirect %}
1412
{%- if show_login_redirect_link %}
15-
<div class="module-content">
13+
{%- call ui.util.call(ui.text) -%}
1614
{{ _("You might need to login to access this page.") }}
1715
{{ ui.link(_("Click here to login"), href=h.url_for('user.login')) }}
18-
</div>
16+
{%- endcall %}
1917
{%- endif %}
2018
{%- endblock %}
21-
</article>
19+
20+
{%- endcall %}
2221
{%- endblock %}
2322

2423
{%- block breadcrumb %}{% endblock %}
2524

26-
{%- block flash %}
25+
{%- block notifications_container %}
2726
{# eat the flash messages caused by the 404 #}
28-
{%- set flash_messages = h.get_flashed_messages() %}
27+
{%- do h.get_flashed_messages() -%}
2928
{% endblock %}
30-
31-
{%- block secondary_content %}{% endblock %}

ckanext/theming/themes/bare/templates/macros/ui/container.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
{%- endmacro %}
7373

7474
{%- macro panel(content, title, id, open) -%}
75-
<div {{ ui.util.attrs(kwargs) }} data-panel="{{ id }}" {{ 'data-panel-default="true"' if open else "hidden" }}>
75+
<div {{ ui.util.attrs(kwargs) }} data-panel="{{ id }}"
76+
{% if open %} data-panel-default="true"{% else %} hidden{% endif %}>
7677
{{ content }}
7778
</div>
7879
{%- endmacro %}

ckanext/theming/themes/bare/templates/macros/ui/nav.html

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{%- macro breadcrumb_wrapper(content) -%}
2-
<div {{ ui.util.attrs(kwargs) }}>
2+
<div {{ ui.util.attrs(kwargs) }} class="breadcrumbs">
33
{{ content }}
44
</div>
55
{%- endmacro %}
@@ -56,36 +56,41 @@
5656
{%- endif %}
5757
{%- endmacro %}
5858

59-
{%- macro pagination(page=1, total_pages=1, url_generator=h.pager_url, padding=2) -%}
60-
{%- if total_pages > 1 %}
59+
{%- macro pagination(page=1, total=1, url_generator=h.pager_url, padding=2, hide_edges=false, hide_siblings=false, start_label=null, end_label=null, previous_label=_("Previous"), next_label=_("Next"), padding_label="...") -%}
60+
{%- if total > 1 %}
6161
<div {{ ui.util.attrs(kwargs) }}>
6262

63-
{%- if page > 1 %}
64-
{{ ui.link(_("Previous"), href=url_generator(page=page - 1)) }}
63+
{%- if page > 1 and not hide_siblings %}
64+
{{ ui.link(previous_label, href=url_generator(page=page - 1)) }}
6565
{%- endif %}
6666

6767

6868
{%- if page - 1 > padding %}
69-
{{ ui.link(1, href=url_generator(page=1)) }}
70-
<span>...</span>
69+
{%- if not hide_edges -%}
70+
{{ ui.link(start_label|default(1), href=url_generator(page=1)) }}
71+
{%- endif %}
72+
73+
<span>{{ padding_label }}</span>
7174
{%- endif %}
7275

73-
{%- for i in range([page - padding, 1]|max, [page + padding, total_pages + 1]|min) %}
76+
{%- for i in range([page - padding, 1]|max, [page + padding, total]|min + 1) %}
7477
{%- if i == page %}
7578
<span>{{ i }}</span>
7679
{%- else %}
7780
{{ ui.link(i, href=url_generator(page=i)) }}
7881
{%- endif %}
7982
{%- endfor %}
8083

81-
{%- if total_pages - page > padding %}
82-
<span>...</span>
83-
{{ ui.link(total_pages, href=url_generator(page=total_pages)) }}
84+
{%- if total - page > padding %}
85+
<span>{{ padding_label }}</span>
86+
{%- if not hide_edges -%}
87+
{{ ui.link(end_label|default(total), href=url_generator(page=total)) }}
88+
{%- endif %}
8489
{%- endif %}
8590

8691

87-
{%- if page < total_pages %}
88-
{{ ui.link(_("Next"), href=url_generator(page=page + 1)) }}
92+
{%- if page < total and not hide_siblings %}
93+
{{ ui.link(next_label, href=url_generator(page=page + 1)) }}
8994
{%- endif %}
9095

9196
</div>

ckanext/theming/themes/bare/templates/package/_resource_edit_base.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
{{ ui.content_nav_item(_('Edit resource'), href=h.url_for(pkg_dict.type ~ '_resource.edit', id=pkg_dict.name, resource_id=resource.id), active=request.endpoint == pkg_dict.type ~ '_resource.edit') }}
2929
{{ ui.content_nav_item(_('Views'), href=h.url_for(pkg_dict.type ~ '_resource.views', id=pkg_dict.name, resource_id=resource.id), active=request.endpoint == pkg_dict.type ~ '_resource.views') }}
3030
{{ ui.content_nav_item(_('DataStore'), href=h.url_for('datapusher.resource_data', id=pkg_dict.name, resource_id=resource.id), active=request.endpoint == 'datapusher.resource_data') if h.plugin_loaded("datapusher") }}
31+
{{ ui.content_nav_item(_('DataStore'), href=h.url_for('xloader.resource_data', id=pkg_dict.name, resource_id=resource.id), active=request.endpoint == 'xloader.resource_data') if h.plugin_loaded("xloader") and h.is_resource_supported_by_xloader(resource) }}
32+
{% if resource.datastore_active %}
33+
{{ ui.content_nav_item(_('Data Dictionary'), href=h.url_for('datastore.dictionary', id=pkg_dict.name, resource_id=resource.id), active=request.endpoint == 'datastore.dictionary') }}
34+
{% endif %}
35+
3136
{%- endif %}
3237

3338
{% endblock %}

0 commit comments

Comments
 (0)