diff --git a/addon/components/hyper-table/filters-renderers/numeric.js b/addon/components/hyper-table/filters-renderers/numeric.js
index 47afe82b..dda111cf 100644
--- a/addon/components/hyper-table/filters-renderers/numeric.js
+++ b/addon/components/hyper-table/filters-renderers/numeric.js
@@ -3,6 +3,7 @@ import { computed, observer } from '@ember/object';
import { debounce } from '@ember/runloop';
import FiltersRendererMixin from '@upfluence/hypertable/mixins/filters-renderer';
+import { onlyNumeric } from '@upfluence/hypertable/utils';
export default Component.extend(FiltersRendererMixin, {
lowerBoundFilter: null,
@@ -14,10 +15,10 @@ export default Component.extend(FiltersRendererMixin, {
},
orderingOptions: computed('column.orderKey', function () {
- return {
- '0 — 9': `${this.column.orderKey}:asc`,
- '9 — 0': `${this.column.orderKey}:desc`
- };
+ return [
+ { label: '0 — 9', value: `${this.column.orderKey}:asc` },
+ { label: '9 — 0', value: `${this.column.orderKey}:desc` }
+ ];
}),
currentExistenceFilter: computed('column.filters.[]', 'lowerBoundFilter', 'upperBoundFilter', function () {
@@ -44,6 +45,16 @@ export default Component.extend(FiltersRendererMixin, {
this.manager.hooks.onColumnsChange('columns:change');
},
+ setupOnlyNumericListener(element) {
+ const input = element.querySelector('input');
+ input?.addEventListener('keydown', onlyNumeric);
+ },
+
+ teardownOnlyNumericListener(element) {
+ const input = element.querySelector('input');
+ input?.removeEventListener('keydown', onlyNumeric);
+ },
+
didReceiveAttrs() {
this._super();
if (this.column) {
diff --git a/addon/components/hyper-table/filters-renderers/text.hbs b/addon/components/hyper-table/filters-renderers/text.hbs
index aac6abfe..c6421a68 100644
--- a/addon/components/hyper-table/filters-renderers/text.hbs
+++ b/addon/components/hyper-table/filters-renderers/text.hbs
@@ -1,51 +1,36 @@
-{{#if column.orderable}}
- {{#input-wrapper}}
+{{#if this.column.orderable}}
+
{{/if}}
-{{#if column.filterable}}
- {{#input-wrapper classNames=(if column.orderable "margin-top-xx-sm")}}
+{{#if this.column.filterable}}
+
-
- {{#each-in existenceFilters as |label value|}}
- {{radio-button
- value=value
- currentValue=currentExistenceFilter
- label=label
- options=existenceFilters
- onCheck="existenceFilterChanged"
- }}
+
+ {{#each-in this.existenceFilters as |label value|}}
+
+
+ {{label}}
+
{{/each-in}}
- {{/input-wrapper}}
+
- {{#input-wrapper}}
+
-
-
-
- {{/input-wrapper}}
+
+
diff --git a/addon/components/hyper-table/filters-renderers/text.js b/addon/components/hyper-table/filters-renderers/text.js
index a8f42dc7..3344bce9 100644
--- a/addon/components/hyper-table/filters-renderers/text.js
+++ b/addon/components/hyper-table/filters-renderers/text.js
@@ -9,10 +9,10 @@ export default Component.extend(FiltersRendererMixin, {
_searchQuery: null,
orderingOptions: computed('column.orderKey', function () {
- return {
- 'A — Z': `${this.column.orderKey}:asc`,
- 'Z — A': `${this.column.orderKey}:desc`
- };
+ return [
+ { label: 'A — Z', value: `${this.column.orderKey}:asc` },
+ { label: 'Z — A', value: `${this.column.orderKey}:desc` }
+ ];
}),
existenceFilters: {
diff --git a/addon/core/handler.ts b/addon/core/handler.ts
index 0ea06b7b..eb4d1d66 100644
--- a/addon/core/handler.ts
+++ b/addon/core/handler.ts
@@ -67,6 +67,7 @@ export default class TableHandler {
.fetchColumns()
.then(({ columns }) => {
this.columns = columns;
+ this._lastOrderedColumn = columns.find((column) => column.order);
})
.catch(() => {
this.communicationError = true;
diff --git a/addon/utils/index.ts b/addon/utils/index.ts
new file mode 100644
index 00000000..528e182c
--- /dev/null
+++ b/addon/utils/index.ts
@@ -0,0 +1,26 @@
+const NUMERIC_ONLY = /^\d$/i;
+const AUTHORIZED_INPUTS = [
+ 'Backspace',
+ 'Delete',
+ 'ArrowLeft',
+ 'ArrowRight',
+ 'Tab',
+ 'Shift',
+ 'Control',
+ 'ArrowUp',
+ 'ArrowDown'
+];
+
+export function onlyNumeric(event: KeyboardEvent): void {
+ _ensureValueFormat(event, NUMERIC_ONLY);
+}
+
+function _ensureValueFormat(event: KeyboardEvent, regexp: RegExp): void {
+ if (['c', 'v', 'a'].includes(event.key) && (event.metaKey || event.ctrlKey)) {
+ return;
+ }
+
+ if (![regexp.test(event.key)].every((c) => c) && !AUTHORIZED_INPUTS.find((key: string) => key === event.key)) {
+ event.preventDefault();
+ }
+}
diff --git a/app/styles/columns.less b/app/styles/columns.less
index a6746122..9914cde0 100644
--- a/app/styles/columns.less
+++ b/app/styles/columns.less
@@ -290,6 +290,8 @@
opacity: 0;
.filters {
+ display: flex;
+ flex-direction: column;
padding-top: var(--spacing-px-12);
.filters__option {
diff --git a/app/utils/index.js b/app/utils/index.js
new file mode 100644
index 00000000..2760f7d9
--- /dev/null
+++ b/app/utils/index.js
@@ -0,0 +1 @@
+export { onlyNumeric } from '@upfluence/hypertable/utils';
diff --git a/package.json b/package.json
index b61d9a8b..3dae4807 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
"ember-cli-typescript": "^4.2.1",
"ember-flatpickr": "^3.1.1",
"ember-named-blocks-polyfill": "^0.2.5",
- "ember-sortable": "4.0.0",
+ "ember-sortable": "^4.0.3",
"ember-truth-helpers": "^3.1.1",
"moment": "^2.29.4",
"tether": "^1.4.7"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bfa6b9f9..f189e2cb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -33,8 +33,8 @@ dependencies:
specifier: ^0.2.5
version: 0.2.5
ember-sortable:
- specifier: 4.0.0
- version: 4.0.0(@babel/core@7.23.9)(@glint/template@1.2.1)(ember-source@3.28.12)
+ specifier: ^4.0.3
+ version: 4.0.3(@babel/core@7.23.9)(@glint/template@1.2.1)
ember-truth-helpers:
specifier: ^3.1.1
version: 3.1.1
@@ -6728,17 +6728,6 @@ packages:
- supports-color
dev: false
- /ember-get-config@2.1.1(@glint/template@1.2.1):
- resolution: {integrity: sha512-uNmv1cPG/4qsac8oIf5txJ2FZ8p88LEpG4P3dNcjsJS98Y8hd0GPMFwVqpnzI78Lz7VYRGQWY4jnE4qm5R3j4g==}
- engines: {node: 12.* || 14.* || >= 16}
- dependencies:
- '@embroider/macros': 1.13.4(@glint/template@1.2.1)
- ember-cli-babel: 7.26.11
- transitivePeerDependencies:
- - '@glint/template'
- - supports-color
- dev: false
-
/ember-intl@6.4.0(@babel/core@7.23.9)(@glint/template@1.2.1)(typescript@4.9.5)(webpack@5.88.2):
resolution: {integrity: sha512-BXxscjgoqzXQ6tUSV8aJsQcUAIcfqLJnNjegarFWdBBHLEOffQ8xARhvQC0hW40zGi/RHFEyTTx7vbiCPGtP1A==}
engines: {node: 16.* || >= 18}
@@ -6921,22 +6910,17 @@ packages:
- supports-color
dev: true
- /ember-sortable@4.0.0(@babel/core@7.23.9)(@glint/template@1.2.1)(ember-source@3.28.12):
- resolution: {integrity: sha512-fRR7946IXwIt7SPMqRN2dJ3Gxaw6ioF/fzv/yzOPRBAaLMRRy3U8BGqCM0bNnE8IRuhRd63ox98Y0aFIkK43Hw==}
+ /ember-sortable@4.0.3(@babel/core@7.23.9)(@glint/template@1.2.1):
+ resolution: {integrity: sha512-iZ898uEXhIe/ywmhU8ASJPOHU9HV77cCRcnls0QtFIdwHV6hOc5+yoNaySMsud563gPdo1kXbVClot30y9RCUQ==}
engines: {node: 14.* || >= 16}
dependencies:
- '@ember/render-modifiers': 2.1.0(@babel/core@7.23.9)(@glint/template@1.2.1)(ember-source@3.28.12)
'@ember/test-waiters': 3.0.2
+ '@embroider/macros': 1.13.4(@glint/template@1.2.1)
ember-cli-babel: 7.26.11
- ember-cli-htmlbars: 6.3.0
- ember-cli-version-checker: 5.1.2
- ember-get-config: 2.1.1(@glint/template@1.2.1)
ember-modifier: 3.2.7(@babel/core@7.23.9)
- ember-test-selectors: 6.0.0
transitivePeerDependencies:
- '@babel/core'
- '@glint/template'
- - ember-source
- supports-color
dev: false
@@ -7036,17 +7020,6 @@ packages:
- supports-color
dev: true
- /ember-test-selectors@6.0.0:
- resolution: {integrity: sha512-PgYcI9PeNvtKaF0QncxfbS68olMYM1idwuI8v/WxsjOGqUx5bmsu6V17vy/d9hX4mwmjgsBhEghrVasGSuaIgw==}
- engines: {node: 12.* || 14.* || >= 16.*}
- dependencies:
- calculate-cache-key-for-tree: 2.0.0
- ember-cli-babel: 7.26.11
- ember-cli-version-checker: 5.1.2
- transitivePeerDependencies:
- - supports-color
- dev: false
-
/ember-truth-helpers@3.1.1:
resolution: {integrity: sha512-FHwJAx77aA5q27EhdaaiBFuy9No+8yaWNT5A7zs0sIFCmf14GbcLn69vJEp6mW7vkITezizGAWhw7gL0Wbk7DA==}
engines: {node: 10.* || >= 12}
diff --git a/tests/dummy/app/controllers/application.ts b/tests/dummy/app/controllers/application.ts
index 54e50345..7ab9d631 100644
--- a/tests/dummy/app/controllers/application.ts
+++ b/tests/dummy/app/controllers/application.ts
@@ -23,6 +23,18 @@ const columnDefinitions = [
];
const columns = [
+ { key: 'foo', extra: { filterable: true, category: 'influencer', clustering_key: 'instagram' } },
+ { key: 'time', extra: { orderable: true, filterable: true, category: 'influencer', type: 'timestamp' } },
+ { key: 'total', extra: { orderable: true, filterable: true, category: 'influencer', type: 'integer' } },
+ { key: 'bar', extra: { category: 'influencer', clustering_key: 'youtube' } },
+ { key: 'code', extra: { category: 'affiliation', clustering_key: '' } },
+
+ { key: 'foo', extra: { filterable: true, category: 'influencer', clustering_key: 'instagram' } },
+ { key: 'time', extra: { orderable: true, filterable: true, category: 'influencer', type: 'timestamp' } },
+ { key: 'total', extra: { orderable: true, filterable: true, category: 'influencer', type: 'integer' } },
+ { key: 'bar', extra: { category: 'influencer', clustering_key: 'youtube' } },
+ { key: 'code', extra: { category: 'affiliation', clustering_key: '' } },
+
{ key: 'foo', extra: { filterable: true, category: 'influencer', clustering_key: 'instagram' } },
{ key: 'time', extra: { orderable: true, filterable: true, category: 'influencer', type: 'timestamp' } },
{ key: 'total', extra: { orderable: true, filterable: true, category: 'influencer', type: 'integer' } },
diff --git a/tests/integration/components/hyper-table-v2/filtering-renderers/common/ordering-test.ts b/tests/integration/components/hyper-table-v2/filtering-renderers/common/ordering-test.ts
index bbdd5291..b14c97bc 100644
--- a/tests/integration/components/hyper-table-v2/filtering-renderers/common/ordering-test.ts
+++ b/tests/integration/components/hyper-table-v2/filtering-renderers/common/ordering-test.ts
@@ -28,11 +28,11 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/common/orde
this.column = this.handler.columns[0];
});
- test('it has the right data-control-name', async function (assert: Assert) {
+ test('it is properly rendered', async function (assert: Assert) {
await render(
hbs``
);
- assert.dom('.btn-group').exists();
+ assert.dom('.oss-toggle-buttons-container').exists();
});
test('it uses the default orderingOptions when no @orderingOptions are passed', async function (assert: Assert) {
@@ -40,10 +40,10 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/common/orde
hbs``
);
- assert.dom('.btn-group').exists();
- assert.dom('.btn-group .btn').exists({ count: 2 });
- assert.dom('.btn-group .btn:nth-child(1)').hasText('A — Z');
- assert.dom('.btn-group .btn:nth-child(2)').hasText('Z — A');
+ assert.dom('.oss-toggle-buttons-container').exists();
+ assert.dom('.oss-toggle-buttons-container .oss-toggle-buttons-btn').exists({ count: 2 });
+ assert.dom('.oss-toggle-buttons-container .oss-toggle-buttons-btn:nth-child(1)').hasText('A — Z');
+ assert.dom('.oss-toggle-buttons-container .oss-toggle-buttons-btn:nth-child(2)').hasText('Z — A');
});
test('it properly displays @orderingOptions when they are passed', async function (assert: Assert) {
@@ -56,10 +56,10 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/common/orde
@orderingOptions={{this.orderingOptions}} />`
);
- assert.dom('.btn-group').exists();
- assert.dom('.btn-group .btn').exists({ count: 2 });
- assert.dom('.btn-group .btn:nth-child(1)').hasText('Oldest — Newest');
- assert.dom('.btn-group .btn:nth-child(2)').hasText('Newest — Oldest');
+ assert.dom('.oss-toggle-buttons-container').exists();
+ assert.dom('.oss-toggle-buttons-container .oss-toggle-buttons-btn').exists({ count: 2 });
+ assert.dom('.oss-toggle-buttons-container .oss-toggle-buttons-btn:nth-child(1)').hasText('Oldest — Newest');
+ assert.dom('.oss-toggle-buttons-container .oss-toggle-buttons-btn:nth-child(2)').hasText('Newest — Oldest');
});
test('it calls the Handler#applyOrder method correctly via the radio buttons', async function (assert: Assert) {
@@ -70,7 +70,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/common/orde
assert.equal(this.column.order, undefined);
- await click('.upf-radio-btn:first-child');
+ await click('.oss-toggle-buttons-container .oss-toggle-buttons-btn:nth-child(1)');
//@ts-ignore
assert.ok(handlerSpy.applyOrder.calledWith(this.column, 'asc'));
assert.deepEqual(this.column.order, {
@@ -78,7 +78,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/common/orde
key: 'date'
});
- await click('.upf-radio-btn:last-child');
+ await click('.oss-toggle-buttons-container .oss-toggle-buttons-btn:nth-child(2)');
//@ts-ignore
assert.ok(handlerSpy.applyOrder.calledWith(this.column, 'desc'));
assert.deepEqual(this.column.order, {
diff --git a/tests/integration/components/hyper-table-v2/filtering-renderers/date-test.ts b/tests/integration/components/hyper-table-v2/filtering-renderers/date-test.ts
index 0c7c52c3..b2c29265 100644
--- a/tests/integration/components/hyper-table-v2/filtering-renderers/date-test.ts
+++ b/tests/integration/components/hyper-table-v2/filtering-renderers/date-test.ts
@@ -34,25 +34,18 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
this.column = this.handler.columns[1];
});
- test('it has the right data-control-name', async function (assert: Assert) {
- await render(hbs``);
-
- assert.dom('div[data-control-name="hypertable__column_filtering_for_date"]').exists();
- });
-
module('ordering', function () {
test('it does not render the section if the column is not orderable', async function (assert: Assert) {
this.column.definition.orderable = false;
await render(hbs``);
- assert.dom('div[data-control-name="hypertable__column_filtering_for_date_order_by_radiogroup"]').doesNotExist();
+ assert.dom('[data-control-name="hypertable__column_filtering_for_date_order_by_radiogroup"]').doesNotExist();
});
test('it renders if the column is orderable', async function (assert: Assert) {
await render(hbs``);
-
- assert.dom('div[data-control-name="hypertable__column_filtering_for_date_order_by_radiogroup"]').exists();
+ assert.dom('[data-control-name="hypertable__column_filtering_for_date_order_by_radiogroup"]').exists();
});
test('it calls the Handler#applyOrder method correctly via the radio buttons', async function (assert: Assert) {
@@ -63,7 +56,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
assert.equal(this.column.order, undefined);
await click(
- 'div[data-control-name="hypertable__column_filtering_for_date_ordering"] .upf-radio-btn:first-child '
+ '[data-control-name="hypertable__column_filtering_for_date_ordering"] .oss-toggle-buttons-btn:nth-child(1)'
);
//@ts-ignore
@@ -73,7 +66,9 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
key: 'date'
});
- await click('div[data-control-name="hypertable__column_filtering_for_date_ordering"] .upf-radio-btn:last-child ');
+ await click(
+ 'div[data-control-name="hypertable__column_filtering_for_date_ordering"] .oss-toggle-buttons-btn:nth-child(2)'
+ );
//@ts-ignore
assert.ok(handlerSpy.applyOrder.calledWith(this.column, 'desc'));
@@ -105,7 +100,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
await render(hbs``);
await click(
- 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .upf-radio-btn:first-child'
+ 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .oss-toggle-buttons-btn:nth-child(1)'
);
let filterOptions = findAll('.filters__option');
assert.equal(filterOptions.length, 6);
@@ -122,7 +117,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
await render(hbs``);
await click(
- 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .upf-radio-btn:first-child'
+ 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .oss-toggle-buttons-btn:nth-child(1)'
);
await click('.filters__option');
assert.ok(
@@ -139,7 +134,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
await render(hbs``);
await click(
- 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .upf-radio-btn:last-child'
+ 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .oss-toggle-buttons-btn:nth-child(2)'
);
assert.dom('div[data-control-name="hypertable__column_filtering_for_date_date_range_inputs"]').exists();
});
@@ -148,7 +143,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/date', func
await render(hbs``);
await click(
- 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .upf-radio-btn:last-child'
+ 'div[data-control-name="hypertable__column_filtering_for_date_filter_by_radiogroup"] .oss-toggle-buttons-btn:nth-child(2)'
);
await click('div[data-control-name="hypertable__column_filtering_for_date_date_range_inputs"] .upf-input');
diff --git a/tests/integration/components/hyper-table-v2/filtering-renderers/numeric-test.ts b/tests/integration/components/hyper-table-v2/filtering-renderers/numeric-test.ts
index db98a507..10d77125 100644
--- a/tests/integration/components/hyper-table-v2/filtering-renderers/numeric-test.ts
+++ b/tests/integration/components/hyper-table-v2/filtering-renderers/numeric-test.ts
@@ -66,7 +66,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/numeric', f
assert.equal(this.column.order, undefined);
await click(
- 'div[data-control-name="hypertable__column_filtering_for_total_ordering"] .upf-radio-btn:first-child '
+ 'div[data-control-name="hypertable__column_filtering_for_total_ordering"] .oss-toggle-buttons-btn:nth-child(1)'
);
//@ts-ignore
@@ -77,7 +77,7 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/numeric', f
});
await click(
- 'div[data-control-name="hypertable__column_filtering_for_total_ordering"] .upf-radio-btn:last-child '
+ 'div[data-control-name="hypertable__column_filtering_for_total_ordering"] .oss-toggle-buttons-btn:nth-child(2)'
);
//@ts-ignore
diff --git a/tests/integration/components/hyper-table-v2/filtering-renderers/text-test.ts b/tests/integration/components/hyper-table-v2/filtering-renderers/text-test.ts
index 76702b44..9003c631 100644
--- a/tests/integration/components/hyper-table-v2/filtering-renderers/text-test.ts
+++ b/tests/integration/components/hyper-table-v2/filtering-renderers/text-test.ts
@@ -59,7 +59,9 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/text', func
await render(hbs``);
assert.equal(this.column.order, undefined);
- await click('div[data-control-name="hypertable__column_filtering_for_foo_ordering"] .upf-radio-btn:first-child ');
+ await click(
+ 'div[data-control-name="hypertable__column_filtering_for_foo_ordering"] .oss-toggle-buttons-btn:nth-child(1)'
+ );
//@ts-ignore
assert.ok(handlerSpy.applyOrder.calledWith(this.column, 'asc'));
@@ -68,7 +70,9 @@ module('Integration | Component | hyper-table-v2/filtering-renderers/text', func
key: 'foo'
});
- await click('div[data-control-name="hypertable__column_filtering_for_foo_ordering"] .upf-radio-btn:last-child ');
+ await click(
+ 'div[data-control-name="hypertable__column_filtering_for_foo_ordering"] .oss-toggle-buttons-btn:nth-child(2)'
+ );
//@ts-ignore
assert.ok(handlerSpy.applyOrder.calledWith(this.column, 'desc'));