diff --git a/addon-test-support/index.ts b/addon-test-support/index.ts index 049a04b6..b9d73511 100644 --- a/addon-test-support/index.ts +++ b/addon-test-support/index.ts @@ -1,4 +1,5 @@ import TableManager from './table-manager'; import RowsFetcher, { AllRowsFetcher } from './rows-fetcher'; +import { setupTable } from './setup-table'; -export { TableManager, RowsFetcher, AllRowsFetcher }; +export { TableManager, RowsFetcher, AllRowsFetcher, setupTable }; diff --git a/addon-test-support/setup-table.ts b/addon-test-support/setup-table.ts new file mode 100644 index 00000000..3642d8e3 --- /dev/null +++ b/addon-test-support/setup-table.ts @@ -0,0 +1,23 @@ +import { type TestContext } from '@ember/test-helpers'; + +import TableHandler from '@upfluence/hypertable/core/handler'; +import { TableManager, RowsFetcher } from '@upfluence/hypertable/test-support'; +import sinon from 'sinon'; + +export function setupTable(hooks: NestedHooks): void { + hooks.beforeEach(function (this: TestContext) { + this.tableManager = new TableManager(); + this.tableRowsFetcher = new RowsFetcher(); + this.tableHandler = new TableHandler(this, this.tableManager, this.tableRowsFetcher); + this.tableRows = []; + + sinon.stub(this.tableRowsFetcher, 'fetch').callsFake(() => { + return Promise.resolve({ + rows: this.tableRows, + meta: { + total: this.tableRows.length + } + }); + }); + }); +} diff --git a/addon/components/hyper-table-v2/column.hbs b/addon/components/hyper-table-v2/column.hbs index cfea1017..099a6812 100644 --- a/addon/components/hyper-table-v2/column.hbs +++ b/addon/components/hyper-table-v2/column.hbs @@ -1,6 +1,10 @@
-
+
{{#if this.loadingHeaderComponent}} @@ -10,7 +14,7 @@ @column={{@column}} @extra={{this.headerComponent.args}} /> - {{#if this.isOrderingIndicatorVisible}} + {{#if (and (not @delegatedFiltering) this.isOrderingIndicatorVisible)}} - {{else if (eq @column.order.direction "desc")}} - - {{/if}} + {{#unless @delegatedFiltering}} + {{#if (eq @column.order.direction "asc")}} + + {{else if (eq @column.order.direction "desc")}} + + {{/if}} + {{/unless}}
-
- {{#if (or @column.definition.filterable @column.definition.orderable)}} - - {{/if}} - - {{#if (and this.filteringComponent (eq @handler.tetherOn @column.definition.key))}} -
- + {{#if (or @column.definition.filterable @column.definition.orderable)}} + -
- {{/if}} -
+ {{/if}} + + {{#if (and this.filteringComponent (eq @handler.tetherOn @column.definition.key))}} +
+ +
+ {{/if}} +
+ {{/unless}}
{{yield}} diff --git a/addon/components/hyper-table-v2/column.ts b/addon/components/hyper-table-v2/column.ts index 29fcc940..6e8350ab 100644 --- a/addon/components/hyper-table-v2/column.ts +++ b/addon/components/hyper-table-v2/column.ts @@ -9,6 +9,7 @@ import { Column, FieldSize, ResolvedRenderingComponent } from '@upfluence/hypert interface HyperTableV2ColumnArgs { handler: TableHandler; column: Column; + delegatedFiltering?: boolean; } export default class HyperTableV2Column extends Component { diff --git a/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.hbs b/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.hbs index c1669ab7..14965a08 100644 --- a/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.hbs +++ b/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.hbs @@ -1,7 +1,9 @@
{{#if this.searchEnabled}}
- + {{#if this.displaySearchLabel}} + + {{/if}} -
+
{{facet.count}}
diff --git a/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.ts b/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.ts index 8d489a77..55845cbc 100644 --- a/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.ts +++ b/addon/components/hyper-table-v2/filtering-renderers/common/facets-loader.ts @@ -16,6 +16,7 @@ interface FacetsLoaderArgs { facettingKey: string; searchEnabled: boolean; searchPlaceholder?: string; + displaySearchLabel?: boolean; sortCompareFn?(a: Facet, b: Facet): number; } @@ -50,6 +51,10 @@ export default class HyperTableV2FacetsLoader extends Component { - this.facets = facets.sort(this.facetsSorter); + this.facets = (facets ?? []).sort(this.facetsSorter); this.filteringKey = filtering_key; const filterForKey = this.args.column.filters.find((v) => v.key === this.filteringKey); diff --git a/addon/components/hyper-table-v2/index.hbs b/addon/components/hyper-table-v2/index.hbs index a1db5506..51e7ea1b 100644 --- a/addon/components/hyper-table-v2/index.hbs +++ b/addon/components/hyper-table-v2/index.hbs @@ -1,51 +1,57 @@
-
-
-
- {{#if this.features.selection}} -
- {{format-number this.selectionCount}} -
- {{/if}} + {{#if (or (has-block "search") (has-block "contextual-actions") (has-block "table-actions") this.displayHeader)}} +
+
+
+ {{#if this.features.selection}} +
+ {{format-number this.selectionCount}} +
+ {{/if}} - {{#if this.initialFetchColumnsDone}} - - {{/if}} - {{#if (has-block "contextual-actions")}} - {{yield to="contextual-actions"}} - {{/if}} -
-
- + {{#if this.initialFetchColumnsDone}} + + {{/if}} + {{#if (has-block "contextual-actions")}} + {{yield to="contextual-actions"}} + {{/if}} +
+
+ {{#if this.features.global_filters_reset}} + + {{/if}} - {{#if (has-block "table-actions")}} - {{yield to="table-actions"}} - {{/if}} + {{#if (has-block "table-actions")}} + {{yield to="table-actions"}} + {{/if}} - + {{#if this.features.manageable_fields}} + + {{/if}} +
+
- -
+ {{/if}}
{{/if}} - + {{#each @handler.rows as |row|}} { @@ -55,6 +63,10 @@ export default class HyperTableV2 extends Component { }; } + get displayHeader(): boolean { + return Object.keys(this.features).some((key) => this.features[key as keyof FeatureSet]); + } + get selectionCount(): number { if ( !this.args.handler.rowsMeta || diff --git a/addon/core/handler.ts b/addon/core/handler.ts index 454ca356..3209dbf3 100644 --- a/addon/core/handler.ts +++ b/addon/core/handler.ts @@ -45,7 +45,12 @@ export default class TableHandler { currentPage: number = 1; - constructor(emberContext: unknown, manager: TableManager, rowsFetcher: RowsFetcher, renderingResolver = undefined) { + constructor( + emberContext: unknown, + manager: TableManager, + rowsFetcher: RowsFetcher, + renderingResolver?: RendererResolver + ) { this._context = emberContext; this.tableManager = manager; this.rowsFetcher = rowsFetcher; @@ -68,6 +73,7 @@ export default class TableHandler { .then(({ columns }) => { this.columns = columns; this._lastOrderedColumn = columns.find((column) => column.order); + this.triggerEvent('columns-loaded'); }) .catch(() => { this.communicationError = true; diff --git a/app/styles/columns.less b/app/styles/columns.less index 3be32de1..1c37003f 100644 --- a/app/styles/columns.less +++ b/app/styles/columns.less @@ -89,6 +89,11 @@ text-overflow: ellipsis; white-space: nowrap; + &.cell-header--delegated-filtering { + overflow: visible; + width: 100%; + } + .header-title-container { display: flex; align-items: center; diff --git a/tests/integration/components/hyper-table-v2-test.ts b/tests/integration/components/hyper-table-v2-test.ts index 7794c53c..f3797838 100644 --- a/tests/integration/components/hyper-table-v2-test.ts +++ b/tests/integration/components/hyper-table-v2-test.ts @@ -71,13 +71,12 @@ module('Integration | Component | hyper-table-v2', function (hooks) { }); test('it triggers the row-click event correctly', async function (this: TestContext, assert: Assert) { - const handlerSpy = sinon.spy(this.handler); + const triggerEventSpy = sinon.spy(this.handler, 'triggerEvent'); await render(hbs``); await click('.hypertable__sticky-columns > .hypertable__column .hypertable__cell'); - // @ts-ignore - assert.ok(handlerSpy.triggerEvent.calledOnceWithExactly('row-click', this.handler.rows[0])); + assert.ok(triggerEventSpy.calledWithExactly('row-click', this.handler.rows[0])); }); test('when destroyed, the table properly calls the handler teardown method', async function (this: TestContext, assert: Assert) { @@ -122,6 +121,12 @@ module('Integration | Component | hyper-table-v2', function (hooks) { }); }); + test('the actions header is completely missing if all of its features are disabled and no named block is passed', async function (this: TestContext, assert: Assert) { + this.features = { selection: false, searchable: false, manageable_fields: false, global_filters_reset: false }; + await render(hbs``); + assert.dom('.hypertable__upper-header').doesNotExist(); + }); + module('error state', function () { test('It displays an error state when the fetchRows call fails', async function (this: TestContext, assert: Assert) { sinon.stub(this.rowsFetcher, 'fetch').callsFake(() => { @@ -509,6 +514,32 @@ module('Integration | Component | hyper-table-v2', function (hooks) { }); }); + module('FeatureSet: manageable_fields', () => { + test('the Manage field button is displayed by default', async function (assert) { + await render(hbs``); + assert.dom('.hypertable__manage-fields').exists(); + }); + + test('the Manage field button is not displayed if the feature is disabled', async function (this: TestContext, assert) { + this.features = { manageable_fields: false }; + await render(hbs``); + assert.dom('.hypertable__manage-fields').doesNotExist(); + }); + }); + + module('FeatureSet: global_filters_reset', () => { + test('the global Reset all button is displayed by default', async function (assert) { + await render(hbs``); + assert.dom('[data-control-name="hypertable_reset_filters_button"]').exists(); + }); + + test('the global Reset all button is not displayed if the feature is disabled', async function (this: TestContext, assert) { + this.features = { global_filters_reset: false }; + await render(hbs``); + assert.dom('[data-control-name="hypertable_reset_filters_button"]').doesNotExist(); + }); + }); + module('Contextual Actions named-block is displayed if defined', () => { test('if a <:contextual-actions> named-block is passed to the component, then it should be visible in the table', async function (assert: Assert) { await render(hbs` diff --git a/tests/integration/components/hyper-table-v2/column-test.ts b/tests/integration/components/hyper-table-v2/column-test.ts index 3d54ae33..73b2dcdf 100644 --- a/tests/integration/components/hyper-table-v2/column-test.ts +++ b/tests/integration/components/hyper-table-v2/column-test.ts @@ -178,4 +178,12 @@ module('Integration | Component | hyper-table-v2/column', function (hooks) { assert.dom('.filter-command').hasClass('filter-command--opened'); }); }); + + test('the icon commands are not displayed if the @delegatedFiltering arg is truthy', async function (assert) { + await render(hbs` + + `); + + assert.dom('.hypertable__column .icon-commands').doesNotExist(); + }); });