Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data Cleaning Prototype (ignore, unless curious) #35418

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Adds an `is-loading` class to the element with ID specified in the `hq-hx-loading` attribute.
This `is-loading` class is applied when to that ID before an HTMX request begins, and is
removed after an HTMX swap is completed.

This is useful for adding loading indicators to elements outside the parent heirarchy available
through using `hx-indicator` alone. Right now, this is used to add an `is-loading` style to a django tables
table, which overlays a loading indicator across the entire table (seen in hqwebapp/tables/bootstrap5_htmx.html)
*/
document.body.addEventListener('htmx:beforeRequest', (evt) => {
if (evt.detail.elt.hasAttribute('hq-hx-loading')) {
let loadingElt = document.getElementById(evt.detail.elt.getAttribute('hq-hx-loading'));
if (loadingElt) {
loadingElt.classList.add('is-loading');
}
}
});
document.body.addEventListener('htmx:afterSwap', (evt) => {
if (evt.detail.elt.hasAttribute('hq-hx-loading')) {
let loadingElt = document.getElementById(evt.detail.elt.getAttribute('hq-hx-loading'));
if (loadingElt && loadingElt.classList.contains('is-loading')) {
loadingElt.classList.remove('is-loading');
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Sends an `hqRefresh` event to the selector (element) specified in the `hq-hx-refresh` attribute.
*/
import htmx from 'htmx.org';

document.body.addEventListener('htmx:afterSwap', (evt) => {
if (evt.detail.elt.hasAttribute('hq-hx-refresh')) {
htmx.trigger(evt.detail.elt.getAttribute('hq-hx-refresh'), 'hqRefresh');
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
@import "commcarehq/ace_cle";
@import "commcarehq/appcues";
@import "commcarehq/backgrounds";
@import "commcarehq/data_cleaning";
@import "commcarehq/datagrid";
@import "commcarehq/datatables";
@import "commcarehq/date_range_picker";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
.dc-spaces {
opacity: .5;
background-color: transparent;
font-weight: bold;
font-size: $font-size-base * 1.5;
line-height: $font-size-base * 1.5;
position: relative;
vertical-align: middle;
transition: .5s ease-in-out background-color;

&::before {
position: absolute;
top: 0;
left: 0;
font-size: $font-size-lg;
display: none;
}

&:hover {
cursor: help;
color: $white;
background-color: rgba(0, 0, 0, .5);
opacity: 1.0;
}
}

.dc-value {
border: 1px solid rgba(0, 0, 0, .1);
display: inline-block;
font-family: $font-family-monospace;
letter-spacing: 1px;
line-height: 12px;
padding: $spacer *.25 $spacer *.5;
vertical-align: middle;
}

.dc-diff-view {
font-family: $font-family-monospace;
letter-spacing: 1px;
}

.dc-diff-before,
.dc-diff-after {
border: 1px solid white;
display: inline-block;
margin: $spacer *.13;
padding-right: $spacer *.5;
vertical-align: middle;

&::before {
display: inline-block;
color: $white;
line-height: 12px;
padding: $spacer *.25 $spacer *.5;
}
}

.dc-diff-before {
background-color: $red-100;
border-color: $red-500;

&::before {
background-color: $red-500;
content: "-";
}

.dc-spaces {
color: $red-800;

&:hover {
color: $white;
}
}
}

.dc-diff-after {
background-color: $green-100;
border-color: $green-500;

&::before {
background-color: $green-500;
content: "+";
}

.dc-spaces {
color: $green-800;
}
}

.dc-null-value {
display: block;
position: relative;

.dc-info {
background-color: $gray-800;
color: $white;
font-weight: bold;
position: absolute;
left: 0;
top: 0;
opacity: 0;
padding: 0 $spacer * .25;
transition: opacity .5s ease-in-out;
}
&:hover .dc-info {
display: block;
opacity: 1;
}
}

.dc-diff-before .dc-null-value,
.dc-diff-after .dc-null-value {
display: inline-block;

.dc-info {
top: -2px;
left: -9px;
font-size: $font-size-sm;
padding: 3px 6.5px;
}
}

.dc-diff-before .dc-null-value {
color: $red-500;

.dc-info {
background-color: $red-500;
}
}

.dc-diff-after .dc-null-value {
color: $green-500;

.dc-info {
background-color: $green-500;
}
}

.table tbody tr td .inline-edit-block {
display: block;
background-color: transparent;
cursor: text;
transition: background-color .5s ease-in-out;
position: relative;
padding: $spacer * 0.5;
margin: $spacer * -0.5;

.inline-edit-action {
position: absolute;
right: 0;
top: calc(50% - 12px);
opacity: 0;
transition: opacity .5s ease-in-out;
}

.inline-edit-action-text {
background-color: $white;
padding: $spacer * .25;
white-space: nowrap;
$_offset: $spacer * .6;
top: calc(50% - $_offset);
right: $spacer * 0.25;
font-size: 10px;
line-height: $spacer * .75;
text-transform: uppercase;
font-weight: bold;
}

&:hover {
background-color: rgba(0, 0, 0, .06);
}

&:hover .inline-edit-action {
display: block;
opacity: 1;

&.inline-edit-action-text {
opacity: 1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,95 @@
.table-editprops-filterval {
min-width: 115px;
}

.table thead tr th.orderable {
position: relative;
padding: 0;

a {
display: block;
background-color: $blue-800;
color: $white;
padding: 0.5rem 0.5rem;
}
&:nth-child(odd) a {
background-color: $blue-700;
}

&::before,
&::after {
position: absolute;
display: block;
right: 10px;
line-height: 9px;
font-size: .8em;
color: $white;
opacity: 0.3;
}

&::before {
bottom: 50%;
content: "▲" / "";
}

&::after {
top: 50%;
content: "▼" / "";
}

&.asc::before {
opacity: 1.0;
}
&.desc::after {
opacity: 1.0;
}
}

.table thead tr th.select-header {
width: 28px;
background-color: $blue-800;

&:nth-child(odd) {
background-color: $blue-700;
}
}

.table-container {
position: relative;

.table-loading-indicator {
z-index: 1000;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(255, 255, 255, 0.25);
display: none;

&.is-loading {
display: block;
}

.spinner-border {
position: absolute;
border-width: $table-loading-spinner-border-width;
color: rgba(0, 0, 0, 0.25);
width: $table-loading-spinner-size;
height: $table-loading-spinner-size;
$_offset: $table-loading-spinner-size / 2;
left: calc(50% - $_offset);
top: calc(50% - $_offset);
}

.table-loading-progress {
z-index: 1000;
position: absolute;
top: 0;
left: 0;
width: 100%;
background-color: $white;
font-weight: bold;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,7 @@ $form-validation-states: (
// Make pagination-lg the same height as other lg inputs
$pagination-padding-x-lg: 1.0rem;
$pagination-padding-y-lg: 0.5rem;

// Table loading indicator
$table-loading-spinner-size: 150px;
$table-loading-spinner-border-width: 20px;
Empty file.
52 changes: 52 additions & 0 deletions corehq/apps/hqwebapp/tables/pagination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from django.core.paginator import Paginator
from django.views.generic.list import ListView

from django_tables2 import SingleTableMixin


class SelectablePaginator(Paginator):
paging_options = [10, 25, 50, 100]
default_option = 25


class SelectablePaginatedTableMixin(SingleTableMixin):
"""
Use this mixin with django-tables2's SingleTableView

Specify a `urlname` attribute to assist with naming the pagination cookie,
otherwise the cookie slug will default to using the class name.
"""
# `paginator_class` should always be a subclass of `SelectablePaginator`
paginator_class = SelectablePaginator

@property
def paginate_by_cookie_slug(self):
slug = self.urlname if hasattr(self, "urlname") else self.__class__.__name__
return f'{slug}-paginate_by'

@property
def default_paginate_by(self):
return self.request.COOKIES.get(
self.paginate_by_cookie_slug,
self.paginator_class.default_option
)

@property
def current_paginate_by(self):
return self.request.GET.get('per_page', self.default_paginate_by)

def get_paginate_by(self, table_data):
return self.current_paginate_by


class SelectablePaginatedTableView(SelectablePaginatedTableMixin, ListView):
"""
Based on SingleTableView, which inherits from `SingleTableMixin`, `ListView`
we instead extend the `SingleTableMixin` with `SavedPaginatedTableMixin`.
"""
template_name = "hqwebapp/tables/single_table.html"

def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
response.set_cookie(self.paginate_by_cookie_slug, self.current_paginate_by)
return response
Loading
Loading